diff --git a/.github/workflows/deploy-account-wide-infra.yml b/.github/workflows/deploy-account-wide-infra.yml index 564a8e1d1..82cbed87f 100644 --- a/.github/workflows/deploy-account-wide-infra.yml +++ b/.github/workflows/deploy-account-wide-infra.yml @@ -88,9 +88,9 @@ jobs: 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 - aws s3 cp terraform/account-wide-infrastructure/modules/glue/files/src.zip s3://nhsd-nrlf--mgmt--github-ci-logging/acc-$ACCOUNT_NAME/${{ github.run_id }}/glue-src.zip + aws s3 cp terraform/account-wide-infrastructure/$ACCOUNT_NAME/tfplan s3://nhsd-nrlf--mgmt--github-ci-data/acc-$ACCOUNT_NAME/${{ github.run_id }}/tfplan + aws s3 cp terraform/account-wide-infrastructure/$ACCOUNT_NAME/tfplan.txt s3://nhsd-nrlf--mgmt--github-ci-data/acc-$ACCOUNT_NAME/${{ github.run_id }}/tfplan.txt + aws s3 cp terraform/account-wide-infrastructure/modules/glue/files/src.zip s3://nhsd-nrlf--mgmt--github-ci-data/acc-$ACCOUNT_NAME/${{ github.run_id }}/glue-src.zip terraform-apply: name: Terraform Apply - ${{ inputs.environment }} @@ -120,11 +120,11 @@ jobs: 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 - aws s3 cp s3://nhsd-nrlf--mgmt--github-ci-logging/acc-$ACCOUNT_NAME/${{ github.run_id }}/tfplan.txt terraform/account-wide-infrastructure/${ACCOUNT_NAME}/tfplan.txt + aws s3 cp s3://nhsd-nrlf--mgmt--github-ci-data/acc-$ACCOUNT_NAME/${{ github.run_id }}/tfplan terraform/account-wide-infrastructure/${ACCOUNT_NAME}/tfplan + aws s3 cp s3://nhsd-nrlf--mgmt--github-ci-data/acc-$ACCOUNT_NAME/${{ github.run_id }}/tfplan.txt terraform/account-wide-infrastructure/${ACCOUNT_NAME}/tfplan.txt mkdir -p terraform/account-wide-infrastructure/modules/glue/files - aws s3 cp s3://nhsd-nrlf--mgmt--github-ci-logging/acc-$ACCOUNT_NAME/${{ github.run_id }}/glue-src.zip terraform/account-wide-infrastructure/modules/glue/files/src.zip + aws s3 cp s3://nhsd-nrlf--mgmt--github-ci-data/acc-$ACCOUNT_NAME/${{ github.run_id }}/glue-src.zip terraform/account-wide-infrastructure/modules/glue/files/src.zip - name: Retrieve Server Certificates env: diff --git a/.github/workflows/persistent-environment.yml b/.github/workflows/persistent-environment.yml index 3559e39dd..bca092c4b 100644 --- a/.github/workflows/persistent-environment.yml +++ b/.github/workflows/persistent-environment.yml @@ -143,8 +143,8 @@ jobs: ENVIRONMENT: ${{ inputs.environment }} run: | terraform -chdir=terraform/infrastructure show -no-color tfplan > terraform/infrastructure/tfplan.txt - aws s3 cp terraform/infrastructure/tfplan s3://nhsd-nrlf--mgmt--github-ci-logging/$ENVIRONMENT/${{ github.run_id }}/tfplan - aws s3 cp terraform/infrastructure/tfplan.txt s3://nhsd-nrlf--mgmt--github-ci-logging/$ENVIRONMENT/${{ github.run_id }}/tfplan.txt + aws s3 cp terraform/infrastructure/tfplan s3://nhsd-nrlf--mgmt--github-ci-data/$ENVIRONMENT/${{ github.run_id }}/tfplan + aws s3 cp terraform/infrastructure/tfplan.txt s3://nhsd-nrlf--mgmt--github-ci-data/$ENVIRONMENT/${{ github.run_id }}/tfplan.txt terraform-apply: name: Terraform Apply - ${{ inputs.environment }} @@ -186,7 +186,7 @@ jobs: - name: Download Terraform Plan artifact env: ENVIRONMENT: ${{ inputs.environment }} - run: aws s3 cp s3://nhsd-nrlf--mgmt--github-ci-logging/$ENVIRONMENT/${{ github.run_id }}/tfplan terraform/infrastructure/tfplan + run: aws s3 cp s3://nhsd-nrlf--mgmt--github-ci-data/$ENVIRONMENT/${{ github.run_id }}/tfplan terraform/infrastructure/tfplan - name: Retrieve Server Certificates env: diff --git a/.github/workflows/update-lambda-permissions.yml b/.github/workflows/update-lambda-permissions.yml index c7017724d..886df9da9 100644 --- a/.github/workflows/update-lambda-permissions.yml +++ b/.github/workflows/update-lambda-permissions.yml @@ -220,8 +220,8 @@ jobs: ENVIRONMENT: ${{ inputs.environment }} run: | terraform -chdir=terraform/infrastructure show -no-color tfplan > terraform/infrastructure/tfplan.txt - aws s3 cp terraform/infrastructure/tfplan s3://nhsd-nrlf--mgmt--github-ci-logging/$ENVIRONMENT/${{ github.run_id }}/tfplan - aws s3 cp terraform/infrastructure/tfplan.txt s3://nhsd-nrlf--mgmt--github-ci-logging/$ENVIRONMENT/${{ github.run_id }}/tfplan.txt + aws s3 cp terraform/infrastructure/tfplan s3://nhsd-nrlf--mgmt--github-ci-data/$ENVIRONMENT/${{ github.run_id }}/tfplan + aws s3 cp terraform/infrastructure/tfplan.txt s3://nhsd-nrlf--mgmt--github-ci-data/$ENVIRONMENT/${{ github.run_id }}/tfplan.txt terraform-apply: name: Apply permissions @@ -265,7 +265,7 @@ jobs: - name: Download Terraform Plan artifact env: ENVIRONMENT: ${{ inputs.environment }} - run: aws s3 cp s3://nhsd-nrlf--mgmt--github-ci-logging/$ENVIRONMENT/${{ github.run_id }}/tfplan terraform/infrastructure/tfplan + run: aws s3 cp s3://nhsd-nrlf--mgmt--github-ci-data/$ENVIRONMENT/${{ github.run_id }}/tfplan terraform/infrastructure/tfplan - name: Terraform Init env: diff --git a/terraform/account-wide-infrastructure/mgmt/codebuild.tf b/terraform/account-wide-infrastructure/mgmt/codebuild.tf index 52f7db234..d6c6ce925 100644 --- a/terraform/account-wide-infrastructure/mgmt/codebuild.tf +++ b/terraform/account-wide-infrastructure/mgmt/codebuild.tf @@ -63,7 +63,9 @@ data "aws_iam_policy_document" "codebuild_policy" { statement { effect = "Allow" actions = [ - "ecr:*" + "ecr:GetDownloadUrlForLayer", + "ecr:BatchGetImage", + "ecr:BatchCheckLayerAvailability" ] resources = [ "${aws_ecr_repository.repository.arn}", diff --git a/terraform/account-wide-infrastructure/mgmt/data.tf b/terraform/account-wide-infrastructure/mgmt/data.tf index ebfc46ff1..619199098 100644 --- a/terraform/account-wide-infrastructure/mgmt/data.tf +++ b/terraform/account-wide-infrastructure/mgmt/data.tf @@ -2,6 +2,13 @@ data "aws_caller_identity" "current" {} data "aws_region" "current" {} +data "external" "current-info" { + program = [ + "bash", + "../../../scripts/get-current-info.sh", + ] +} + data "aws_dynamodb_table" "terraform_state_lock" { name = "${local.project}--terraform-state-lock" } @@ -10,10 +17,6 @@ data "aws_s3_bucket" "terraform_state" { bucket = "${local.project}--terraform-state" } -data "aws_s3_bucket" "ci_logging" { - bucket = "${local.project}--mgmt--github-ci-logging" -} - data "aws_s3_bucket" "truststore" { bucket = "${local.project}--truststore" } @@ -53,3 +56,7 @@ data "aws_secretsmanager_secret_version" "test_backup_account_id" { data "aws_secretsmanager_secret_version" "test_restore_account_id" { secret_id = data.aws_secretsmanager_secret.test_restore_account_id.name } + +data "aws_secretsmanager_secret_version" "prod_account_id" { + secret_id = data.aws_secretsmanager_secret.prod_account_id.name +} diff --git a/terraform/account-wide-infrastructure/mgmt/iam.tf b/terraform/account-wide-infrastructure/mgmt/iam.tf deleted file mode 100644 index 834e922d7..000000000 --- a/terraform/account-wide-infrastructure/mgmt/iam.tf +++ /dev/null @@ -1,110 +0,0 @@ -module "developer_policy" { - source = "../modules/role-policy" - name = "${local.prefix}--developer-policy" - role_name = aws_iam_role.developer_role.name - iam_permissions = [ - { - Action = [ - "s3:PutObject", - "s3:DeleteObject", - "s3:GetObject", - "dynamodb:PutItem", - "dynamodb:GetItem", - "dynamodb:DeleteItem", - "s3:ListBucket" - ] - Effect = "Allow" - Resource = [ - data.aws_dynamodb_table.terraform_state_lock.arn, - data.aws_s3_bucket.terraform_state.arn, - "${data.aws_s3_bucket.terraform_state.arn}/*" - ] - }, - { - Action = [ - "s3:PutObject", - "s3:GetObject", - "s3:DeleteObject" - ] - Effect = "Deny" - Resource = [ - "${data.aws_s3_bucket.terraform_state.arn}/${local.project}/prod/*", - "${data.aws_s3_bucket.terraform_state.arn}/${local.project}/mgmt/*", - ] - }, - { - Action = [ - "s3:DeleteObject" - ] - Effect = "Deny" - Resource = [ - "${data.aws_s3_bucket.terraform_state.arn}/${local.project}/dev/*" - ] - }, - { - Action = "sts:AssumeRole" - Effect = "Allow" - Resource = [ - "arn:aws:iam::${data.aws_secretsmanager_secret_version.dev_account_id.secret_string}:role/terraform", - "arn:aws:iam::${data.aws_secretsmanager_secret_version.test_account_id.secret_string}:role/terraform", - "arn:aws:iam::${data.aws_secretsmanager_secret_version.test_backup_account_id.secret_string}:role/terraform", - "arn:aws:iam::${data.aws_secretsmanager_secret_version.test_restore_account_id.secret_string}:role/terraform" - ] - }, - { - Action = [ - "secretsmanager:GetResourcePolicy", - "secretsmanager:GetSecretValue", - "secretsmanager:DescribeSecret", - "secretsmanager:ListSecretVersionIds" - ] - Effect = "Allow" - Resource = [ - data.aws_secretsmanager_secret.dev_account_id.arn, - data.aws_secretsmanager_secret.test_account_id.arn - ] - }, - { - Action = [ - "s3:ListAllMyBuckets" - ] - Effect = "Allow" - Resource = [ - "arn:aws:s3:::*" - ] - }, - { - Action = [ - "s3:GetObject", - "s3:ListBucket" - ] - Effect = "Allow" - Resource = [ - data.aws_s3_bucket.ci_logging.arn, - "${data.aws_s3_bucket.ci_logging.arn}/*" - ] - }, - { - Action = [ - "s3:PutObject", - "s3:GetObject", - "s3:DeleteObject" - ] - Effect = "Deny" - Resource = [ - "${data.aws_s3_bucket.truststore.arn}/ca/prod*", - "${data.aws_s3_bucket.truststore.arn}/client/prod*", - "${data.aws_s3_bucket.truststore.arn}/server/prod*" - ] - }, - { - Action = [ - "s3:GetObject" - ] - Effect = "Allow" - Resource = [ - "${data.aws_s3_bucket.truststore.arn}/*" - ] - } - ] -} diff --git a/terraform/account-wide-infrastructure/mgmt/iam_developer.tf b/terraform/account-wide-infrastructure/mgmt/iam_developer.tf new file mode 100644 index 000000000..109140c3d --- /dev/null +++ b/terraform/account-wide-infrastructure/mgmt/iam_developer.tf @@ -0,0 +1,117 @@ +resource "aws_iam_policy" "developer_policy" { + name = "${local.prefix}--developer-policy" + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = [ + "s3:PutObject", + "s3:DeleteObject", + "s3:GetObject", + "dynamodb:PutItem", + "dynamodb:GetItem", + "dynamodb:DeleteItem", + "s3:ListBucket" + ] + Effect = "Allow" + Resource = [ + data.aws_dynamodb_table.terraform_state_lock.arn, + data.aws_s3_bucket.terraform_state.arn, + "${data.aws_s3_bucket.terraform_state.arn}/*" + ] + }, + { + Action = [ + "s3:PutObject", + "s3:GetObject", + "s3:DeleteObject" + ] + Effect = "Deny" + Resource = [ + "${data.aws_s3_bucket.terraform_state.arn}/${local.project}/prod/*", + "${data.aws_s3_bucket.terraform_state.arn}/${local.project}/mgmt/*", + ] + }, + { + Action = [ + "s3:DeleteObject" + ] + Effect = "Deny" + Resource = [ + "${data.aws_s3_bucket.terraform_state.arn}/${local.project}/dev/*" + ] + }, + { + Action = "sts:AssumeRole" + Effect = "Allow" + Resource = [ + "arn:aws:iam::${data.aws_secretsmanager_secret_version.dev_account_id.secret_string}:role/terraform", + "arn:aws:iam::${data.aws_secretsmanager_secret_version.test_account_id.secret_string}:role/terraform", + "arn:aws:iam::${data.aws_secretsmanager_secret_version.test_backup_account_id.secret_string}:role/terraform", + "arn:aws:iam::${data.aws_secretsmanager_secret_version.test_restore_account_id.secret_string}:role/terraform" + ] + }, + { + Action = [ + "secretsmanager:GetResourcePolicy", + "secretsmanager:GetSecretValue", + "secretsmanager:DescribeSecret", + "secretsmanager:ListSecretVersionIds" + ] + Effect = "Allow" + Resource = [ + data.aws_secretsmanager_secret.dev_account_id.arn, + data.aws_secretsmanager_secret.test_account_id.arn + ] + }, + { + Action = [ + "s3:ListAllMyBuckets" + ] + Effect = "Allow" + Resource = [ + "arn:aws:s3:::*" + ] + }, + { + Action = [ + "s3:GetObject", + "s3:ListBucket" + ] + Effect = "Allow" + Resource = [ + aws_s3_bucket.ci_data.arn, + "${aws_s3_bucket.ci_data.arn}/*" + ] + }, + { + Action = [ + "s3:PutObject", + "s3:GetObject", + "s3:DeleteObject" + ] + Effect = "Deny" + Resource = [ + "${data.aws_s3_bucket.truststore.arn}/ca/prod*", + "${data.aws_s3_bucket.truststore.arn}/client/prod*", + "${data.aws_s3_bucket.truststore.arn}/server/prod*" + ] + }, + { + Action = [ + "s3:GetObject" + ] + Effect = "Allow" + Resource = [ + "${data.aws_s3_bucket.truststore.arn}/*" + ] + } + ] + }) +} + +resource "aws_iam_role_policy_attachment" "developer_policy_attachment" { + role = var.developer_role_name + policy_arn = aws_iam_policy.developer_policy.arn +} diff --git a/terraform/account-wide-infrastructure/mgmt/iam_github-ci.tf b/terraform/account-wide-infrastructure/mgmt/iam_github-ci.tf new file mode 100644 index 000000000..c12ec150d --- /dev/null +++ b/terraform/account-wide-infrastructure/mgmt/iam_github-ci.tf @@ -0,0 +1,104 @@ +resource "aws_iam_openid_connect_provider" "github_action" { + url = "https://token.actions.githubusercontent.com" + + client_id_list = [ + "sts.amazonaws.com", + ] + + thumbprint_list = [ + # pragma: allowlist nextline secret + "6938fd4d98bab03faadb97b34396831e3780aea1" + ] +} + +resource "aws_iam_role" "github_ci" { + name = "${local.prefix}--github-ci" + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = "sts:AssumeRoleWithWebIdentity" + Effect = "Allow" + Principal = { + Federated = aws_iam_openid_connect_provider.github_action.arn + } + Condition = { + StringLike = { + "token.actions.githubusercontent.com:aud" = "sts.amazonaws.com" + "token.actions.githubusercontent.com:sub" = "repo:NHSDigital/NRLF:*" + } + } + } + ] + }) +} + +resource "aws_iam_policy" "github_ci_policy" { + name = "${local.prefix}--github-ci-policy" + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = [ + "s3:PutObject", + "s3:DeleteObject", + "s3:GetObject", + "dynamodb:PutItem", + "dynamodb:GetItem", + "dynamodb:DeleteItem", + "s3:ListBucket" + ] + Effect = "Allow" + Resource = [ + data.aws_dynamodb_table.terraform_state_lock.arn, + data.aws_s3_bucket.terraform_state.arn, + "${data.aws_s3_bucket.terraform_state.arn}/*" + ] + }, + { + Action = [ + "sts:AssumeRole", + "sts:TagSession" + ], + Effect = "Allow" + Resource = [ + "arn:aws:iam::${data.aws_secretsmanager_secret_version.dev_account_id.secret_string}:role/terraform", + "arn:aws:iam::${data.aws_secretsmanager_secret_version.test_account_id.secret_string}:role/terraform", + "arn:aws:iam::${data.aws_secretsmanager_secret_version.prod_account_id.secret_string}:role/terraform" + ] + }, + { + Action = [ + "secretsmanager:GetResourcePolicy", + "secretsmanager:GetSecretValue", + "secretsmanager:DescribeSecret", + "secretsmanager:ListSecretVersionIds" + ] + Effect = "Allow" + Resource = [ + data.aws_secretsmanager_secret.dev_account_id.arn, + data.aws_secretsmanager_secret.test_account_id.arn, + data.aws_secretsmanager_secret.prod_account_id.arn + ] + }, + { + Action = [ + "s3:PutObject", + "s3:DeleteObject", + "s3:GetObject", + "s3:ListBucket" + ] + Effect = "Allow" + Resource = [ + aws_s3_bucket.ci_data.arn, + "${aws_s3_bucket.ci_data.arn}/*" + ] + } + ] + }) +} + +resource "aws_iam_role_policy_attachment" "github_ci_policy_attachment" { + role = aws_iam_role.github_ci.name + policy_arn = aws_iam_policy.github_ci_policy.arn +} diff --git a/terraform/account-wide-infrastructure/mgmt/outputs.tf b/terraform/account-wide-infrastructure/mgmt/outputs.tf new file mode 100644 index 000000000..86cbc87a1 --- /dev/null +++ b/terraform/account-wide-infrastructure/mgmt/outputs.tf @@ -0,0 +1,7 @@ +output "version" { + value = data.external.current-info.result.version +} + +output "caller_identity" { + value = data.aws_caller_identity.current +} diff --git a/terraform/account-wide-infrastructure/mgmt/s3.tf b/terraform/account-wide-infrastructure/mgmt/s3.tf new file mode 100644 index 000000000..b3fd09fc4 --- /dev/null +++ b/terraform/account-wide-infrastructure/mgmt/s3.tf @@ -0,0 +1,62 @@ +resource "aws_s3_bucket" "ci_data" { + bucket = "${local.prefix}--ci-data" +} + +resource "aws_s3_bucket_acl" "ci_data" { + bucket = aws_s3_bucket.ci_data.id + acl = "private" + + depends_on = [ + aws_s3_bucket.ci_data + ] +} + +resource "aws_s3_bucket_public_access_block" "ci_data" { + bucket = aws_s3_bucket.ci_data.id + + block_public_acls = true + block_public_policy = true + restrict_public_buckets = true + ignore_public_acls = true + + depends_on = [ + aws_s3_bucket.ci_data + ] +} + +resource "aws_s3_bucket_versioning" "ci_data" { + bucket = aws_s3_bucket.ci_data.id + versioning_configuration { + status = "Enabled" + } + + depends_on = [ + aws_s3_bucket.ci_data + ] +} + +resource "aws_s3_bucket_policy" "ci_data" { + bucket = aws_s3_bucket.ci_data.id + + policy = jsonencode({ + Version = "2012-10-17" + Id = "${local.prefix}--ci-data-bucket-policy" + Statement = [ + { + Sid = "HTTPSOnly" + Effect = "Deny" + Principal = "*" + Action = "s3:*" + Resource = [ + aws_s3_bucket.ci_data.arn, + "${aws_s3_bucket.ci_data.arn}/*", + ] + Condition = { + Bool = { + "aws:SecureTransport" = "false" + } + } + }, + ] + }) +} diff --git a/terraform/account-wide-infrastructure/mgmt/vars.tf b/terraform/account-wide-infrastructure/mgmt/vars.tf index 4785b5af3..a05502b52 100644 --- a/terraform/account-wide-infrastructure/mgmt/vars.tf +++ b/terraform/account-wide-infrastructure/mgmt/vars.tf @@ -1,3 +1,9 @@ +variable "developer_role_name" { + description = "Name of the IAM role for developers" + type = string + default = "AWSReservedSSO_NHSDDeveloperRole_fa10ba0474290a64" +} + variable "private_subnet_cidr_blocks" { description = "Available CIDR blocks for private subnets" type = list(string)