diff --git a/.terraform.lock.hcl b/.terraform.lock.hcl index f23a168..41d52e4 100644 --- a/.terraform.lock.hcl +++ b/.terraform.lock.hcl @@ -5,6 +5,7 @@ provider "registry.terraform.io/hashicorp/aws" { version = "5.56.0" hashes = [ "h1:09fAczBASw/S5fgA35pxTCjtUgTn1Q+u9AxVdu9PYT0=", + "h1:F9Ad0SflY+F0M+1F5FohJlQ573cVpCGn+c7hIvJRwkg=", "zh:626ada4e076bd852fb7fc3d0722f17a0eddd87356d94cfce8b3595a520e8d91d", "zh:6b31e0c5b60d830a623ae9cc7d8cf2db74f75735d83097c659607c8a6276adaf", "zh:774d02a1c5ddcc9b5efbfe86bc967f4af8a52b8cb5880b2f5d1b255e5b0868ba", diff --git a/environment_roles/main.tf b/environment_roles/main.tf index 03d3fdb..ca6c14e 100644 --- a/environment_roles/main.tf +++ b/environment_roles/main.tf @@ -7,9 +7,13 @@ locals { } module "terraform_role" { - source = "git::https://github.com/nationalarchives/da-terraform-modules//iam_role" - assume_role_policy = templatefile("./templates/iam_role/account_assume_role.json.tpl", { account_id = var.management_account_number, external_id = var.terraform_external_id }) - name = "${title(var.environment)}TerraformRole" + source = "git::https://github.com/nationalarchives/da-terraform-modules//iam_role" + assume_role_policy = templatefile("./templates/iam_role/account_assume_role.json.tpl", { + admin_role_arn = data.aws_ssm_parameter.dev_admin_role.value + account_id = var.account_number, + repo_filters = var.terraform_repository_filters + }) + name = "${title(var.environment)}TerraformRole" policy_attachments = { terraform_policy = module.terraform_policy.policy_arn } @@ -19,7 +23,7 @@ module "terraform_role" { module "terraform_policy" { source = "git::https://github.com/nationalarchives/da-terraform-modules//iam_policy" name = "${title(var.environment)}TerraformPolicy" - policy_string = templatefile("./templates/iam_policy/terraform_policy.json.tpl", { account_id = var.account_number, environment = var.environment, environment_title = title(var.environment) }) + policy_string = templatefile("./templates/iam_policy/terraform_policy.json.tpl", { account_id = var.account_number, environment = var.environment, environment_title = title(var.environment), management_account_id = var.management_account_number }) } module "custodian_repo_filters" { @@ -59,8 +63,8 @@ module "copy_tna_to_preservica_role" { assume_role_policy = templatefile("./templates/iam_role/tna_to_preservica_trust_policy.json.tpl", { terraform_role_arn = module.terraform_role.role_arn, account_id = data.aws_caller_identity.current.account_id, - admin_role_arn = var.management_developer_role_arn - terraform_github_role_arn = var.terraform_github_role_arn + admin_role_arn = data.aws_ssm_parameter.dev_admin_role.value + terraform_github_role_arn = module.terraform_role.role_arn title_environment = title(var.environment) environment = var.environment }) @@ -97,3 +101,4 @@ resource "aws_cloudwatch_log_group" "terraform_plan_log_group" { data "aws_ssm_parameter" "dev_admin_role" { name = "/${var.environment}/developer_role" } + diff --git a/environment_roles/variables.tf b/environment_roles/variables.tf index 9064cba..9fa20b1 100644 --- a/environment_roles/variables.tf +++ b/environment_roles/variables.tf @@ -4,8 +4,4 @@ variable "account_number" {} variable "management_account_number" {} -variable "terraform_external_id" {} - -variable "terraform_github_role_arn" {} - -variable "management_developer_role_arn" {} +variable "terraform_repository_filters" {} \ No newline at end of file diff --git a/root.tf b/root.tf index 07a30b8..7dd3961 100644 --- a/root.tf +++ b/root.tf @@ -1,5 +1,6 @@ locals { terraform_state_bucket_name = "mgmt-dp-terraform-state" + terraform_role_arns = jsonencode([module.environment_roles_intg.terraform_role_arn, module.environment_roles_staging.terraform_role_arn, module.environment_roles_prod.terraform_role_arn]) code_deploy_bucket_name = "mgmt-dp-code-deploy" environments = toset(["intg", "staging", "prod"]) dev_notifications_channel_id = "C052LJASZ08" @@ -65,6 +66,9 @@ module "terraform_config" { module "terraform_s3_bucket" { source = "git::https://github.com/nationalarchives/da-terraform-modules.git//s3" bucket_name = local.terraform_state_bucket_name + bucket_policy = templatefile("${path.module}/templates/s3/terraform_state_policy.json.tpl", { + terraform_role_arns = local.terraform_role_arns + }) } module "da_terraform_dynamo" { @@ -77,23 +81,10 @@ module "dp_terraform_dynamo" { source = "git::https://github.com/nationalarchives/da-terraform-modules.git//dynamo" hash_key = { type = "S", name = "LockID" } table_name = "mgmt-dp-terraform-state-lock" -} - -module "terraform_github_repository_iam" { - source = "git::https://github.com/nationalarchives/da-terraform-modules.git//iam_role" - assume_role_policy = templatefile("${path.module}/templates/iam_role/github_assume_role.json.tpl", { - account_id = data.aws_caller_identity.current.account_id, - repo_filters = jsonencode([ - "repo:nationalarchives/dr2-terraform-github-repositories:pull_request", - "repo:nationalarchives/dr2-terraform-github-repositories:ref:refs/heads/main" - ]) + resource_policy = templatefile("${path.module}/templates/dynamo/lock_table_policy.json.tpl", { + table_arn = module.dp_terraform_dynamo.table_arn + terraform_role_arns = local.terraform_role_arns }) - name = "MgmtDPTerraformGitHubRepositoriesRole" - policy_attachments = { - state_access_policy = module.terraform_github_repository_policy.policy_arn - ssm_policy = "arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess" - } - tags = {} } module "terraform_github_repository_da_iam" { @@ -110,44 +101,6 @@ module "terraform_github_repository_da_iam" { tags = {} } -module "terraform_github_terraform_environments" { - for_each = local.environments - source = "git::https://github.com/nationalarchives/da-terraform-modules.git//iam_role" - assume_role_policy = templatefile("${path.module}/templates/iam_role/github_assume_role.json.tpl", { - account_id = data.aws_caller_identity.current.account_id, - repo_filters = jsonencode(concat( - module.department_terraform_repository_filters.repository_environments["dr2-${each.key}"], - module.dr2_terraform_repository_filters.repository_environments[each.key], - ["repo:nationalarchives/tna-custodian:pull_request", "repo:nationalarchives/tdr-aws-accounts:pull_request"] - )) - }) - name = "MgmtDPGithubTerraformEnvironmentsRole${title(each.key)}" - policy_attachments = { - state_access_policy = module.terraform_github_repository_policy.policy_arn - terraform_environments_policy = module.terraform_github_terraform_environments_policy[each.key].policy_arn - } - tags = {} -} - -module "terraform_github_terraform_environments_policy" { - for_each = local.environments - source = "git::https://github.com/nationalarchives/da-terraform-modules.git//iam_policy" - name = "MgmtDPGithubTerraformEnvironmentsPolicy${each.key}" - policy_string = templatefile("./templates/iam_policy/terraform_mgmt_assume_role.json.tpl", { - terraform_role_arn = local.environments_roles[each.key] - preservica_copy_role_intg_arn = module.environment_roles_intg.copy_tna_to_preservica_role_arn[0] - preservica_copy_role_staging_arn = module.environment_roles_staging.copy_tna_to_preservica_role_arn[0] - preservica_copy_role_prod_arn = module.environment_roles_prod.copy_tna_to_preservica_role_arn[0] - account_id = data.aws_caller_identity.current.account_id - }) -} - -module "terraform_github_repository_policy" { - source = "git::https://github.com/nationalarchives/da-terraform-modules.git//iam_policy" - name = "MgmtDPTerraformStateAccessPolicy" - policy_string = templatefile("${path.module}/templates/iam_policy/terraform_state_access.json.tpl", { bucket_name = local.terraform_state_bucket_name, dynamo_table_arn = module.dp_terraform_dynamo.table_arn }) -} - module "terraform_da_github_repository_policy" { source = "git::https://github.com/nationalarchives/da-terraform-modules.git//iam_policy" name = "MgmtDATerraformGitHubRepositoriesPolicy" @@ -158,49 +111,53 @@ module "environment_roles_intg" { providers = { aws = aws.intg } - source = "./environment_roles" - account_number = data.aws_ssm_parameter.intg_account_number.value - environment = "intg" - management_account_number = data.aws_caller_identity.current.account_id - terraform_external_id = module.terraform_config.terraform_config["intg"]["terraform_external_id"] - terraform_github_role_arn = module.terraform_github_terraform_environments["intg"].role_arn - management_developer_role_arn = data.aws_ssm_parameter.dev_admin_role.value + source = "./environment_roles" + account_number = data.aws_ssm_parameter.intg_account_number.value + environment = "intg" + management_account_number = data.aws_caller_identity.current.account_id + terraform_repository_filters = jsonencode(concat( + module.department_terraform_repository_filters.repository_environments["dr2-intg"], + module.dr2_terraform_repository_filters.repository_environments["intg"] + )) } module "environment_roles_staging" { providers = { aws = aws.staging } - source = "./environment_roles" - account_number = data.aws_ssm_parameter.staging_account_number.value - environment = "staging" - management_account_number = data.aws_caller_identity.current.account_id - terraform_external_id = module.terraform_config.terraform_config["staging"]["terraform_external_id"] - terraform_github_role_arn = module.terraform_github_terraform_environments["staging"].role_arn - management_developer_role_arn = data.aws_ssm_parameter.dev_admin_role.value + source = "./environment_roles" + account_number = data.aws_ssm_parameter.staging_account_number.value + environment = "staging" + management_account_number = data.aws_caller_identity.current.account_id + terraform_repository_filters = jsonencode(concat( + module.department_terraform_repository_filters.repository_environments["dr2-staging"], + module.dr2_terraform_repository_filters.repository_environments["staging"] + )) } module "environment_roles_prod" { providers = { aws = aws.prod } - source = "./environment_roles" - account_number = data.aws_ssm_parameter.prod_account_number.value - environment = "prod" - management_account_number = data.aws_caller_identity.current.account_id - terraform_external_id = module.terraform_config.terraform_config["prod"]["terraform_external_id"] - terraform_github_role_arn = module.terraform_github_terraform_environments["prod"].role_arn - management_developer_role_arn = data.aws_ssm_parameter.dev_admin_role.value + source = "./environment_roles" + account_number = data.aws_ssm_parameter.prod_account_number.value + environment = "prod" + management_account_number = data.aws_caller_identity.current.account_id + terraform_repository_filters = jsonencode(concat( + module.department_terraform_repository_filters.repository_environments["dr2-prod"], + module.dr2_terraform_repository_filters.repository_environments["prod"] + )) } module "environment_roles_mgmt" { - source = "./environment_roles" - account_number = data.aws_caller_identity.current.account_id - environment = "mgmt" - management_account_number = data.aws_caller_identity.current.account_id - terraform_external_id = module.terraform_config.terraform_config["mgmt"]["terraform_external_id"] - terraform_github_role_arn = module.terraform_github_repository_iam.role_arn - management_developer_role_arn = data.aws_ssm_parameter.dev_admin_role.value + source = "./environment_roles" + account_number = data.aws_caller_identity.current.account_id + environment = "mgmt" + management_account_number = data.aws_caller_identity.current.account_id + terraform_repository_filters = jsonencode(concat( + module.department_terraform_repository_filters.repository_environments["dr2-mgmt"], + module.dr2_terraform_repository_filters.repository_environments["mgmt"] + )) } module "code_deploy_bucket" { @@ -254,20 +211,6 @@ resource "aws_ecr_registry_scanning_configuration" "enhanced_scanning" { scan_type = "ENHANCED" } -module "e2e_tests_repository" { - source = "git::https://github.com/nationalarchives/da-terraform-modules.git//ecr" - repository_name = "e2e-tests" - repository_policy = templatefile("${path.module}/templates/ecr/cross_account_repository_policy.json.tpl", { - allowed_principals = jsonencode([ - "arn:aws:iam::${data.aws_ssm_parameter.intg_account_number.value}:role/intg-dr2-e2e-tests-execution-role", - "arn:aws:iam::${data.aws_ssm_parameter.staging_account_number.value}:role/staging-dr2-e2e-tests-execution-role" - ]), - account_number = data.aws_caller_identity.current.account_id - }) - common_tags = {} - image_source_url = "https://github.com/nationalarchives/dr2-e2e-tests" -} - module "custodial_copy_backend_repository" { source = "git::https://github.com/nationalarchives/da-terraform-modules.git//ecr" repository_name = "dr2-custodial-copy-backend" diff --git a/root_data.tf b/root_data.tf index 3666388..ea42fec 100644 --- a/root_data.tf +++ b/root_data.tf @@ -21,6 +21,3 @@ data "aws_ssm_parameter" "dr2_notifications_slack_channel" { name = "/mgmt/slack/notifications/channel" } -data "aws_ssm_parameter" "dev_admin_role" { - name = "/mgmt/developer_role" -} diff --git a/templates/dynamo/lock_table_policy.json.tpl b/templates/dynamo/lock_table_policy.json.tpl new file mode 100644 index 0000000..e9bc4d3 --- /dev/null +++ b/templates/dynamo/lock_table_policy.json.tpl @@ -0,0 +1,19 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "AllowAccountAccess", + "Effect": "Allow", + "Principal": { + "AWS": ${terraform_role_arns} + }, + "Action": [ + "dynamodb:DescribeTable", + "dynamodb:DeleteItem", + "dynamodb:GetItem", + "dynamodb:PutItem" + ], + "Resource": "${table_arn}" + } + ] +} \ No newline at end of file diff --git a/templates/iam_policy/terraform_policy.json.tpl b/templates/iam_policy/terraform_policy.json.tpl index dd3dbc7..7f2d668 100644 --- a/templates/iam_policy/terraform_policy.json.tpl +++ b/templates/iam_policy/terraform_policy.json.tpl @@ -55,6 +55,23 @@ "arn:aws:iam::${account_id}:policy/${environment_title}*", "arn:aws:iam::${account_id}:instance-profile/${environment}*" ] + }, + { + "Action": [ + "dynamodb:DescribeTable", + "dynamodb:DeleteItem", + "dynamodb:GetItem", + "dynamodb:PutItem", + "s3:GetObject", + "s3:ListBucket", + "s3:PutObject" + ], + "Effect": "Allow", + "Resource": [ + "arn:aws:s3:::mgmt-dp-terraform-state", + "arn:aws:s3:::mgmt-dp-terraform-state/*", + "arn:aws:dynamodb:eu-west-2:${management_account_id}:table/mgmt-dp-terraform-state-lock" + ] } ] } diff --git a/templates/iam_policy/tna_to_preservica_copy.json.tpl b/templates/iam_policy/tna_to_preservica_copy.json.tpl index ad9b636..552496a 100644 --- a/templates/iam_policy/tna_to_preservica_copy.json.tpl +++ b/templates/iam_policy/tna_to_preservica_copy.json.tpl @@ -27,6 +27,7 @@ "datasync:CancelTaskExecution", "datasync:DescribeLocation*", "datasync:CreateTask", + "datasync:CreateLocationS3", "datasync:DescribeTask", "datasync:DescribeLocation*", "datasync:StartTaskExecution", diff --git a/templates/iam_role/account_assume_role.json.tpl b/templates/iam_role/account_assume_role.json.tpl index 48fd699..10ad6c7 100644 --- a/templates/iam_role/account_assume_role.json.tpl +++ b/templates/iam_role/account_assume_role.json.tpl @@ -4,12 +4,22 @@ { "Effect": "Allow", "Principal": { - "AWS": "arn:aws:iam::${account_id}:root" + "AWS": "${admin_role_arn}" }, - "Action": "sts:AssumeRole", + "Action": "sts:AssumeRole" + }, + { + "Effect": "Allow", + "Principal": { + "Federated": "arn:aws:iam::${account_id}:oidc-provider/token.actions.githubusercontent.com" + }, + "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { - "sts:ExternalId": "${external_id}" + "token.actions.githubusercontent.com:aud": "sts.amazonaws.com" + }, + "StringLike": { + "token.actions.githubusercontent.com:sub": ${repo_filters} } } } diff --git a/templates/s3/terraform_state_policy.json.tpl b/templates/s3/terraform_state_policy.json.tpl new file mode 100644 index 0000000..42f943b --- /dev/null +++ b/templates/s3/terraform_state_policy.json.tpl @@ -0,0 +1,21 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "Allow account roles access", + "Effect": "Allow", + "Principal": { + "AWS": ${terraform_role_arns} + }, + "Action": [ + "s3:GetObject", + "s3:ListBucket", + "s3:PutObject" + ], + "Resource": [ + "arn:aws:s3:::mgmt-dp-terraform-state", + "arn:aws:s3:::mgmt-dp-terraform-state/*" + ] + } + ] +}