diff --git a/.github/workflows/deploy-account-wide-infra.yml b/.github/workflows/deploy-account-wide-infra.yml new file mode 100644 index 000000000..0e2231faa --- /dev/null +++ b/.github/workflows/deploy-account-wide-infra.yml @@ -0,0 +1,149 @@ +name: Deploy Account-wide infrastructure +run-name: Account-wide infra deployment to ${{ inputs.environment }} of ${{ inputs.branch_name }} by ${{ github.actor }} + +on: + workflow_dispatch: + inputs: + environment: + description: "Account to deploy to" + required: true + default: "account-dev" + type: environment + branch_name: + description: Branch to deploy + required: true + +permissions: + id-token: write + contents: read + actions: write + +jobs: + check-selected-environment: + name: Check Workflow Env + runs-on: codebuild-nhsd-nrlf-ci-build-project-${{ github.run_id }}-${{ github.run_attempt }} + steps: + - name: Validate environment + env: + IS_VALID_ENV: ${{ startsWith(inputs.environment, 'account-') }} + run: | + echo "valid workflow environment selected:" $IS_VALID_ENV + if [[ $IS_VALID_ENV == true ]]; then + exit 0 + fi + echo "This workflow can only be run with 'account-*' environments as it deploys account-specific infrastructure" + exit 1 + + terraform-plan: + name: Terraform Plan - ${{ inputs.environment }} + environment: ${{ inputs.environment }} + needs: [check-selected-environment] + runs-on: codebuild-nhsd-nrlf-ci-build-project-${{ github.run_id }}-${{ github.run_attempt }} + + steps: + - name: Git clone - ${{ inputs.branch_name }} + uses: actions/checkout@v4 + with: + ref: ${{ inputs.branch_name }} + + - name: Setup environment + run: | + echo "${HOME}/.asdf/bin" >> $GITHUB_PATH + poetry install --no-root + + - name: Configure Management Credentials + uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a #v4.3.1 + with: + aws-region: eu-west-2 + role-to-assume: ${{ secrets.MGMT_ROLE_ARN }} + role-session-name: github-actions-ci-${{ inputs.environment }}-${{ github.run_id }} + + - name: Retrieve Server Certificates + env: + ACCOUNT_NAME: ${{ vars.ACCOUNT_NAME }} + run: | + make truststore-pull-all-for-account ACCOUNT=${ACCOUNT_NAME} + + - name: Terraform Init + env: + ACCOUNT_NAME: ${{ vars.ACCOUNT_NAME }} + run: | + terraform -chdir=terraform/account-wide-infrastructure/${ACCOUNT_NAME} init + terraform -chdir=terraform/account-wide-infrastructure/${ACCOUNT_NAME} workspace new ${ACCOUNT_NAME} || \ + terraform -chdir=terraform/account-wide-infrastructure/${ACCOUNT_NAME} workspace select ${ACCOUNT_NAME} + + - name: Terraform Plan + env: + ACCOUNT_NAME: ${{ vars.ACCOUNT_NAME }} + ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }} + run: | + terraform -chdir=terraform/account-wide-infrastructure/${ACCOUNT_NAME} plan \ + -var assume_account=${ACCOUNT_ID} \ + -var assume_role=terraform \ + -out tfplan + + - name: Save Terraform Plan + env: + ACCOUNT_NAME: ${{ vars.ACCOUNT_NAME }} + run: | + terraform -chdir=terraform/account-wide-infrastructure/${ACCOUNT_NAME} show -no-color tfplan > terraform/account-wide-infrastructure/$ACCOUNT_NAME/tfplan.txt + + aws s3 cp terraform/account-wide-infrastructure/$ACCOUNT_NAME/tfplan s3://nhsd-nrlf--mgmt--github-ci-logging/acc-$ACCOUNT_NAME/${{ github.run_id }}/tfplan + aws s3 cp terraform/account-wide-infrastructure/$ACCOUNT_NAME/tfplan.txt s3://nhsd-nrlf--mgmt--github-ci-logging/acc-$ACCOUNT_NAME/${{ github.run_id }}/tfplan.txt + + terraform-apply: + name: Terraform Apply - ${{ inputs.environment }} + needs: [terraform-plan] + runs-on: codebuild-nhsd-nrlf-ci-build-project-${{ github.run_id }}-${{ github.run_attempt }} + environment: ${{ inputs.environment }} + + steps: + - name: Git clone - ${{ inputs.branch_name }} + uses: actions/checkout@v4 + with: + ref: ${{ inputs.branch_name }} + + - name: Setup environment + run: | + echo "${HOME}/.asdf/bin" >> $GITHUB_PATH + poetry install --no-root + + - name: Configure Management Credentials + uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a #v4.3.1 + with: + aws-region: eu-west-2 + role-to-assume: ${{ secrets.MGMT_ROLE_ARN }} + role-session-name: github-actions-ci-${{ inputs.environment }}-${{ github.run_id}} + + - name: Download Terraform Plan artifact + env: + ACCOUNT_NAME: ${{ vars.ACCOUNT_NAME }} + run: aws s3 cp s3://nhsd-nrlf--mgmt--github-ci-logging/acc-$ACCOUNT_NAME/${{ github.run_id }}/tfplan terraform/account-wide-infrastructure/${ACCOUNT_NAME}/tfplan + + - name: Retrieve Server Certificates + env: + ACCOUNT_NAME: ${{ vars.ACCOUNT_NAME }} + run: | + make truststore-pull-all-for-account ACCOUNT=${ACCOUNT_NAME} + + - name: Terraform Init + env: + ACCOUNT_NAME: ${{ vars.ACCOUNT_NAME }} + run: | + terraform -chdir=terraform/account-wide-infrastructure/${ACCOUNT_NAME} init + terraform -chdir=terraform/account-wide-infrastructure/${ACCOUNT_NAME} workspace new ${ACCOUNT_NAME} || \ + terraform -chdir=terraform/account-wide-infrastructure/${ACCOUNT_NAME} workspace select ${ACCOUNT_NAME} + + - name: Terraform Apply + env: + ACCOUNT_NAME: ${{ vars.ACCOUNT_NAME }} + ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }} + run: | + terraform -chdir=terraform/account-wide-infrastructure/${ACCOUNT_NAME} apply tfplan + + - name: Update environment config version + env: + ACCOUNT_NAME: ${{ vars.ACCOUNT_NAME }} + run: | + deployed_version=$(terraform -chdir=terraform/account-wide-infrastructure/${ACCOUNT_NAME} output --raw version) + echo $deployed_version diff --git a/Makefile b/Makefile index 00104a48c..6c754d888 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,7 @@ SMOKE_TEST_ARGS ?= FEATURE_TEST_ARGS ?= ./tests/features --format progress2 TF_WORKSPACE_NAME ?= $(shell terraform -chdir=terraform/infrastructure workspace show) ENV ?= dev +ACCOUNT ?= dev APP_ALIAS ?= default HOST ?= $(TF_WORKSPACE_NAME).api.record-locator.$(ENV).national.nhs.uk ENV_TYPE ?= $(ENV) @@ -201,6 +202,9 @@ truststore-build-ca: check-warn ## Build a CA (Certificate Authority) truststore-build-cert: check-warn ## Build a certificate @./scripts/truststore.sh build-cert "$(CA_NAME)" "$(CERT_NAME)" "$(CERT_SUBJECT)" +truststore-pull-all-for-account: check-warn ## Pull all certificates for each environment in a given account + @./scripts/truststore.sh pull-all-for-account "$(ACCOUNT)" + truststore-pull-all: check-warn ## Pull all certificates @./scripts/truststore.sh pull-all "$(ENV)" diff --git a/README.md b/README.md index 1ebb41ab9..9dd572102 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ As a short guideline about profiles to assume for a typical workflow: ### Set up NRLF certificates In order to execute make commands that need AWS access, you will need to pull the NRLF certificates. -In order to do this, make sure you have AWS CLI installed and configured, then run: +In order to do this, make sure you have AWS CLI installed and configured, assume the mgmt account, then run: ``` make ENV=env truststore-pull-all diff --git a/scripts/get-envs-for-account.sh b/scripts/get-envs-for-account.sh new file mode 100755 index 000000000..09bc70972 --- /dev/null +++ b/scripts/get-envs-for-account.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# Get the names of all environments in a provided NRL AWS account +set -o errexit -o nounset -o pipefail + +if [[ $# -ne 1 ]]; then + echo "Usage: get-envs-for-account.sh " + exit 1 +fi + +account="$1" + +case "${account}" in + dev) + envs_array=("dev" "dev-sandbox") + echo ${envs_array[@]} + ;; + test) + envs_array=("qa" "perftest" "ref" "int" "int-sandbox") # "qa-sandbox" currently broken + echo ${envs_array[@]} + ;; + prod) + envs_array=("prod") + echo ${envs_array[@]} + ;; + *) + echo "Unknown account ${account}" + exit 1 +esac diff --git a/scripts/truststore.sh b/scripts/truststore.sh index 5f209c9e7..a7f45c913 100755 --- a/scripts/truststore.sh +++ b/scripts/truststore.sh @@ -303,6 +303,7 @@ function _truststore_pull_server() { function _truststore_pull_all() { env=$1 + _truststore_pull_ca $env _truststore_pull_client $env _truststore_pull_server $env @@ -311,6 +312,25 @@ function _truststore_pull_all() { return 0 } +function _truststore_pull_all_for_account() { + account=$1 + + # sets envs_array + source ./scripts/get-envs-for-account.sh $account + + echo "Pulling certs for environments ${envs_array[@]} in ${account} account" + + for env in ${envs_array[@]}; do + echo "⏳ Pulling ${env} truststore certs" + _truststore_pull_ca $env + _truststore_pull_client $env + _truststore_pull_server $env + done + + echo -e "✅ Successfully pulled all ${account} truststore files from s3://${BUCKET}" + return 0 +} + function _truststore_push_all() { env=$1 @@ -364,6 +384,7 @@ function _truststore() { "build-ca") _truststore_build_ca $args ;; "build-cert") _truststore_build_cert $args ;; "pull-all") _truststore_pull_all $args ;; + "pull-all-for-account") _truststore_pull_all_for_account $args ;; "pull-server") _truststore_pull_server $args ;; "pull-client") _truststore_pull_client $args ;; "pull-ca") _truststore_pull_ca $args ;; diff --git a/terraform/account-wide-infrastructure/README.md b/terraform/account-wide-infrastructure/README.md index 69fe335f5..7619fe732 100644 --- a/terraform/account-wide-infrastructure/README.md +++ b/terraform/account-wide-infrastructure/README.md @@ -18,7 +18,7 @@ Each subdirectory corresponds to each AWS account (`mgmt`, `prod`, `test` and `d Before deploying the NRLF account-wide infrastructure, you will need: - AWS accounts that have already been bootstrapped, as described in [bootstrap/README.md](../bootstrap/README.md). This is a one-time account setup step. -- The required packages to build NRLF, see [the Setup section in README.md](../../README.md#setup). +- The required packages to build NRLF, see [the Setup section in README.md](../../README.md#before-you-begin). ## Deploy mgmt resources @@ -45,7 +45,7 @@ terraform apply ### If you get "Error: creating CodeBuild Webhook" -If you see this erro: +If you see this error: ``` │ Error: creating CodeBuild Webhook (nhsd-nrlf-ci-build-project): operation error CodeBuild: CreateWebhook, https response error StatusCode: 400, RequestID: , ResourceNotFoundException: Access token not found in CodeBuild project for server type github diff --git a/terraform/account-wide-infrastructure/dev/data.tf b/terraform/account-wide-infrastructure/dev/data.tf index 02e297f54..633f06302 100644 --- a/terraform/account-wide-infrastructure/dev/data.tf +++ b/terraform/account-wide-infrastructure/dev/data.tf @@ -17,3 +17,10 @@ data "aws_secretsmanager_secret" "emails" { data "aws_secretsmanager_secret_version" "emails" { secret_id = data.aws_secretsmanager_secret.emails.id } + +data "external" "current-info" { + program = [ + "bash", + "../../../scripts/get-current-info.sh", + ] +} diff --git a/terraform/account-wide-infrastructure/dev/outputs.tf b/terraform/account-wide-infrastructure/dev/outputs.tf index 9f99d1105..8f4da5455 100644 --- a/terraform/account-wide-infrastructure/dev/outputs.tf +++ b/terraform/account-wide-infrastructure/dev/outputs.tf @@ -22,3 +22,7 @@ output "athena_kms_key_arn" { description = "KMS key ARN for Athena encryption" value = var.enable_reporting ? module.dev-athena[0].kms_key_arn : null } + +output "version" { + value = data.external.current-info.result.version +} diff --git a/terraform/account-wide-infrastructure/prod/data.tf b/terraform/account-wide-infrastructure/prod/data.tf index c21a0cb4d..8974b7fb0 100644 --- a/terraform/account-wide-infrastructure/prod/data.tf +++ b/terraform/account-wide-infrastructure/prod/data.tf @@ -17,3 +17,10 @@ data "aws_secretsmanager_secret_version" "emails" { data "aws_secretsmanager_secret_version" "backup_destination_parameters" { secret_id = aws_secretsmanager_secret.backup_destination_parameters.name } + +data "external" "current-info" { + program = [ + "bash", + "../../../scripts/get-current-info.sh", + ] +} diff --git a/terraform/account-wide-infrastructure/prod/outputs.tf b/terraform/account-wide-infrastructure/prod/outputs.tf index 270d62ea6..cd43c90ce 100644 --- a/terraform/account-wide-infrastructure/prod/outputs.tf +++ b/terraform/account-wide-infrastructure/prod/outputs.tf @@ -22,3 +22,7 @@ output "athena_kms_key_arn" { description = "KMS key ARN for Athena encryption" value = var.enable_reporting ? module.prod-athena[0].kms_key_arn : null } + +output "version" { + value = data.external.current-info.result.version +} diff --git a/terraform/account-wide-infrastructure/test/data.tf b/terraform/account-wide-infrastructure/test/data.tf index c21a0cb4d..8974b7fb0 100644 --- a/terraform/account-wide-infrastructure/test/data.tf +++ b/terraform/account-wide-infrastructure/test/data.tf @@ -17,3 +17,10 @@ data "aws_secretsmanager_secret_version" "emails" { data "aws_secretsmanager_secret_version" "backup_destination_parameters" { secret_id = aws_secretsmanager_secret.backup_destination_parameters.name } + +data "external" "current-info" { + program = [ + "bash", + "../../../scripts/get-current-info.sh", + ] +} diff --git a/terraform/account-wide-infrastructure/test/outputs.tf b/terraform/account-wide-infrastructure/test/outputs.tf index 096cf026f..263720462 100644 --- a/terraform/account-wide-infrastructure/test/outputs.tf +++ b/terraform/account-wide-infrastructure/test/outputs.tf @@ -22,3 +22,7 @@ output "athena_kms_key_arn" { description = "KMS key ARN for Athena encryption" value = var.enable_reporting ? module.test-athena[0].kms_key_arn : null } + +output "version" { + value = data.external.current-info.result.version +} diff --git a/terraform/bootstrap/README.md b/terraform/bootstrap/README.md index 1ed4c93bd..45bd77de8 100644 --- a/terraform/bootstrap/README.md +++ b/terraform/bootstrap/README.md @@ -15,7 +15,7 @@ The setup creates AWS resources to enable terraform deployments to AWS accounts. Before you begin deploying NRLF bootstrap components, you will need: - Four AWS accounts created. These will be assigned as: mgmt, prod, test and dev -- The required packages to build NRLF, see [the Setup section in README.md](../../README.md#setup). +- The required packages to build NRLF, see [the Setup section in README.md](../../README.md#before-you-begin). ## Bootstrapping the environments diff --git a/terraform/infrastructure/README.md b/terraform/infrastructure/README.md index a78ac05b8..cf5717796 100644 --- a/terraform/infrastructure/README.md +++ b/terraform/infrastructure/README.md @@ -35,7 +35,7 @@ CI pipeline creates infrastructure in the dev AWS account. These will have works Before you begin deploying NRLF infrastructure, you will need: - An NRLF-enabled AWS account, ideally `dev`. See [bootstrap](../bootstrap/README.md) for details on setting up a new account. -- The required packages to build NRLF, see [the Setup section in README.md](../../README.md#setup). +- The required packages to build NRLF, see [the Setup section in README.md](../../README.md#before-you-begin). - To be logged into the AWS mgmt account on the CLI that you are deploying from. If infrastructure changes require account wide AWS resources. Please deploy the corresponding [NRLF account wide infrastructure](../account-wide-infrastructure/README.md) first.