From 7cf936dc875539ada981e75ef92bf4b75962d8a9 Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Mon, 19 May 2025 13:57:26 +0200 Subject: [PATCH] Enable context replacements for IAM principals in project factory module (#3094) * enable context replacements for iam principals in pf module * test changes --- modules/project-factory/README.md | 3 +++ modules/project-factory/folders.tf | 9 ++++++-- modules/project-factory/main.tf | 23 ++++++++++++++++++- .../project_factory/examples/example.yaml | 7 ++++-- 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/modules/project-factory/README.md b/modules/project-factory/README.md index b64175908..2737c4c62 100644 --- a/modules/project-factory/README.md +++ b/modules/project-factory/README.md @@ -350,6 +350,9 @@ service_encryption_key_ids: services: - container.googleapis.com - storage.googleapis.com +iam_by_principals: + app-0-be: + - roles/storage.objectViewer service_accounts: app-0-be: display_name: "Backend instances." diff --git a/modules/project-factory/folders.tf b/modules/project-factory/folders.tf index a3e8b4aff..6f4710853 100644 --- a/modules/project-factory/folders.tf +++ b/modules/project-factory/folders.tf @@ -63,8 +63,13 @@ module "hierarchy-folder-lvl-1" { ) }) } - iam_by_principals = lookup(each.value, "iam_by_principals", {}) - org_policies = lookup(each.value, "org_policies", {}) + iam_by_principals = { + for k, v in lookup(each.value, "iam_by_principals", {}) : + lookup( + var.factories_config.context.iam_principals, k, k + ) => v + } + org_policies = lookup(each.value, "org_policies", {}) tag_bindings = { for k, v in lookup(each.value, "tag_bindings", {}) : k => lookup(var.factories_config.context.tag_values, v, v) diff --git a/modules/project-factory/main.tf b/modules/project-factory/main.tf index 1a90eb5dc..5bcf9a30f 100644 --- a/modules/project-factory/main.tf +++ b/modules/project-factory/main.tf @@ -186,7 +186,28 @@ module "projects-iam" { }) } # IAM by principals would trigger dynamic key errors so we don't interpolate - iam_by_principals = try(each.value.iam_by_principals, {}) + # iam_by_principals = try(each.value.iam_by_principals, {}) + iam_by_principals = { + for k, v in try(each.value.iam_by_principals, {}) : + try( + # project service accounts (sa) + module.service-accounts["${each.key}/${k}"].iam_email, + # automation service account (rw) + local.context.iam_principals["${each.key}/automation/${k}"], + # automation service account (automation/rw) + local.context.iam_principals["${each.key}/${k}"], + # other projects service accounts (project/sa) + module.service-accounts[k].iam_email, + # other automation service account (project/automation/rw) + local.context.iam_principals[k], + # passthrough + error handling using tonumber until Terraform gets fail/raise function + ( + strcontains(k, ":") + ? k + : tonumber("[Error] Invalid member: '${k}' in project '${each.key}'") + ) + ) => v + } # Shared VPC configuration is done at stage 2, to avoid dependency cycle between project service accounts and # IAM grants done for those service accounts factories_config = { diff --git a/tests/modules/project_factory/examples/example.yaml b/tests/modules/project_factory/examples/example.yaml index 8152997e0..2a0239101 100644 --- a/tests/modules/project_factory/examples/example.yaml +++ b/tests/modules/project_factory/examples/example.yaml @@ -525,7 +525,7 @@ counts: google_kms_crypto_key_iam_member: 1 google_monitoring_notification_channel: 1 google_project: 4 - google_project_iam_binding: 4 + google_project_iam_binding: 5 google_project_iam_member: 18 google_project_service: 12 google_project_service_identity: 4 @@ -534,7 +534,10 @@ counts: google_storage_bucket_iam_binding: 2 google_storage_project_service_account: 4 google_tags_tag_binding: 1 + google_tags_tag_key: 1 + google_tags_tag_value: 2 + google_tags_tag_value_iam_binding: 1 modules: 20 - resources: 74 + resources: 75 outputs: {}