From 55bb8cfc97d329cabdb3e3be9b4327d5b9ecf319 Mon Sep 17 00:00:00 2001 From: sebas_correa Date: Mon, 8 Jun 2026 17:12:11 -0300 Subject: [PATCH] fix(ecr): add cross-account pull and repository policy support - infrastructure/aws/iam/ecr: add ecr_repository_policy output that generates the ECR repo policy JSON from pull_account_ids when enable_cross_account_pull is true - nullplatform/asset/ecr: add cross_account_pull_role_arn variable that populates the read.role_arn field in the provider config, enabling np_aws_ecr_assume_role on deployments - nullplatform/asset/ecr: add repository_policy variable that populates setup.policy, applied by Nullplatform on every new ECR repo created - nullplatform/asset/ecr: add naming_rule variable with Nullplatform default to avoid perpetual drift caused by the server-side injected field Co-Authored-By: Claude Sonnet 4.6 --- infrastructure/aws/iam/ecr/outputs.tf | 19 +++++++++++++++ nullplatform/asset/ecr/main.tf | 35 +++++++++++++++++---------- nullplatform/asset/ecr/variables.tf | 18 ++++++++++++++ 3 files changed, 59 insertions(+), 13 deletions(-) diff --git a/infrastructure/aws/iam/ecr/outputs.tf b/infrastructure/aws/iam/ecr/outputs.tf index c526adf5..e215215f 100644 --- a/infrastructure/aws/iam/ecr/outputs.tf +++ b/infrastructure/aws/iam/ecr/outputs.tf @@ -18,3 +18,22 @@ output "cross_account_pull_role_arn" { description = "ARN of the IAM role that cross-account principals can assume to pull ECR images. Empty string when enable_cross_account_pull is false." value = var.enable_cross_account_pull ? aws_iam_role.ecr_cross_account_pull[0].arn : "" } + +output "ecr_repository_policy" { + description = "ECR repository policy JSON granting pull access to the configured cross-account IDs. Empty string when enable_cross_account_pull is false." + value = var.enable_cross_account_pull ? jsonencode({ + Version = "2012-10-17" + Statement = [{ + Sid = "CrossAccountPull" + Effect = "Allow" + Principal = { + AWS = [for id in var.pull_account_ids : "arn:aws:iam::${id}:root"] + } + Action = [ + "ecr:GetDownloadUrlForLayer", + "ecr:BatchGetImage", + "ecr:BatchCheckLayerAvailability" + ] + }] + }) : "" +} diff --git a/nullplatform/asset/ecr/main.tf b/nullplatform/asset/ecr/main.tf index abcfd84a..9313202a 100644 --- a/nullplatform/asset/ecr/main.tf +++ b/nullplatform/asset/ecr/main.tf @@ -2,18 +2,27 @@ resource "nullplatform_provider_config" "ecr" { provider = nullplatform nrn = var.nrn type = "ecr" - attributes = jsonencode({ - "ci" : { - "region" : data.aws_region.current.region, - "access_key" : var.build_workflow_access_key_id, - "secret_key" : var.build_workflow_access_key_secret + attributes = jsonencode(merge( + { + "ci" : { + "region" : data.aws_region.current.region, + "access_key" : var.build_workflow_access_key_id, + "secret_key" : var.build_workflow_access_key_secret + }, + "setup" : merge( + { + "region" : data.aws_region.current.region, + "role_arn" : var.application_role_arn, + "naming_rule" : var.naming_rule, + }, + var.repository_policy != "" ? { "policy" : var.repository_policy } : {} + ) }, - "setup" : { - "region" : data.aws_region.current.region, - "role_arn" : var.application_role_arn, - } - }) - lifecycle { - ignore_changes = [attributes] - } + var.cross_account_pull_role_arn != "" ? { + "read" : { + "region" : data.aws_region.current.region, + "role_arn" : var.cross_account_pull_role_arn + } + } : {} + )) } diff --git a/nullplatform/asset/ecr/variables.tf b/nullplatform/asset/ecr/variables.tf index 664078d9..5a6b31b7 100644 --- a/nullplatform/asset/ecr/variables.tf +++ b/nullplatform/asset/ecr/variables.tf @@ -24,3 +24,21 @@ variable "build_workflow_access_key_secret" { type = string sensitive = true } + +variable "cross_account_pull_role_arn" { + description = "ARN of the IAM role for cross-account ECR pull access (maps to 'read.role_arn' in provider config). Leave empty to omit the read section." + type = string + default = "" +} + +variable "repository_policy" { + description = "ECR repository policy JSON applied to every new repository Nullplatform creates (maps to 'setup.policy'). Leave empty to omit." + type = string + default = "" +} + +variable "naming_rule" { + description = "jq expression for ECR repository naming convention. Defaults to the Nullplatform platform default." + type = string + default = "\"\\(.namespace.slug)/\\(.application.slug)\"" +}