From b0d3a05e37851e0e0dddc326b38aa86dd3abfe06 Mon Sep 17 00:00:00 2001 From: BenFielder Date: Tue, 7 Jul 2026 14:15:58 +0100 Subject: [PATCH 01/21] feat: Update IAM policy document to limit ECR permissions (DBTP-3170) --- terraform/codebase-pipelines/ecr.tf | 63 +++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/terraform/codebase-pipelines/ecr.tf b/terraform/codebase-pipelines/ecr.tf index 2dd3af2f1..e9d96a8eb 100644 --- a/terraform/codebase-pipelines/ecr.tf +++ b/terraform/codebase-pipelines/ecr.tf @@ -25,11 +25,7 @@ data "aws_iam_policy_document" "ecr_policy" { actions = [ "ecr:BatchCheckLayerAvailability", "ecr:BatchGetImage", - "ecr:CompleteLayerUpload", "ecr:GetDownloadUrlForLayer", - "ecr:InitiateLayerUpload", - "ecr:PutImage", - "ecr:UploadLayerPart" ] principals { @@ -41,6 +37,65 @@ data "aws_iam_policy_document" "ecr_policy" { } } + statement { + effect = "Allow" + sid = "allowECRAuthentication" + actions = [ + "ecr:GetAuthorizationToken" + ] + resources = "*" + } + + statement { + sid = "AllowImagePull" + effect = "Allow" + actions = [ + "ecr:BatchGetImage", + "ecr:BatchCheckLayerAvailability", + "ecr:GetDownloadUrlForLayer" + ] + resources = [ + "arn:aws:ecr:eu-west-2:${id}:repository/${locals.ecr_name}", + ] + } + + statement { + sid = "AllowSignatureRevokeCheck" + effect = "Allow" + actions = [ + "signer:GetRevocationStatus" + ] + resources = [ + "*" + ] + } + + statement { + effect = "Allow" + sid = "PushActions" + + actions = [ + "ecr:CompleteLayerUpload", + "ecr:InitiateLayerUpload", + "ecr:PutImage", + "ecr:UploadLayerPart" + ] + + principals { + type = "AWS" + identifiers = ["*"] + } + + condition { + test = "StringLike" + variable = "aws:PrincipalArn" + values = [ + "arn:aws:iam::${id}:role/aws-reserved/sso.amazonaws.com/eu-west-2/AWSReservedSSO_AdministratorAccess_*", + "arn:aws:iam::${id}:role/GithubActionsRole" #Replace me once you know the role it should be! + ] + } + } + statement { sid = "PreventRepoDelete" effect = "Deny" From 551a9f43e74da5435dd31a6c3a86810ff0fc1f7b Mon Sep 17 00:00:00 2001 From: BenFielder Date: Thu, 9 Jul 2026 11:13:56 +0100 Subject: [PATCH 02/21] Add role names for github actions and paketo --- terraform/codebase-pipelines/ecr.tf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/terraform/codebase-pipelines/ecr.tf b/terraform/codebase-pipelines/ecr.tf index e9d96a8eb..86872d089 100644 --- a/terraform/codebase-pipelines/ecr.tf +++ b/terraform/codebase-pipelines/ecr.tf @@ -91,7 +91,8 @@ data "aws_iam_policy_document" "ecr_policy" { variable = "aws:PrincipalArn" values = [ "arn:aws:iam::${id}:role/aws-reserved/sso.amazonaws.com/eu-west-2/AWSReservedSSO_AdministratorAccess_*", - "arn:aws:iam::${id}:role/GithubActionsRole" #Replace me once you know the role it should be! + "arn:aws:iam::${id}:role/github-oidc-${var.application}-repo-role", + "arn:aws:iam::${id}:role/${var.application}-${var.codebase}-codebase-image-build" ] } } From 00b0f0b595c66a1f43d5429b6ef2bd25bd5b370b Mon Sep 17 00:00:00 2001 From: Connor Hindle Date: Tue, 18 Aug 2026 15:49:08 +0100 Subject: [PATCH 03/21] allow image build role to delete --- terraform/codebase-pipelines/ecr.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terraform/codebase-pipelines/ecr.tf b/terraform/codebase-pipelines/ecr.tf index 86872d089..dabfd4036 100644 --- a/terraform/codebase-pipelines/ecr.tf +++ b/terraform/codebase-pipelines/ecr.tf @@ -127,7 +127,7 @@ data "aws_iam_policy_document" "ecr_policy" { condition { test = "ArnNotLike" variable = "aws:PrincipalArn" - values = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/ecr-housekeeping-role"] + values = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/ecr-housekeeping-role", "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/github-oidc-${var.application}-platform-image-build"] } } } From 7621040f61baf57773d8ca235ac26fc6c2daeea1 Mon Sep 17 00:00:00 2001 From: BenFielder Date: Wed, 19 Aug 2026 10:41:30 +0100 Subject: [PATCH 04/21] Update policy to have conditional sections based on pipeline_mode --- terraform/codebase-pipelines/ecr.tf | 234 ++++++++++++++++++---------- 1 file changed, 150 insertions(+), 84 deletions(-) diff --git a/terraform/codebase-pipelines/ecr.tf b/terraform/codebase-pipelines/ecr.tf index 1ed75fad5..79a8eab0c 100644 --- a/terraform/codebase-pipelines/ecr.tf +++ b/terraform/codebase-pipelines/ecr.tf @@ -13,124 +13,190 @@ resource "aws_ecr_repository" "this" { } } -resource "aws_ecr_repository_policy" "ecr_policy" { +resource "aws_ecr_repository_policy" "ecr_repo_policy" { repository = aws_ecr_repository.this.name policy = data.aws_iam_policy_document.ecr_policy.json } data "aws_iam_policy_document" "ecr_policy" { - statement { - effect = "Allow" + statement { + sid = "PreventRepoDelete" + effect = "Deny" actions = [ - "ecr:BatchCheckLayerAvailability", - "ecr:BatchGetImage", - "ecr:GetDownloadUrlForLayer", + "ecr:DeleteRepository" ] - principals { - type = "AWS" - identifiers = [ - for id in local.deploy_account_ids : - "arn:aws:iam::${id}:root" - ] + type = "AWS" + identifiers = ["*"] } } statement { - effect = "Allow" - sid = "allowECRAuthentication" + sid = "PreventImageDelete" + effect = "Deny" actions = [ - "ecr:GetAuthorizationToken" + "ecr:BatchDeleteImage" ] - resources = "*" - } + principals { + type = "*" + identifiers = ["*"] + } + condition { + test = "ArnNotLike" + variable = "aws:PrincipalArn" - statement { - sid = "AllowImagePull" - effect = "Allow" - actions = [ - "ecr:BatchGetImage", - "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer" - ] - resources = [ - "arn:aws:ecr:eu-west-2:${id}:repository/${locals.ecr_name}", - ] + values = compact([ + "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/ecr-housekeeping-role", + contains(["dual_codepipeline_github", "github_actions"], var.pipeline_mode) + ? "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/github-oidc-${var.application}-platform-image-build" + : "" + ]) + } } - statement { - sid = "AllowSignatureRevokeCheck" - effect = "Allow" - actions = [ - "signer:GetRevocationStatus" - ] - resources = [ - "*" - ] + # ========================================== + # CodePipeline / Dual mode policy + # ========================================== + + dynamic "statement" { + for_each = contains(["aws_codepipeline", "dual_codepipeline_github"], var.pipeline_mode) ? [1] : [] + + content { + sid = "BasicECRAccess" + effect = "Allow" + actions = [ + "ecr:BatchCheckLayerAvailability", + "ecr:BatchGetImage", + "ecr:CompleteLayerUpload", + "ecr:GetDownloadUrlForLayer", + "ecr:InitiateLayerUpload", + "ecr:PutImage", + "ecr:UploadLayerPart" + ] + principals { + type = "AWS" + identifiers = [ + for id in local.deploy_account_ids : "arn:aws:iam::${id}:root" + ] + } + condition { + test = "StringLike" + variable = "aws:PrincipalArn" + values = flatten([ + for id in local.deploy_account_ids : [ + "arn:aws:iam::${id}:role/aws-reserved/sso.amazonaws.com/eu-west-2/AWSReservedSSO_AdministratorAccess_*", + "arn:aws:iam::${id}:role/github-oidc-${var.application}-platform-image-build", + "arn:aws:iam::${id}:role/${var.application}-${var.codebase}-codebase-image-build" + ] + ]) + } + } } - statement { - effect = "Allow" - sid = "PushActions" - - actions = [ - "ecr:CompleteLayerUpload", - "ecr:InitiateLayerUpload", - "ecr:PutImage", - "ecr:UploadLayerPart" - ] + # ========================================== + # Github actions policy + # ========================================== - principals { - type = "AWS" - identifiers = ["*"] - } + dynamic "statement" { + for_each = var.pipeline_mode == "github_actions" ? [1] : [] - condition { - test = "StringLike" - variable = "aws:PrincipalArn" - values = [ - "arn:aws:iam::${id}:role/aws-reserved/sso.amazonaws.com/eu-west-2/AWSReservedSSO_AdministratorAccess_*", - "arn:aws:iam::${id}:role/github-oidc-${var.application}-repo-role", - "arn:aws:iam::${id}:role/${var.application}-${var.codebase}-codebase-image-build" + content { + sid = "EnhancedRootPull" + effect = "Allow" + actions = [ + "ecr:BatchCheckLayerAvailability", + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer", ] + principals { + type = "AWS" + identifiers = [ + for id in local.deploy_account_ids : "arn:aws:iam::${id}:root" + ] + } } } - statement { - sid = "PreventRepoDelete" - effect = "Deny" + dynamic "statement" { + for_each = var.pipeline_mode == "github_actions" ? [1] : [] + + content { + sid = "allowECRAuthentication" + effect = "Allow" + actions = ["ecr:GetAuthorizationToken"] + resources = ["*"] + principals { + type = "AWS" + identifiers = ["*"] + } + } + } - actions = [ - "ecr:DeleteRepository" - ] + dynamic "statement" { + for_each = var.pipeline_mode == "github_actions" ? [1] : [] - principals { - type = "AWS" - identifiers = ["*"] + content { + sid = "AllowImagePull" + effect = "Allow" + actions = [ + "ecr:BatchGetImage", + "ecr:BatchCheckLayerAvailability", + "ecr:GetDownloadUrlForLayer" + ] + resources = [ + "arn:aws:ecr:eu-west-2:${data.aws_caller_identity.current.account_id}:repository/${local.ecr_name}", + ] + principals { + type = "AWS" + identifiers = ["*"] + } } } - statement { - sid = "PreventImageDelete" - effect = "Deny" + dynamic "statement" { + for_each = var.pipeline_mode == "github_actions" ? [1] : [] - actions = [ - "ecr:BatchDeleteImage" - ] - - principals { - type = "*" - identifiers = ["*"] + content { + sid = "AllowSignatureRevokeCheck" + effect = "Allow" + actions = [ + "signer:GetRevocationStatus" + ] + resources = ["*"] + principals { + type = "AWS" + identifiers = ["*"] + } } + } - condition { - test = "ArnNotLike" - variable = "aws:PrincipalArn" - values = [ - "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/ecr-housekeeping-role", - "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/github-oidc-${var.application}-platform-image-build" + dynamic "statement" { + for_each = var.pipeline_mode == "github_actions" ? [1] : [] + + content { + sid = "PushActions" + effect = "Allow" + actions = [ + "ecr:CompleteLayerUpload", + "ecr:InitiateLayerUpload", + "ecr:PutImage", + "ecr:UploadLayerPart" ] + principals { + type = "AWS" + identifiers = ["*"] + } + condition { + test = "StringLike" + variable = "aws:PrincipalArn" + values = flatten([ + for id in local.deploy_account_ids : [ + "arn:aws:iam::${id}:role/aws-reserved/sso.amazonaws.com/eu-west-2/AWSReservedSSO_AdministratorAccess_*", + "arn:aws:iam::${id}:role/github-oidc-${var.application}-repo-role" + ] + ]) + } } } -} +} \ No newline at end of file From 415a71c7c74ea42adfabc3b6e9f18352009701ed Mon Sep 17 00:00:00 2001 From: BenFielder Date: Wed, 19 Aug 2026 10:43:27 +0100 Subject: [PATCH 05/21] Change name to match original file --- terraform/codebase-pipelines/ecr.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terraform/codebase-pipelines/ecr.tf b/terraform/codebase-pipelines/ecr.tf index 79a8eab0c..7c52ec92c 100644 --- a/terraform/codebase-pipelines/ecr.tf +++ b/terraform/codebase-pipelines/ecr.tf @@ -13,7 +13,7 @@ resource "aws_ecr_repository" "this" { } } -resource "aws_ecr_repository_policy" "ecr_repo_policy" { +resource "aws_ecr_repository_policy" "ecr_policy" { repository = aws_ecr_repository.this.name policy = data.aws_iam_policy_document.ecr_policy.json } From e188d4a6fa7218eca5b978e6bc2d164b1f927dd9 Mon Sep 17 00:00:00 2001 From: BenFielder Date: Wed, 19 Aug 2026 13:46:04 +0100 Subject: [PATCH 06/21] Updates based on PR feedback --- terraform/codebase-pipelines/ecr.tf | 98 +++++++++++------------------ 1 file changed, 35 insertions(+), 63 deletions(-) diff --git a/terraform/codebase-pipelines/ecr.tf b/terraform/codebase-pipelines/ecr.tf index 7c52ec92c..c2a93d0d1 100644 --- a/terraform/codebase-pipelines/ecr.tf +++ b/terraform/codebase-pipelines/ecr.tf @@ -55,16 +55,40 @@ data "aws_iam_policy_document" "ecr_policy" { } } + dynamic "statement" { + for_each = var.pipeline_mode == "aws_codepipeline" ? [1] : [] + + content { + effect = "Allow" + actions = [ + "ecr:BatchCheckLayerAvailability", + "ecr:BatchGetImage", + "ecr:CompleteLayerUpload", + "ecr:GetDownloadUrlForLayer", + "ecr:InitiateLayerUpload", + "ecr:PutImage", + "ecr:UploadLayerPart" + ] + principals { + type = "AWS" + identifiers = [ + for id in local.deploy_account_ids : + "arn:aws:iam::${id}:root" + ] + } + } + } + # ========================================== - # CodePipeline / Dual mode policy + # Github Actions & Paketo/BYOD policy # ========================================== dynamic "statement" { - for_each = contains(["aws_codepipeline", "dual_codepipeline_github"], var.pipeline_mode) ? [1] : [] + for_each = contains(["dual_codepipeline_github"], var.pipeline_mode) ? [1] : [] content { sid = "BasicECRAccess" - effect = "Allow" + effect = "Deny" actions = [ "ecr:BatchCheckLayerAvailability", "ecr:BatchGetImage", @@ -81,7 +105,7 @@ data "aws_iam_policy_document" "ecr_policy" { ] } condition { - test = "StringLike" + test = "ArnNotLike" variable = "aws:PrincipalArn" values = flatten([ for id in local.deploy_account_ids : [ @@ -95,11 +119,11 @@ data "aws_iam_policy_document" "ecr_policy" { } # ========================================== - # Github actions policy + # Github Actions & BYOD policy # ========================================== dynamic "statement" { - for_each = var.pipeline_mode == "github_actions" ? [1] : [] + for_each = (var.pipeline_mode == "github_actions" && var.requires_image_build == false) ? [1] : [] content { sid = "EnhancedRootPull" @@ -119,76 +143,24 @@ data "aws_iam_policy_document" "ecr_policy" { } dynamic "statement" { - for_each = var.pipeline_mode == "github_actions" ? [1] : [] - - content { - sid = "allowECRAuthentication" - effect = "Allow" - actions = ["ecr:GetAuthorizationToken"] - resources = ["*"] - principals { - type = "AWS" - identifiers = ["*"] - } - } - } - - dynamic "statement" { - for_each = var.pipeline_mode == "github_actions" ? [1] : [] - - content { - sid = "AllowImagePull" - effect = "Allow" - actions = [ - "ecr:BatchGetImage", - "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer" - ] - resources = [ - "arn:aws:ecr:eu-west-2:${data.aws_caller_identity.current.account_id}:repository/${local.ecr_name}", - ] - principals { - type = "AWS" - identifiers = ["*"] - } - } - } - - dynamic "statement" { - for_each = var.pipeline_mode == "github_actions" ? [1] : [] - - content { - sid = "AllowSignatureRevokeCheck" - effect = "Allow" - actions = [ - "signer:GetRevocationStatus" - ] - resources = ["*"] - principals { - type = "AWS" - identifiers = ["*"] - } - } - } - - dynamic "statement" { - for_each = var.pipeline_mode == "github_actions" ? [1] : [] + for_each = (var.pipeline_mode == "github_actions" && var.requires_image_build == false) ? [1] : [] content { sid = "PushActions" - effect = "Allow" + effect = "Deny" actions = [ "ecr:CompleteLayerUpload", "ecr:InitiateLayerUpload", "ecr:PutImage", - "ecr:UploadLayerPart" + "ecr:UploadLayerPart", + "ecr:BatchCheckLayerAvailability" ] principals { type = "AWS" identifiers = ["*"] } condition { - test = "StringLike" + test = "ArnNotLike" variable = "aws:PrincipalArn" values = flatten([ for id in local.deploy_account_ids : [ From f5d0aa939a140c6ce79511102d647a9b4770cd19 Mon Sep 17 00:00:00 2001 From: BenFielder Date: Wed, 19 Aug 2026 13:57:25 +0100 Subject: [PATCH 07/21] Run tf fmt --- terraform/codebase-pipelines/ecr.tf | 32 ++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/terraform/codebase-pipelines/ecr.tf b/terraform/codebase-pipelines/ecr.tf index c2a93d0d1..14b5ba57a 100644 --- a/terraform/codebase-pipelines/ecr.tf +++ b/terraform/codebase-pipelines/ecr.tf @@ -59,23 +59,23 @@ data "aws_iam_policy_document" "ecr_policy" { for_each = var.pipeline_mode == "aws_codepipeline" ? [1] : [] content { - effect = "Allow" - actions = [ - "ecr:BatchCheckLayerAvailability", - "ecr:BatchGetImage", - "ecr:CompleteLayerUpload", - "ecr:GetDownloadUrlForLayer", - "ecr:InitiateLayerUpload", - "ecr:PutImage", - "ecr:UploadLayerPart" - ] - principals { - type = "AWS" - identifiers = [ - for id in local.deploy_account_ids : - "arn:aws:iam::${id}:root" + effect = "Allow" + actions = [ + "ecr:BatchCheckLayerAvailability", + "ecr:BatchGetImage", + "ecr:CompleteLayerUpload", + "ecr:GetDownloadUrlForLayer", + "ecr:InitiateLayerUpload", + "ecr:PutImage", + "ecr:UploadLayerPart" ] - } + principals { + type = "AWS" + identifiers = [ + for id in local.deploy_account_ids : + "arn:aws:iam::${id}:root" + ] + } } } From 6a7feaf421c6cb7224cb2303f2a2e51abdbb0b35 Mon Sep 17 00:00:00 2001 From: Dragos Stoian Date: Wed, 19 Aug 2026 14:24:02 +0100 Subject: [PATCH 08/21] Update terraform/codebase-pipelines/ecr.tf --- terraform/codebase-pipelines/ecr.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terraform/codebase-pipelines/ecr.tf b/terraform/codebase-pipelines/ecr.tf index 14b5ba57a..2f1645399 100644 --- a/terraform/codebase-pipelines/ecr.tf +++ b/terraform/codebase-pipelines/ecr.tf @@ -165,7 +165,7 @@ data "aws_iam_policy_document" "ecr_policy" { values = flatten([ for id in local.deploy_account_ids : [ "arn:aws:iam::${id}:role/aws-reserved/sso.amazonaws.com/eu-west-2/AWSReservedSSO_AdministratorAccess_*", - "arn:aws:iam::${id}:role/github-oidc-${var.application}-repo-role" + "arn:aws:iam::${id}:role/github-oidc-${var.application}-platform-image-build" ] ]) } From 35dc9da8674cec9cd33be6e16205f3225ecaa29d Mon Sep 17 00:00:00 2001 From: BenFielder Date: Wed, 19 Aug 2026 14:31:13 +0100 Subject: [PATCH 09/21] Separate out pull permissions --- terraform/codebase-pipelines/ecr.tf | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/terraform/codebase-pipelines/ecr.tf b/terraform/codebase-pipelines/ecr.tf index 2f1645399..4008a42d1 100644 --- a/terraform/codebase-pipelines/ecr.tf +++ b/terraform/codebase-pipelines/ecr.tf @@ -90,9 +90,6 @@ data "aws_iam_policy_document" "ecr_policy" { sid = "BasicECRAccess" effect = "Deny" actions = [ - "ecr:BatchCheckLayerAvailability", - "ecr:BatchGetImage", - "ecr:CompleteLayerUpload", "ecr:GetDownloadUrlForLayer", "ecr:InitiateLayerUpload", "ecr:PutImage", @@ -118,6 +115,26 @@ data "aws_iam_policy_document" "ecr_policy" { } } + dynamic "statement" { + for_each = contains(["dual_codepipeline_github"], var.pipeline_mode) ? [1] : [] + + content { + sid = "EnhancedRootPull" + effect = "Allow" + actions = [ + "ecr:BatchCheckLayerAvailability", + "ecr:BatchGetImage", + "ecr:CompleteLayerUpload" + ] + principals { + type = "AWS" + identifiers = [ + for id in local.deploy_account_ids : "arn:aws:iam::${id}:root" + ] + } + } + } + # ========================================== # Github Actions & BYOD policy # ========================================== From f480a3cc14bca247ef7f266707aa54a57b01d536 Mon Sep 17 00:00:00 2001 From: BenFielder Date: Wed, 19 Aug 2026 14:39:08 +0100 Subject: [PATCH 10/21] Move policy statements into no condition area --- terraform/codebase-pipelines/ecr.tf | 58 ++++++++--------------------- 1 file changed, 16 insertions(+), 42 deletions(-) diff --git a/terraform/codebase-pipelines/ecr.tf b/terraform/codebase-pipelines/ecr.tf index 4008a42d1..35b66d701 100644 --- a/terraform/codebase-pipelines/ecr.tf +++ b/terraform/codebase-pipelines/ecr.tf @@ -32,6 +32,22 @@ data "aws_iam_policy_document" "ecr_policy" { } } + statement { + sid = "RootPull" + effect = "Allow" + actions = [ + "ecr:BatchCheckLayerAvailability", + "ecr:BatchGetImage", + "ecr:CompleteLayerUpload" + ] + principals { + type = "AWS" + identifiers = [ + for id in local.deploy_account_ids : "arn:aws:iam::${id}:root" + ] + } + } + statement { sid = "PreventImageDelete" effect = "Deny" @@ -61,9 +77,6 @@ data "aws_iam_policy_document" "ecr_policy" { content { effect = "Allow" actions = [ - "ecr:BatchCheckLayerAvailability", - "ecr:BatchGetImage", - "ecr:CompleteLayerUpload", "ecr:GetDownloadUrlForLayer", "ecr:InitiateLayerUpload", "ecr:PutImage", @@ -115,49 +128,10 @@ data "aws_iam_policy_document" "ecr_policy" { } } - dynamic "statement" { - for_each = contains(["dual_codepipeline_github"], var.pipeline_mode) ? [1] : [] - - content { - sid = "EnhancedRootPull" - effect = "Allow" - actions = [ - "ecr:BatchCheckLayerAvailability", - "ecr:BatchGetImage", - "ecr:CompleteLayerUpload" - ] - principals { - type = "AWS" - identifiers = [ - for id in local.deploy_account_ids : "arn:aws:iam::${id}:root" - ] - } - } - } - # ========================================== # Github Actions & BYOD policy # ========================================== - dynamic "statement" { - for_each = (var.pipeline_mode == "github_actions" && var.requires_image_build == false) ? [1] : [] - - content { - sid = "EnhancedRootPull" - effect = "Allow" - actions = [ - "ecr:BatchCheckLayerAvailability", - "ecr:BatchGetImage", - "ecr:GetDownloadUrlForLayer", - ] - principals { - type = "AWS" - identifiers = [ - for id in local.deploy_account_ids : "arn:aws:iam::${id}:root" - ] - } - } - } dynamic "statement" { for_each = (var.pipeline_mode == "github_actions" && var.requires_image_build == false) ? [1] : [] From cddda654f44a79e69a482862c6b326086a5e37c2 Mon Sep 17 00:00:00 2001 From: BenFielder Date: Wed, 19 Aug 2026 14:40:30 +0100 Subject: [PATCH 11/21] TF fmt --- terraform/codebase-pipelines/ecr.tf | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/terraform/codebase-pipelines/ecr.tf b/terraform/codebase-pipelines/ecr.tf index 35b66d701..a147e0c88 100644 --- a/terraform/codebase-pipelines/ecr.tf +++ b/terraform/codebase-pipelines/ecr.tf @@ -33,20 +33,20 @@ data "aws_iam_policy_document" "ecr_policy" { } statement { - sid = "RootPull" - effect = "Allow" - actions = [ - "ecr:BatchCheckLayerAvailability", - "ecr:BatchGetImage", - "ecr:CompleteLayerUpload" + sid = "RootPull" + effect = "Allow" + actions = [ + "ecr:BatchCheckLayerAvailability", + "ecr:BatchGetImage", + "ecr:CompleteLayerUpload" + ] + principals { + type = "AWS" + identifiers = [ + for id in local.deploy_account_ids : "arn:aws:iam::${id}:root" ] - principals { - type = "AWS" - identifiers = [ - for id in local.deploy_account_ids : "arn:aws:iam::${id}:root" - ] - } } + } statement { sid = "PreventImageDelete" From 67c3a0e82da672822520e5a248a7134faa64f9f5 Mon Sep 17 00:00:00 2001 From: BenFielder Date: Wed, 19 Aug 2026 15:12:09 +0100 Subject: [PATCH 12/21] Update tests for new ECR policy --- .../codebase-pipelines/tests/unit.tftest.hcl | 57 +++++++++++++++---- 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/terraform/codebase-pipelines/tests/unit.tftest.hcl b/terraform/codebase-pipelines/tests/unit.tftest.hcl index 42b69431c..17412f370 100644 --- a/terraform/codebase-pipelines/tests/unit.tftest.hcl +++ b/terraform/codebase-pipelines/tests/unit.tftest.hcl @@ -396,18 +396,12 @@ run "test_ecr" { error_message = "Should be: {\"Sid\": \"ECRPolicy\"}" } assert { - condition = data.aws_iam_policy_document.ecr_policy.statement[0].effect == "Allow" - error_message = "Should be: Allow" + condition = data.aws_iam_policy_document.ecr_policy.statement[0].effect == "Deny" + error_message = "Should be: Deny" } assert { - condition = data.aws_iam_policy_document.ecr_policy.statement[0].actions == toset([ - "ecr:BatchCheckLayerAvailability", - "ecr:BatchGetImage", - "ecr:CompleteLayerUpload", - "ecr:GetDownloadUrlForLayer", - "ecr:InitiateLayerUpload", - "ecr:PutImage", - "ecr:UploadLayerPart" + condition = data.aws_iam_policy_document.ecr_policy.statement[2].values == toset([ + "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/ecr-housekeeping-role", ]) error_message = "Unexpected actions" } @@ -421,6 +415,49 @@ run "test_ecr" { } } +run "test_ecr_pipeline_mode_github" { + command = plan + + variables { + pipeline_mode = "github_actions" + } + assert { + condition = data.aws_iam_policy_document.ecr_policy.statement[5].values == toset([ + "arn:aws:iam::${id}:role/aws-reserved/sso.amazonaws.com/eu-west-2/AWSReservedSSO_AdministratorAccess_*", + "arn:aws:iam::${id}:role/github-oidc-${var.application}-platform-image-build" + ]) + error_message = "Unexpected values" + } + assert { + condition = data.aws_iam_policy_document.ecr_policy.statement[2].values == toset([ + "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/github-oidc-${var.application}-platform-image-build" + ]) + error_message = "Unexpected values" + } +} + +run "test_ecr_pipeline_mode_dual" { + command = plan + + variables { + pipeline_mode = "dual_codepipeline_github" + } + assert { + condition = data.aws_iam_policy_document.ecr_policy.statement[4].values == toset([ + "arn:aws:iam::${id}:role/aws-reserved/sso.amazonaws.com/eu-west-2/AWSReservedSSO_AdministratorAccess_*", + "arn:aws:iam::${id}:role/github-oidc-${var.application}-platform-image-build", + "arn:aws:iam::${id}:role/${var.application}-${var.codebase}-codebase-image-build" + ]) + error_message = "Unexpected values" + } + assert { + condition = data.aws_iam_policy_document.ecr_policy.statement[2].values == toset([ + "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/github-oidc-${var.application}-platform-image-build" + ]) + error_message = "Unexpected values" + } +} + run "test_artifact_store" { command = plan From 26166eb92af4439695b9d32138a22c73c0b7aaa3 Mon Sep 17 00:00:00 2001 From: BenFielder Date: Wed, 19 Aug 2026 15:21:33 +0100 Subject: [PATCH 13/21] Change test condition star expected --- terraform/codebase-pipelines/tests/unit.tftest.hcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terraform/codebase-pipelines/tests/unit.tftest.hcl b/terraform/codebase-pipelines/tests/unit.tftest.hcl index 17412f370..734110aca 100644 --- a/terraform/codebase-pipelines/tests/unit.tftest.hcl +++ b/terraform/codebase-pipelines/tests/unit.tftest.hcl @@ -410,7 +410,7 @@ run "test_ecr" { error_message = "Should be: AWS" } assert { - condition = flatten([for el in data.aws_iam_policy_document.ecr_policy.statement[0].principals : el.identifiers]) == ["arn:aws:iam::000123456789:root", "arn:aws:iam::123456789000:root"] + condition = flatten([for el in data.aws_iam_policy_document.ecr_policy.statement[0].principals : el.identifiers]) == ["*"] error_message = "ECR policy principals incorrect" } } From 7421106fcdb906d1930bbca8fe964c23e156a647 Mon Sep 17 00:00:00 2001 From: BenFielder Date: Wed, 19 Aug 2026 15:34:12 +0100 Subject: [PATCH 14/21] Update tests to read correct part of values --- terraform/codebase-pipelines/tests/unit.tftest.hcl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/terraform/codebase-pipelines/tests/unit.tftest.hcl b/terraform/codebase-pipelines/tests/unit.tftest.hcl index 734110aca..0663bbdb3 100644 --- a/terraform/codebase-pipelines/tests/unit.tftest.hcl +++ b/terraform/codebase-pipelines/tests/unit.tftest.hcl @@ -400,7 +400,7 @@ run "test_ecr" { error_message = "Should be: Deny" } assert { - condition = data.aws_iam_policy_document.ecr_policy.statement[2].values == toset([ + condition = toset(data.aws_iam_policy_document.ecr_policy.statement[2].condition[0].values) == toset([ "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/ecr-housekeeping-role", ]) error_message = "Unexpected actions" @@ -422,14 +422,14 @@ run "test_ecr_pipeline_mode_github" { pipeline_mode = "github_actions" } assert { - condition = data.aws_iam_policy_document.ecr_policy.statement[5].values == toset([ + condition = toset(data.aws_iam_policy_document.ecr_policy.statement[5].condition[0].values) == toset([ "arn:aws:iam::${id}:role/aws-reserved/sso.amazonaws.com/eu-west-2/AWSReservedSSO_AdministratorAccess_*", "arn:aws:iam::${id}:role/github-oidc-${var.application}-platform-image-build" ]) error_message = "Unexpected values" } assert { - condition = data.aws_iam_policy_document.ecr_policy.statement[2].values == toset([ + condition = toset(data.aws_iam_policy_document.ecr_policy.statement[2].condition[0].values) == toset([ "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/github-oidc-${var.application}-platform-image-build" ]) error_message = "Unexpected values" @@ -443,7 +443,7 @@ run "test_ecr_pipeline_mode_dual" { pipeline_mode = "dual_codepipeline_github" } assert { - condition = data.aws_iam_policy_document.ecr_policy.statement[4].values == toset([ + condition = toset(data.aws_iam_policy_document.ecr_policy.statement[4].condition[0].values) == toset([ "arn:aws:iam::${id}:role/aws-reserved/sso.amazonaws.com/eu-west-2/AWSReservedSSO_AdministratorAccess_*", "arn:aws:iam::${id}:role/github-oidc-${var.application}-platform-image-build", "arn:aws:iam::${id}:role/${var.application}-${var.codebase}-codebase-image-build" @@ -451,7 +451,7 @@ run "test_ecr_pipeline_mode_dual" { error_message = "Unexpected values" } assert { - condition = data.aws_iam_policy_document.ecr_policy.statement[2].values == toset([ + condition = toset(data.aws_iam_policy_document.ecr_policy.statement[2].condition[0].values) == toset([ "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/github-oidc-${var.application}-platform-image-build" ]) error_message = "Unexpected values" From 8c056326118e65860cedb46611d7f47c95843358 Mon Sep 17 00:00:00 2001 From: BenFielder Date: Wed, 19 Aug 2026 15:47:32 +0100 Subject: [PATCH 15/21] Fix issue with tests --- .../codebase-pipelines/tests/unit.tftest.hcl | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/terraform/codebase-pipelines/tests/unit.tftest.hcl b/terraform/codebase-pipelines/tests/unit.tftest.hcl index 0663bbdb3..fee6b43f1 100644 --- a/terraform/codebase-pipelines/tests/unit.tftest.hcl +++ b/terraform/codebase-pipelines/tests/unit.tftest.hcl @@ -422,14 +422,20 @@ run "test_ecr_pipeline_mode_github" { pipeline_mode = "github_actions" } assert { - condition = toset(data.aws_iam_policy_document.ecr_policy.statement[5].condition[0].values) == toset([ + condition = toset(flatten([ + for c in data.aws_iam_policy_document.ecr_policy.statement[5].condition : c.values + if c.variable == "aws:PrincipalArn" + ])) == toset([ "arn:aws:iam::${id}:role/aws-reserved/sso.amazonaws.com/eu-west-2/AWSReservedSSO_AdministratorAccess_*", "arn:aws:iam::${id}:role/github-oidc-${var.application}-platform-image-build" ]) error_message = "Unexpected values" } assert { - condition = toset(data.aws_iam_policy_document.ecr_policy.statement[2].condition[0].values) == toset([ + condition = toset(flatten([ + for c in data.aws_iam_policy_document.ecr_policy.statement[2].condition : c.values + if c.variable == "aws:PrincipalArn" + ])) == toset([ "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/github-oidc-${var.application}-platform-image-build" ]) error_message = "Unexpected values" @@ -443,7 +449,10 @@ run "test_ecr_pipeline_mode_dual" { pipeline_mode = "dual_codepipeline_github" } assert { - condition = toset(data.aws_iam_policy_document.ecr_policy.statement[4].condition[0].values) == toset([ + condition = toset(flatten([ + for c in data.aws_iam_policy_document.ecr_policy.statement[4].condition : c.values + if c.variable == "aws:PrincipalArn" + ])) == toset([ "arn:aws:iam::${id}:role/aws-reserved/sso.amazonaws.com/eu-west-2/AWSReservedSSO_AdministratorAccess_*", "arn:aws:iam::${id}:role/github-oidc-${var.application}-platform-image-build", "arn:aws:iam::${id}:role/${var.application}-${var.codebase}-codebase-image-build" @@ -451,7 +460,9 @@ run "test_ecr_pipeline_mode_dual" { error_message = "Unexpected values" } assert { - condition = toset(data.aws_iam_policy_document.ecr_policy.statement[2].condition[0].values) == toset([ + condition = toset(flatten([ + for c in data.aws_iam_policy_document.ecr_policy.statement[2].condition : c.values + ])) == toset([ "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/github-oidc-${var.application}-platform-image-build" ]) error_message = "Unexpected values" From 9090f339d16ce756a2c1e60103b9f21266898726 Mon Sep 17 00:00:00 2001 From: BenFielder Date: Wed, 19 Aug 2026 15:48:41 +0100 Subject: [PATCH 16/21] tf fmt tests --- terraform/codebase-pipelines/tests/unit.tftest.hcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terraform/codebase-pipelines/tests/unit.tftest.hcl b/terraform/codebase-pipelines/tests/unit.tftest.hcl index fee6b43f1..e003789db 100644 --- a/terraform/codebase-pipelines/tests/unit.tftest.hcl +++ b/terraform/codebase-pipelines/tests/unit.tftest.hcl @@ -461,7 +461,7 @@ run "test_ecr_pipeline_mode_dual" { } assert { condition = toset(flatten([ - for c in data.aws_iam_policy_document.ecr_policy.statement[2].condition : c.values + for c in data.aws_iam_policy_document.ecr_policy.statement[2].condition : c.values ])) == toset([ "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/github-oidc-${var.application}-platform-image-build" ]) From 9a48388361d40c061004ccdc60c9224ffec43e2c Mon Sep 17 00:00:00 2001 From: BenFielder Date: Wed, 19 Aug 2026 15:51:40 +0100 Subject: [PATCH 17/21] fmt and fix test --- terraform/codebase-pipelines/tests/unit.tftest.hcl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/terraform/codebase-pipelines/tests/unit.tftest.hcl b/terraform/codebase-pipelines/tests/unit.tftest.hcl index e003789db..c573a2c79 100644 --- a/terraform/codebase-pipelines/tests/unit.tftest.hcl +++ b/terraform/codebase-pipelines/tests/unit.tftest.hcl @@ -400,7 +400,10 @@ run "test_ecr" { error_message = "Should be: Deny" } assert { - condition = toset(data.aws_iam_policy_document.ecr_policy.statement[2].condition[0].values) == toset([ + condition = toset(flatten([ + for c in data.aws_iam_policy_document.ecr_policy.statement[2].condition : c.values + if c.variable == "aws:PrincipalArn" + ])) == toset([ "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/ecr-housekeeping-role", ]) error_message = "Unexpected actions" @@ -462,6 +465,7 @@ run "test_ecr_pipeline_mode_dual" { assert { condition = toset(flatten([ for c in data.aws_iam_policy_document.ecr_policy.statement[2].condition : c.values + if c.variable == "aws:PrincipalArn" ])) == toset([ "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/github-oidc-${var.application}-platform-image-build" ]) From 3db1cb33249d6858bba27044491ad7f204141334 Mon Sep 17 00:00:00 2001 From: BenFielder Date: Thu, 20 Aug 2026 09:08:54 +0100 Subject: [PATCH 18/21] try to recreate local var --- .../codebase-pipelines/tests/unit.tftest.hcl | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/terraform/codebase-pipelines/tests/unit.tftest.hcl b/terraform/codebase-pipelines/tests/unit.tftest.hcl index c573a2c79..f7b59e5ae 100644 --- a/terraform/codebase-pipelines/tests/unit.tftest.hcl +++ b/terraform/codebase-pipelines/tests/unit.tftest.hcl @@ -428,10 +428,12 @@ run "test_ecr_pipeline_mode_github" { condition = toset(flatten([ for c in data.aws_iam_policy_document.ecr_policy.statement[5].condition : c.values if c.variable == "aws:PrincipalArn" - ])) == toset([ - "arn:aws:iam::${id}:role/aws-reserved/sso.amazonaws.com/eu-west-2/AWSReservedSSO_AdministratorAccess_*", - "arn:aws:iam::${id}:role/github-oidc-${var.application}-platform-image-build" - ]) + ])) == toset(flatten([ + for id in ["000123456789", "111123456789"] : [ + "arn:aws:iam::${id}:role/aws-reserved/sso.amazonaws.com/eu-west-2/AWSReservedSSO_AdministratorAccess_*", + "arn:aws:iam::${id}:role/github-oidc-${var.application}-platform-image-build" + ] + ])) error_message = "Unexpected values" } assert { @@ -455,11 +457,12 @@ run "test_ecr_pipeline_mode_dual" { condition = toset(flatten([ for c in data.aws_iam_policy_document.ecr_policy.statement[4].condition : c.values if c.variable == "aws:PrincipalArn" - ])) == toset([ - "arn:aws:iam::${id}:role/aws-reserved/sso.amazonaws.com/eu-west-2/AWSReservedSSO_AdministratorAccess_*", - "arn:aws:iam::${id}:role/github-oidc-${var.application}-platform-image-build", - "arn:aws:iam::${id}:role/${var.application}-${var.codebase}-codebase-image-build" - ]) + ])) == toset(flatten([ + for id in ["000123456789", "111123456789"] : [ + "arn:aws:iam::${id}:role/aws-reserved/sso.amazonaws.com/eu-west-2/AWSReservedSSO_AdministratorAccess_*", + "arn:aws:iam::${id}:role/github-oidc-${var.application}-codebase-image-build" + ] + ])) error_message = "Unexpected values" } assert { From 94fc9e32dd1e08163204a8b3fbe40172bd3ebf46 Mon Sep 17 00:00:00 2001 From: BenFielder Date: Thu, 20 Aug 2026 11:27:44 +0100 Subject: [PATCH 19/21] fmt and add new test cases --- terraform/codebase-pipelines/iam.tf | 3 + .../codebase-pipelines/tests/unit.tftest.hcl | 67 +++++++++++++------ 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/terraform/codebase-pipelines/iam.tf b/terraform/codebase-pipelines/iam.tf index c2807be98..f5cf44d0f 100644 --- a/terraform/codebase-pipelines/iam.tf +++ b/terraform/codebase-pipelines/iam.tf @@ -295,6 +295,7 @@ data "aws_iam_policy_document" "ecr_access_for_codebase_pipeline" { } resource "aws_iam_role_policy" "artifact_store_access_for_codebase_pipeline" { + count = var.pipeline_mode != "github_actions" ? 1 : 0 name = "artifact-store-access" role = aws_iam_role.codebase_deploy_pipeline.name policy = data.aws_iam_policy_document.access_artifact_store.json @@ -357,6 +358,7 @@ resource "aws_iam_role" "codebase_deploy" { } resource "aws_iam_role_policy" "artifact_store_access_for_codebuild_deploy" { + count = var.pipeline_mode != "github_actions" ? 1 : 0 name = "artifact-store-access" role = aws_iam_role.codebase_deploy.name policy = data.aws_iam_policy_document.access_artifact_store.json @@ -699,6 +701,7 @@ resource "aws_iam_role_policy" "environment_deploy_role_access_for_update_alb_ru } resource "aws_iam_role_policy" "artifact_store_access_for_update_alb_rules" { + count = var.pipeline_mode != "github_actions" ? 1 : 0 name = "artifact-store-access" role = aws_iam_role.update_alb_rules.name policy = data.aws_iam_policy_document.access_artifact_store.json diff --git a/terraform/codebase-pipelines/tests/unit.tftest.hcl b/terraform/codebase-pipelines/tests/unit.tftest.hcl index f7b59e5ae..4e13e25c1 100644 --- a/terraform/codebase-pipelines/tests/unit.tftest.hcl +++ b/terraform/codebase-pipelines/tests/unit.tftest.hcl @@ -422,28 +422,40 @@ run "test_ecr_pipeline_mode_github" { command = plan variables { - pipeline_mode = "github_actions" + pipeline_mode = "github_actions" + requires_image_build = false + application = var.application + codebase = var.codebase } + assert { condition = toset(flatten([ - for c in data.aws_iam_policy_document.ecr_policy.statement[5].condition : c.values - if c.variable == "aws:PrincipalArn" + for s in data.aws_iam_policy_document.ecr_policy.statement : [ + for c in s.condition : c.values + if c.variable == "aws:PrincipalArn" + ] + if s.sid == "PushActions" ])) == toset(flatten([ - for id in ["000123456789", "111123456789"] : [ + for id in ["000123456789", "123456789000"] : [ "arn:aws:iam::${id}:role/aws-reserved/sso.amazonaws.com/eu-west-2/AWSReservedSSO_AdministratorAccess_*", "arn:aws:iam::${id}:role/github-oidc-${var.application}-platform-image-build" ] ])) - error_message = "Unexpected values" + error_message = "Unexpected values for PushActions" } + assert { condition = toset(flatten([ - for c in data.aws_iam_policy_document.ecr_policy.statement[2].condition : c.values - if c.variable == "aws:PrincipalArn" + for s in data.aws_iam_policy_document.ecr_policy.statement : [ + for c in s.condition : c.values + if c.variable == "aws:PrincipalArn" + ] + if s.sid == "PreventImageDelete" ])) == toset([ - "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/github-oidc-${var.application}-platform-image-build" + "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/github-oidc-${var.application}-platform-image-build", + "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/ecr-housekeeping-role" ]) - error_message = "Unexpected values" + error_message = "Unexpected values for PreventImageDelete" } } @@ -452,27 +464,40 @@ run "test_ecr_pipeline_mode_dual" { variables { pipeline_mode = "dual_codepipeline_github" + application = var.application + codebase = var.codebase } + assert { condition = toset(flatten([ - for c in data.aws_iam_policy_document.ecr_policy.statement[4].condition : c.values - if c.variable == "aws:PrincipalArn" + for s in data.aws_iam_policy_document.ecr_policy.statement : [ + for c in s.condition : c.values + if c.variable == "aws:PrincipalArn" + ] + if s.sid == "BasicECRAccess" ])) == toset(flatten([ - for id in ["000123456789", "111123456789"] : [ + for id in ["000123456789", "123456789000"] : [ "arn:aws:iam::${id}:role/aws-reserved/sso.amazonaws.com/eu-west-2/AWSReservedSSO_AdministratorAccess_*", - "arn:aws:iam::${id}:role/github-oidc-${var.application}-codebase-image-build" + # FIX: Added the platform-image-build role and corrected the codebase-image-build string + "arn:aws:iam::${id}:role/github-oidc-${var.application}-platform-image-build", + "arn:aws:iam::${id}:role/${var.application}-${var.codebase}-codebase-image-build" ] ])) - error_message = "Unexpected values" + error_message = "Unexpected values for BasicECRAccess" } + assert { condition = toset(flatten([ - for c in data.aws_iam_policy_document.ecr_policy.statement[2].condition : c.values - if c.variable == "aws:PrincipalArn" + for s in data.aws_iam_policy_document.ecr_policy.statement : [ + for c in s.condition : c.values + if c.variable == "aws:PrincipalArn" + ] + if s.sid == "PreventImageDelete" ])) == toset([ + "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/ecr-housekeeping-role", "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/github-oidc-${var.application}-platform-image-build" ]) - error_message = "Unexpected values" + error_message = "Unexpected values for PreventImageDelete" } } @@ -1102,11 +1127,11 @@ run "test_iam" { error_message = "Should be: ${jsonencode(var.expected_tags)}" } assert { - condition = aws_iam_role_policy.artifact_store_access_for_codebuild_deploy.name == "artifact-store-access" + condition = aws_iam_role_policy.artifact_store_access_for_codebuild_deploy[0].name == "artifact-store-access" error_message = "Should be: 'artifact-store-access'" } assert { - condition = aws_iam_role_policy.artifact_store_access_for_codebuild_deploy.role == "my-app-my-codebase-codebase-deploy" + condition = aws_iam_role_policy.artifact_store_access_for_codebuild_deploy[0].role == "my-app-my-codebase-codebase-deploy" error_message = "Should be: 'my-app-my-codebase-codebase-deploy'" } assert { @@ -1185,11 +1210,11 @@ run "test_iam" { error_message = "Should be: 'my-app-my-codebase-codebase-pipeline'" } assert { - condition = aws_iam_role_policy.artifact_store_access_for_codebase_pipeline.name == "artifact-store-access" + condition = aws_iam_role_policy.artifact_store_access_for_codebase_pipeline[0].name == "artifact-store-access" error_message = "Should be: 'artifact-store-access'" } assert { - condition = aws_iam_role_policy.artifact_store_access_for_codebase_pipeline.role == "my-app-my-codebase-codebase-pipeline" + condition = aws_iam_role_policy.artifact_store_access_for_codebase_pipeline[0].role == "my-app-my-codebase-codebase-pipeline" error_message = "Should be: 'my-app-my-codebase-codebase-pipeline'" } assert { From e1b23b3b16a021bce590a4bfc46dac55df9c206c Mon Sep 17 00:00:00 2001 From: BenFielder Date: Thu, 20 Aug 2026 12:22:15 +0100 Subject: [PATCH 20/21] Add spacing Signed-off-by: DBT pre-commit check --- terraform/codebase-pipelines/ecr.tf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/terraform/codebase-pipelines/ecr.tf b/terraform/codebase-pipelines/ecr.tf index a147e0c88..bfee637d9 100644 --- a/terraform/codebase-pipelines/ecr.tf +++ b/terraform/codebase-pipelines/ecr.tf @@ -54,10 +54,12 @@ data "aws_iam_policy_document" "ecr_policy" { actions = [ "ecr:BatchDeleteImage" ] + principals { type = "*" identifiers = ["*"] } + condition { test = "ArnNotLike" variable = "aws:PrincipalArn" From 74da15fc58c25f3bf2c2c3b0e4bdf8041a40769b Mon Sep 17 00:00:00 2001 From: BenFielder Date: Thu, 20 Aug 2026 14:25:19 +0100 Subject: [PATCH 21/21] Add override data to fix uneeded part on iam file Signed-off-by: DBT pre-commit check --- terraform/codebase-pipelines/iam.tf | 3 --- .../codebase-pipelines/tests/unit.tftest.hcl | 19 +++++++++++++++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/terraform/codebase-pipelines/iam.tf b/terraform/codebase-pipelines/iam.tf index f5cf44d0f..c2807be98 100644 --- a/terraform/codebase-pipelines/iam.tf +++ b/terraform/codebase-pipelines/iam.tf @@ -295,7 +295,6 @@ data "aws_iam_policy_document" "ecr_access_for_codebase_pipeline" { } resource "aws_iam_role_policy" "artifact_store_access_for_codebase_pipeline" { - count = var.pipeline_mode != "github_actions" ? 1 : 0 name = "artifact-store-access" role = aws_iam_role.codebase_deploy_pipeline.name policy = data.aws_iam_policy_document.access_artifact_store.json @@ -358,7 +357,6 @@ resource "aws_iam_role" "codebase_deploy" { } resource "aws_iam_role_policy" "artifact_store_access_for_codebuild_deploy" { - count = var.pipeline_mode != "github_actions" ? 1 : 0 name = "artifact-store-access" role = aws_iam_role.codebase_deploy.name policy = data.aws_iam_policy_document.access_artifact_store.json @@ -701,7 +699,6 @@ resource "aws_iam_role_policy" "environment_deploy_role_access_for_update_alb_ru } resource "aws_iam_role_policy" "artifact_store_access_for_update_alb_rules" { - count = var.pipeline_mode != "github_actions" ? 1 : 0 name = "artifact-store-access" role = aws_iam_role.update_alb_rules.name policy = data.aws_iam_policy_document.access_artifact_store.json diff --git a/terraform/codebase-pipelines/tests/unit.tftest.hcl b/terraform/codebase-pipelines/tests/unit.tftest.hcl index 4e13e25c1..f4b68884f 100644 --- a/terraform/codebase-pipelines/tests/unit.tftest.hcl +++ b/terraform/codebase-pipelines/tests/unit.tftest.hcl @@ -9,6 +9,17 @@ override_data { } } } + +override_data { + target = data.aws_iam_policy_document.access_artifact_store + values = { + json = jsonencode({ + Version = "2012-10-17" + Statement = [] + }) + } +} + override_data { target = data.aws_iam_policy_document.assume_codebuild_role values = { @@ -1127,11 +1138,11 @@ run "test_iam" { error_message = "Should be: ${jsonencode(var.expected_tags)}" } assert { - condition = aws_iam_role_policy.artifact_store_access_for_codebuild_deploy[0].name == "artifact-store-access" + condition = aws_iam_role_policy.artifact_store_access_for_codebuild_deploy.name == "artifact-store-access" error_message = "Should be: 'artifact-store-access'" } assert { - condition = aws_iam_role_policy.artifact_store_access_for_codebuild_deploy[0].role == "my-app-my-codebase-codebase-deploy" + condition = aws_iam_role_policy.artifact_store_access_for_codebuild_deploy.role == "my-app-my-codebase-codebase-deploy" error_message = "Should be: 'my-app-my-codebase-codebase-deploy'" } assert { @@ -1210,11 +1221,11 @@ run "test_iam" { error_message = "Should be: 'my-app-my-codebase-codebase-pipeline'" } assert { - condition = aws_iam_role_policy.artifact_store_access_for_codebase_pipeline[0].name == "artifact-store-access" + condition = aws_iam_role_policy.artifact_store_access_for_codebase_pipeline.name == "artifact-store-access" error_message = "Should be: 'artifact-store-access'" } assert { - condition = aws_iam_role_policy.artifact_store_access_for_codebase_pipeline[0].role == "my-app-my-codebase-codebase-pipeline" + condition = aws_iam_role_policy.artifact_store_access_for_codebase_pipeline.role == "my-app-my-codebase-codebase-pipeline" error_message = "Should be: 'my-app-my-codebase-codebase-pipeline'" } assert {