From e23660cff60d64eb17f820d26b2c209489152658 Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Fri, 17 Mar 2023 17:24:55 +0100 Subject: [PATCH] Widen scope for prod project factory SA to dev (#1263) * restrict storage role on outputs bucket for stage SAs * grant prod project factory SA authority over prod and dev org policies * network stages delegated grants on dev to prod pf SA * security grants to prod pf SA on dev * tfdoc * tests --- fast/stages/1-resman/branch-data-platform.tf | 4 +-- fast/stages/1-resman/branch-gke.tf | 4 +-- fast/stages/1-resman/branch-networking.tf | 2 +- .../stages/1-resman/branch-project-factory.tf | 35 ++++++++++++------- fast/stages/1-resman/branch-sandbox.tf | 15 -------- fast/stages/1-resman/branch-security.tf | 2 +- fast/stages/1-resman/branch-teams.tf | 2 +- .../2-networking-a-peering/spoke-dev.tf | 2 ++ fast/stages/2-networking-b-vpn/spoke-dev.tf | 2 ++ fast/stages/2-networking-c-nva/spoke-dev.tf | 2 ++ .../2-networking-d-separate-envs/README.md | 6 ++-- .../2-networking-d-separate-envs/spoke-dev.tf | 6 +++- .../spoke-prod.tf | 2 ++ .../2-networking-d-separate-envs/variables.tf | 2 ++ fast/stages/2-security/core-dev.tf | 3 +- fast/stages/2-security/core-prod.tf | 4 +-- .../common.tfvars | 2 ++ 17 files changed, 54 insertions(+), 41 deletions(-) diff --git a/fast/stages/1-resman/branch-data-platform.tf b/fast/stages/1-resman/branch-data-platform.tf index 7a93e7a54b..48509b8ca2 100644 --- a/fast/stages/1-resman/branch-data-platform.tf +++ b/fast/stages/1-resman/branch-data-platform.tf @@ -89,7 +89,7 @@ module "branch-dp-dev-sa" { ]) } iam_storage_roles = { - (var.automation.outputs_bucket) = ["roles/storage.admin"] + (var.automation.outputs_bucket) = ["roles/storage.objectAdmin"] } } @@ -106,7 +106,7 @@ module "branch-dp-prod-sa" { ]) } iam_storage_roles = { - (var.automation.outputs_bucket) = ["roles/storage.admin"] + (var.automation.outputs_bucket) = ["roles/storage.objectAdmin"] } } diff --git a/fast/stages/1-resman/branch-gke.tf b/fast/stages/1-resman/branch-gke.tf index fe25a7beed..791305f22a 100644 --- a/fast/stages/1-resman/branch-gke.tf +++ b/fast/stages/1-resman/branch-gke.tf @@ -88,7 +88,7 @@ module "branch-gke-dev-sa" { ) } iam_storage_roles = { - (var.automation.outputs_bucket) = ["roles/storage.admin"] + (var.automation.outputs_bucket) = ["roles/storage.objectAdmin"] } } @@ -112,7 +112,7 @@ module "branch-gke-prod-sa" { ) } iam_storage_roles = { - (var.automation.outputs_bucket) = ["roles/storage.admin"] + (var.automation.outputs_bucket) = ["roles/storage.objectAdmin"] } } diff --git a/fast/stages/1-resman/branch-networking.tf b/fast/stages/1-resman/branch-networking.tf index 1fd7a6b3d9..fe457569ab 100644 --- a/fast/stages/1-resman/branch-networking.tf +++ b/fast/stages/1-resman/branch-networking.tf @@ -97,7 +97,7 @@ module "branch-network-sa" { ]) } iam_storage_roles = { - (var.automation.outputs_bucket) = ["roles/storage.admin"] + (var.automation.outputs_bucket) = ["roles/storage.objectAdmin"] } } diff --git a/fast/stages/1-resman/branch-project-factory.tf b/fast/stages/1-resman/branch-project-factory.tf index d74a8acb10..8ae9b4fed2 100644 --- a/fast/stages/1-resman/branch-project-factory.tf +++ b/fast/stages/1-resman/branch-project-factory.tf @@ -30,7 +30,7 @@ module "branch-pf-dev-sa" { ]) } iam_storage_roles = { - (var.automation.outputs_bucket) = ["roles/storage.admin"] + (var.automation.outputs_bucket) = ["roles/storage.objectAdmin"] } } @@ -48,7 +48,7 @@ module "branch-pf-prod-sa" { ]) } iam_storage_roles = { - (var.automation.outputs_bucket) = ["roles/storage.admin"] + (var.automation.outputs_bucket) = ["roles/storage.objectAdmin"] } } @@ -80,21 +80,32 @@ module "branch-pf-prod-gcs" { } } -resource "google_organization_iam_member" "org_policy_admin_pf" { - for_each = !var.fast_features.project_factory ? {} : { - pf-dev = ["teams", "development", module.branch-pf-dev-sa.0.iam_email] - pf-prod = ["teams", "production", module.branch-pf-prod-sa.0.iam_email] - } +resource "google_organization_iam_member" "org_policy_admin_pf_dev" { + count = var.fast_features.project_factory ? 1 : 0 org_id = var.organization.id role = "roles/orgpolicy.policyAdmin" - member = each.value.2 + member = module.branch-pf-dev-sa.0.iam_email condition { - title = "org_policy_tag_pf_scoped" - description = "Org policy tag scoped grant for ${each.value.0}/${each.value.1}." + title = "org_policy_tag_pf_scoped_dev" + description = "Org policy tag scoped grant for project factory dev." expression = <<-END - resource.matchTag('${var.organization.id}/${var.tag_names.context}', '${each.value.0}') + resource.matchTag('${var.organization.id}/${var.tag_names.context}', 'teams') && - resource.matchTag('${var.organization.id}/${var.tag_names.environment}', '${each.value.1}') + resource.matchTag('${var.organization.id}/${var.tag_names.environment}', 'development') + END + } +} + +resource "google_organization_iam_member" "org_policy_admin_pf_prod" { + count = var.fast_features.project_factory ? 1 : 0 + org_id = var.organization.id + role = "roles/orgpolicy.policyAdmin" + member = module.branch-pf-prod-sa.0.iam_email + condition { + title = "org_policy_tag_pf_scoped_prod" + description = "Org policy tag scoped grant for project factory prod." + expression = <<-END + resource.matchTag('${var.organization.id}/${var.tag_names.context}', 'teams') END } } diff --git a/fast/stages/1-resman/branch-sandbox.tf b/fast/stages/1-resman/branch-sandbox.tf index 72221bc0d1..33eae4f001 100644 --- a/fast/stages/1-resman/branch-sandbox.tf +++ b/fast/stages/1-resman/branch-sandbox.tf @@ -16,11 +16,6 @@ # tfdoc:file:description Sandbox stage resources. -moved { - from = module.branch-sandbox-folder - to = module.branch-sandbox-folder.0 -} - module "branch-sandbox-folder" { source = "../../../modules/folder" count = var.fast_features.sandbox ? 1 : 0 @@ -43,11 +38,6 @@ module "branch-sandbox-folder" { } } -moved { - from = module.branch-sandbox-gcs - to = module.branch-sandbox-gcs.0 -} - module "branch-sandbox-gcs" { source = "../../../modules/gcs" count = var.fast_features.sandbox ? 1 : 0 @@ -62,11 +52,6 @@ module "branch-sandbox-gcs" { } } -moved { - from = module.branch-sandbox-sa - to = module.branch-sandbox-sa.0 -} - module "branch-sandbox-sa" { source = "../../../modules/iam-service-account" count = var.fast_features.sandbox ? 1 : 0 diff --git a/fast/stages/1-resman/branch-security.tf b/fast/stages/1-resman/branch-security.tf index 4b0c0fb131..8e638a1a3b 100644 --- a/fast/stages/1-resman/branch-security.tf +++ b/fast/stages/1-resman/branch-security.tf @@ -60,7 +60,7 @@ module "branch-security-sa" { ]) } iam_storage_roles = { - (var.automation.outputs_bucket) = ["roles/storage.admin"] + (var.automation.outputs_bucket) = ["roles/storage.objectAdmin"] } } diff --git a/fast/stages/1-resman/branch-teams.tf b/fast/stages/1-resman/branch-teams.tf index 8b0e89b3aa..4996f18383 100644 --- a/fast/stages/1-resman/branch-teams.tf +++ b/fast/stages/1-resman/branch-teams.tf @@ -47,7 +47,7 @@ module "branch-teams-sa" { display_name = "Terraform resman teams service account." prefix = var.prefix iam_storage_roles = { - (var.automation.outputs_bucket) = ["roles/storage.admin"] + (var.automation.outputs_bucket) = ["roles/storage.objectAdmin"] } } diff --git a/fast/stages/2-networking-a-peering/spoke-dev.tf b/fast/stages/2-networking-a-peering/spoke-dev.tf index 17b4a87a08..15a8e47771 100644 --- a/fast/stages/2-networking-a-peering/spoke-dev.tf +++ b/fast/stages/2-networking-a-peering/spoke-dev.tf @@ -39,6 +39,7 @@ module "dev-spoke-project" { "roles/dns.admin" = compact([ try(local.service_accounts.gke-dev, null), try(local.service_accounts.project-factory-dev, null), + try(local.service_accounts.project-factory-prod, null), ]) } } @@ -97,6 +98,7 @@ resource "google_project_iam_binding" "dev_spoke_project_iam_delegated" { members = compact([ try(local.service_accounts.data-platform-dev, null), try(local.service_accounts.project-factory-dev, null), + try(local.service_accounts.project-factory-prod, null), try(local.service_accounts.gke-dev, null), ]) condition { diff --git a/fast/stages/2-networking-b-vpn/spoke-dev.tf b/fast/stages/2-networking-b-vpn/spoke-dev.tf index 17b4a87a08..15a8e47771 100644 --- a/fast/stages/2-networking-b-vpn/spoke-dev.tf +++ b/fast/stages/2-networking-b-vpn/spoke-dev.tf @@ -39,6 +39,7 @@ module "dev-spoke-project" { "roles/dns.admin" = compact([ try(local.service_accounts.gke-dev, null), try(local.service_accounts.project-factory-dev, null), + try(local.service_accounts.project-factory-prod, null), ]) } } @@ -97,6 +98,7 @@ resource "google_project_iam_binding" "dev_spoke_project_iam_delegated" { members = compact([ try(local.service_accounts.data-platform-dev, null), try(local.service_accounts.project-factory-dev, null), + try(local.service_accounts.project-factory-prod, null), try(local.service_accounts.gke-dev, null), ]) condition { diff --git a/fast/stages/2-networking-c-nva/spoke-dev.tf b/fast/stages/2-networking-c-nva/spoke-dev.tf index f7866783cb..cc2c1a4f0b 100644 --- a/fast/stages/2-networking-c-nva/spoke-dev.tf +++ b/fast/stages/2-networking-c-nva/spoke-dev.tf @@ -38,6 +38,7 @@ module "dev-spoke-project" { "roles/dns.admin" = compact([ try(local.service_accounts.gke-dev, null), try(local.service_accounts.project-factory-dev, null), + try(local.service_accounts.project-factory-prod, null), ]) } } @@ -122,6 +123,7 @@ resource "google_project_iam_binding" "dev_spoke_project_iam_delegated" { members = compact([ try(local.service_accounts.data-platform-dev, null), try(local.service_accounts.project-factory-dev, null), + try(local.service_accounts.project-factory-prod, null), try(local.service_accounts.gke-dev, null), ]) condition { diff --git a/fast/stages/2-networking-d-separate-envs/README.md b/fast/stages/2-networking-d-separate-envs/README.md index 55d84fe736..9890c865f9 100644 --- a/fast/stages/2-networking-d-separate-envs/README.md +++ b/fast/stages/2-networking-d-separate-envs/README.md @@ -356,9 +356,9 @@ Regions are defined via the `regions` variable which sets up a mapping between t | [outputs_location](variables.tf#L96) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string | | null | | | [psa_ranges](variables.tf#L113) | IP ranges used for Private Service Access (e.g. CloudSQL). | object({…}) | | null | | | [regions](variables.tf#L134) | Region definitions. | object({…}) | | {…} | | -| [service_accounts](variables.tf#L144) | Automation service accounts in name => email format. | object({…}) | | null | 1-resman | -| [vpn_onprem_dev_primary_config](variables.tf#L156) | VPN gateway configuration for onprem interconnection from dev in the primary region. | object({…}) | | null | | -| [vpn_onprem_prod_primary_config](variables.tf#L199) | VPN gateway configuration for onprem interconnection from prod in the primary region. | object({…}) | | null | | +| [service_accounts](variables.tf#L144) | Automation service accounts in name => email format. | object({…}) | | null | 1-resman | +| [vpn_onprem_dev_primary_config](variables.tf#L158) | VPN gateway configuration for onprem interconnection from dev in the primary region. | object({…}) | | null | | +| [vpn_onprem_prod_primary_config](variables.tf#L201) | VPN gateway configuration for onprem interconnection from prod in the primary region. | object({…}) | | null | | ## Outputs diff --git a/fast/stages/2-networking-d-separate-envs/spoke-dev.tf b/fast/stages/2-networking-d-separate-envs/spoke-dev.tf index de52b42834..f51a4e2be1 100644 --- a/fast/stages/2-networking-d-separate-envs/spoke-dev.tf +++ b/fast/stages/2-networking-d-separate-envs/spoke-dev.tf @@ -37,7 +37,9 @@ module "dev-spoke-project" { } iam = { "roles/dns.admin" = compact([ - try(local.service_accounts.project-factory-dev, null) + try(local.service_accounts.gke-dev, null), + try(local.service_accounts.project-factory-dev, null), + try(local.service_accounts.project-factory-prod, null), ]) } } @@ -95,7 +97,9 @@ resource "google_project_iam_binding" "dev_spoke_project_iam_delegated" { role = "roles/resourcemanager.projectIamAdmin" members = compact([ try(local.service_accounts.data-platform-dev, null), + try(local.service_accounts.gke-dev, null), try(local.service_accounts.project-factory-dev, null), + try(local.service_accounts.project-factory-prod, null), ]) condition { title = "dev_stage3_sa_delegated_grants" diff --git a/fast/stages/2-networking-d-separate-envs/spoke-prod.tf b/fast/stages/2-networking-d-separate-envs/spoke-prod.tf index 1321b2c141..7894452678 100644 --- a/fast/stages/2-networking-d-separate-envs/spoke-prod.tf +++ b/fast/stages/2-networking-d-separate-envs/spoke-prod.tf @@ -37,6 +37,7 @@ module "prod-spoke-project" { } iam = { "roles/dns.admin" = compact([ + try(local.service_accounts.gke-prod, null), try(local.service_accounts.project-factory-prod, null) ]) } @@ -95,6 +96,7 @@ resource "google_project_iam_binding" "prod_spoke_project_iam_delegated" { role = "roles/resourcemanager.projectIamAdmin" members = compact([ try(local.service_accounts.data-platform-prod, null), + try(local.service_accounts.gke-platform-prod, null), try(local.service_accounts.project-factory-prod, null), ]) condition { diff --git a/fast/stages/2-networking-d-separate-envs/variables.tf b/fast/stages/2-networking-d-separate-envs/variables.tf index 4a3e8364e0..a8920c533e 100644 --- a/fast/stages/2-networking-d-separate-envs/variables.tf +++ b/fast/stages/2-networking-d-separate-envs/variables.tf @@ -147,6 +147,8 @@ variable "service_accounts" { type = object({ data-platform-dev = string data-platform-prod = string + gke-dev = string + gke-prod = string project-factory-dev = string project-factory-prod = string }) diff --git a/fast/stages/2-security/core-dev.tf b/fast/stages/2-security/core-dev.tf index c6b9ba01bf..856047b067 100644 --- a/fast/stages/2-security/core-dev.tf +++ b/fast/stages/2-security/core-dev.tf @@ -17,8 +17,9 @@ locals { dev_kms_restricted_admins = [ for sa in compact([ + var.service_accounts.data-platform-dev, var.service_accounts.project-factory-dev, - var.service_accounts.data-platform-dev + var.service_accounts.project-factory-prod ]) : "serviceAccount:${sa}" ] } diff --git a/fast/stages/2-security/core-prod.tf b/fast/stages/2-security/core-prod.tf index b21547607a..ecbce18f1f 100644 --- a/fast/stages/2-security/core-prod.tf +++ b/fast/stages/2-security/core-prod.tf @@ -17,8 +17,8 @@ locals { prod_kms_restricted_admins = [ for sa in compact([ - var.service_accounts.project-factory-prod, - var.service_accounts.data-platform-prod + var.service_accounts.data-platform-prod, + var.service_accounts.project-factory-prod ]) : "serviceAccount:${sa}" ] } diff --git a/tests/fast/stages/s2_networking_d_separate_envs/common.tfvars b/tests/fast/stages/s2_networking_d_separate_envs/common.tfvars index f6b6b7f88d..bc9f5eadfe 100644 --- a/tests/fast/stages/s2_networking_d_separate_envs/common.tfvars +++ b/tests/fast/stages/s2_networking_d_separate_envs/common.tfvars @@ -16,6 +16,8 @@ folder_ids = { service_accounts = { data-platform-dev = "string" data-platform-prod = "string" + gke-dev = "string" + gke-prod = "string" project-factory-dev = "string" project-factory-prod = "string" }