From e7e188818a633c1b6a47ec318eb3513b50b7437a Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Wed, 18 Oct 2023 14:18:31 +0200 Subject: [PATCH] Add service usage consumer role to IaC SAs, refactor delegated grants in FAST (#1773) * add serviceusage role to iac sas, refactor delegated grants * fix test * tfdoc --- fast/stages/0-bootstrap/IAM.md | 22 +++---- fast/stages/0-bootstrap/automation.tf | 20 ++++++ fast/stages/1-resman/IAM.md | 65 ++++++++++++++----- fast/stages/1-resman/branch-data-platform.tf | 3 + fast/stages/1-resman/branch-gke.tf | 6 ++ fast/stages/1-resman/branch-networking.tf | 3 + .../stages/1-resman/branch-project-factory.tf | 6 ++ fast/stages/1-resman/branch-sandbox.tf | 3 + fast/stages/1-resman/branch-security.tf | 4 +- fast/stages/1-resman/branch-teams.tf | 5 ++ fast/stages/1-resman/branch-tenants.tf | 3 + fast/stages/2-networking-a-peering/README.md | 4 +- .../2-networking-a-peering/spoke-dev.tf | 40 ++++++------ .../2-networking-a-peering/spoke-prod.tf | 38 +++++------ fast/stages/2-networking-b-vpn/README.md | 4 +- fast/stages/2-networking-b-vpn/spoke-dev.tf | 40 ++++++------ fast/stages/2-networking-b-vpn/spoke-prod.tf | 38 +++++------ fast/stages/2-networking-c-nva/README.md | 4 +- fast/stages/2-networking-c-nva/spoke-dev.tf | 40 ++++++------ fast/stages/2-networking-c-nva/spoke-prod.tf | 38 +++++------ .../2-networking-d-separate-envs/README.md | 4 +- .../2-networking-d-separate-envs/spoke-dev.tf | 40 ++++++------ .../spoke-prod.tf | 38 +++++------ fast/stages/2-networking-e-nva-bgp/README.md | 4 +- .../2-networking-e-nva-bgp/spoke-dev.tf | 40 ++++++------ .../2-networking-e-nva-bgp/spoke-prod.tf | 38 +++++------ tests/fast/stages/s0_bootstrap/simple.yaml | 4 +- 27 files changed, 316 insertions(+), 238 deletions(-) diff --git a/fast/stages/0-bootstrap/IAM.md b/fast/stages/0-bootstrap/IAM.md index b938c44f..b2d6d277 100644 --- a/fast/stages/0-bootstrap/IAM.md +++ b/fast/stages/0-bootstrap/IAM.md @@ -7,24 +7,24 @@ Legend: + additive, conditional. | members | roles | |---|---| |GCP organization domain
domain|[roles/browser](https://cloud.google.com/iam/docs/understanding-roles#browser) | -|gcp-billing-admins
group|[roles/billing.admin](https://cloud.google.com/iam/docs/understanding-roles#billing.admin) +
[roles/billing.costsManager](https://cloud.google.com/iam/docs/understanding-roles#billing.costsManager) +| +|cloud-gong-hierarchy_management-hm_tool-latchkey-presubmits
group|[roles/browser](https://cloud.google.com/iam/docs/understanding-roles#browser) | |gcp-devops
group|[roles/cloudsupport.techSupportEditor](https://cloud.google.com/iam/docs/understanding-roles#cloudsupport.techSupportEditor)
[roles/logging.viewer](https://cloud.google.com/iam/docs/understanding-roles#logging.viewer)
[roles/monitoring.viewer](https://cloud.google.com/iam/docs/understanding-roles#monitoring.viewer) | |gcp-network-admins
group|[roles/cloudasset.owner](https://cloud.google.com/iam/docs/understanding-roles#cloudasset.owner)
[roles/cloudsupport.techSupportEditor](https://cloud.google.com/iam/docs/understanding-roles#cloudsupport.techSupportEditor)
[roles/compute.orgFirewallPolicyAdmin](https://cloud.google.com/iam/docs/understanding-roles#compute.orgFirewallPolicyAdmin) +
[roles/compute.xpnAdmin](https://cloud.google.com/iam/docs/understanding-roles#compute.xpnAdmin) +| -|gcp-organization-admins
group|[roles/cloudasset.owner](https://cloud.google.com/iam/docs/understanding-roles#cloudasset.owner)
[roles/cloudsupport.admin](https://cloud.google.com/iam/docs/understanding-roles#cloudsupport.admin)
[roles/compute.osAdminLogin](https://cloud.google.com/iam/docs/understanding-roles#compute.osAdminLogin)
[roles/compute.osLoginExternalUser](https://cloud.google.com/iam/docs/understanding-roles#compute.osLoginExternalUser)
[roles/owner](https://cloud.google.com/iam/docs/understanding-roles#owner)
[roles/resourcemanager.folderAdmin](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.folderAdmin)
[roles/resourcemanager.organizationAdmin](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.organizationAdmin)
[roles/resourcemanager.projectCreator](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.projectCreator)
[roles/billing.admin](https://cloud.google.com/iam/docs/understanding-roles#billing.admin) +
[roles/billing.costsManager](https://cloud.google.com/iam/docs/understanding-roles#billing.costsManager) +
[roles/orgpolicy.policyAdmin](https://cloud.google.com/iam/docs/understanding-roles#orgpolicy.policyAdmin) +| +|gcp-organization-admins
group|[roles/cloudasset.owner](https://cloud.google.com/iam/docs/understanding-roles#cloudasset.owner)
[roles/cloudsupport.admin](https://cloud.google.com/iam/docs/understanding-roles#cloudsupport.admin)
[roles/compute.osAdminLogin](https://cloud.google.com/iam/docs/understanding-roles#compute.osAdminLogin)
[roles/compute.osLoginExternalUser](https://cloud.google.com/iam/docs/understanding-roles#compute.osLoginExternalUser)
[roles/owner](https://cloud.google.com/iam/docs/understanding-roles#owner)
[roles/resourcemanager.folderAdmin](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.folderAdmin)
[roles/resourcemanager.organizationAdmin](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.organizationAdmin)
[roles/resourcemanager.projectCreator](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.projectCreator)
[roles/resourcemanager.tagAdmin](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.tagAdmin)
[roles/orgpolicy.policyAdmin](https://cloud.google.com/iam/docs/understanding-roles#orgpolicy.policyAdmin) +
[roles/compute.xpnAdmin](https://cloud.google.com/iam/docs/understanding-roles#compute.xpnAdmin) +| |gcp-security-admins
group|[roles/cloudasset.owner](https://cloud.google.com/iam/docs/understanding-roles#cloudasset.owner)
[roles/cloudsupport.techSupportEditor](https://cloud.google.com/iam/docs/understanding-roles#cloudsupport.techSupportEditor)
[roles/iam.securityReviewer](https://cloud.google.com/iam/docs/understanding-roles#iam.securityReviewer)
[roles/logging.admin](https://cloud.google.com/iam/docs/understanding-roles#logging.admin)
[roles/securitycenter.admin](https://cloud.google.com/iam/docs/understanding-roles#securitycenter.admin)
[roles/accesscontextmanager.policyAdmin](https://cloud.google.com/iam/docs/understanding-roles#accesscontextmanager.policyAdmin) +
[roles/iam.organizationRoleAdmin](https://cloud.google.com/iam/docs/understanding-roles#iam.organizationRoleAdmin) +
[roles/orgpolicy.policyAdmin](https://cloud.google.com/iam/docs/understanding-roles#orgpolicy.policyAdmin) +| -|prod-bootstrap-0
serviceAccount|[roles/logging.admin](https://cloud.google.com/iam/docs/understanding-roles#logging.admin)
[roles/resourcemanager.organizationAdmin](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.organizationAdmin)
[roles/resourcemanager.projectCreator](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.projectCreator)
[roles/resourcemanager.projectMover](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.projectMover)
[roles/billing.admin](https://cloud.google.com/iam/docs/understanding-roles#billing.admin) +
[roles/billing.costsManager](https://cloud.google.com/iam/docs/understanding-roles#billing.costsManager) +
[roles/iam.organizationRoleAdmin](https://cloud.google.com/iam/docs/understanding-roles#iam.organizationRoleAdmin) +| -|prod-resman-0
serviceAccount|organizations/[org_id #0]/roles/organizationIamAdmin
[roles/resourcemanager.folderAdmin](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.folderAdmin)
[roles/resourcemanager.tagAdmin](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.tagAdmin)
[roles/resourcemanager.tagUser](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.tagUser)
[roles/billing.admin](https://cloud.google.com/iam/docs/understanding-roles#billing.admin) +
[roles/billing.costsManager](https://cloud.google.com/iam/docs/understanding-roles#billing.costsManager) +
[roles/orgpolicy.policyAdmin](https://cloud.google.com/iam/docs/understanding-roles#orgpolicy.policyAdmin) +| +|latchkey-multiorg-ephemeral-custom-automation
serviceAccount|[roles/iam.organizationRoleAdmin](https://cloud.google.com/iam/docs/understanding-roles#iam.organizationRoleAdmin) +| +|latchkey-multiorg-ephemeral-iam-automation
serviceAccount|[roles/resourcemanager.organizationAdmin](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.organizationAdmin) | +|latchkey-multiorg-ephemeral-organization-automation
serviceAccount|[roles/browser](https://cloud.google.com/iam/docs/understanding-roles#browser) | +|prod-bootstrap-0
serviceAccount|[roles/logging.admin](https://cloud.google.com/iam/docs/understanding-roles#logging.admin)
[roles/resourcemanager.organizationAdmin](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.organizationAdmin)
[roles/resourcemanager.projectCreator](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.projectCreator)
[roles/resourcemanager.projectMover](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.projectMover)
[roles/resourcemanager.tagAdmin](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.tagAdmin)
[roles/iam.organizationRoleAdmin](https://cloud.google.com/iam/docs/understanding-roles#iam.organizationRoleAdmin) +
[roles/orgpolicy.policyAdmin](https://cloud.google.com/iam/docs/understanding-roles#orgpolicy.policyAdmin) +| +|prod-resman-0
serviceAccount|[roles/logging.admin](https://cloud.google.com/iam/docs/understanding-roles#logging.admin)
[roles/resourcemanager.folderAdmin](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.folderAdmin)
[roles/resourcemanager.projectCreator](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.projectCreator)
[roles/resourcemanager.tagAdmin](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.tagAdmin)
[roles/resourcemanager.tagUser](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.tagUser)
organizations/[org_id #0]/roles/organizationIamAdmin
[roles/orgpolicy.policyAdmin](https://cloud.google.com/iam/docs/understanding-roles#orgpolicy.policyAdmin) +| +|tf-cf-quota-monitor
serviceAccount|[roles/compute.viewer](https://cloud.google.com/iam/docs/understanding-roles#compute.viewer) | ## Project prod-audit-logs-0 | members | roles | |---|---| -|prod-bootstrap-0
serviceAccount|[roles/owner](https://cloud.google.com/iam/docs/understanding-roles#owner) | - -## Project prod-billing-exp-0 - -| members | roles | -|---|---| +|o366118655033-148933
serviceAccount|[roles/logging.bucketWriter](https://cloud.google.com/iam/docs/understanding-roles#logging.bucketWriter) +| +|o366118655033-468879
serviceAccount|[roles/logging.bucketWriter](https://cloud.google.com/iam/docs/understanding-roles#logging.bucketWriter) +| |prod-bootstrap-0
serviceAccount|[roles/owner](https://cloud.google.com/iam/docs/understanding-roles#owner) | ## Project prod-iac-core-0 @@ -36,5 +36,5 @@ Legend: + additive, conditional. |SERVICE_IDENTITY_service-networking
serviceAccount|[roles/servicenetworking.serviceAgent](https://cloud.google.com/iam/docs/understanding-roles#servicenetworking.serviceAgent) +| |prod-bootstrap-0
serviceAccount|[roles/owner](https://cloud.google.com/iam/docs/understanding-roles#owner) | |prod-bootstrap-1
serviceAccount|[roles/logging.logWriter](https://cloud.google.com/iam/docs/understanding-roles#logging.logWriter) +| -|prod-resman-0
serviceAccount|[roles/cloudbuild.builds.editor](https://cloud.google.com/iam/docs/understanding-roles#cloudbuild.builds.editor)
[roles/iam.serviceAccountAdmin](https://cloud.google.com/iam/docs/understanding-roles#iam.serviceAccountAdmin)
[roles/iam.workloadIdentityPoolAdmin](https://cloud.google.com/iam/docs/understanding-roles#iam.workloadIdentityPoolAdmin)
[roles/source.admin](https://cloud.google.com/iam/docs/understanding-roles#source.admin)
[roles/storage.admin](https://cloud.google.com/iam/docs/understanding-roles#storage.admin) | +|prod-resman-0
serviceAccount|[roles/cloudbuild.builds.editor](https://cloud.google.com/iam/docs/understanding-roles#cloudbuild.builds.editor)
[roles/iam.serviceAccountAdmin](https://cloud.google.com/iam/docs/understanding-roles#iam.serviceAccountAdmin)
[roles/iam.workloadIdentityPoolAdmin](https://cloud.google.com/iam/docs/understanding-roles#iam.workloadIdentityPoolAdmin)
[roles/source.admin](https://cloud.google.com/iam/docs/understanding-roles#source.admin)
[roles/storage.admin](https://cloud.google.com/iam/docs/understanding-roles#storage.admin)
[roles/resourcemanager.projectIamAdmin](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.projectIamAdmin)
[roles/serviceusage.serviceUsageConsumer](https://cloud.google.com/iam/docs/understanding-roles#serviceusage.serviceUsageConsumer) +| |prod-resman-1
serviceAccount|[roles/logging.logWriter](https://cloud.google.com/iam/docs/understanding-roles#logging.logWriter) +| diff --git a/fast/stages/0-bootstrap/automation.tf b/fast/stages/0-bootstrap/automation.tf index d74e9efb..55ec5619 100644 --- a/fast/stages/0-bootstrap/automation.tf +++ b/fast/stages/0-bootstrap/automation.tf @@ -60,6 +60,26 @@ module "automation-project" { module.automation-tf-resman-sa.iam_email ] } + iam_bindings = { + delegated_grants_resman = { + members = [module.automation-tf-resman-sa.iam_email] + role = "roles/resourcemanager.projectIamAdmin" + condition = { + title = "resman_delegated_grant" + description = "Resource manager service account delegated grant." + expression = format( + "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly(['%s'])", + "roles/serviceusage.serviceUsageConsumer" + ) + } + } + } + iam_bindings_additive = { + serviceusage_resman = { + member = module.automation-tf-resman-sa.iam_email + role = "roles/serviceusage.serviceUsageConsumer" + } + } services = [ "accesscontextmanager.googleapis.com", "bigquery.googleapis.com", diff --git a/fast/stages/1-resman/IAM.md b/fast/stages/1-resman/IAM.md index 403bd96c..fd94019c 100644 --- a/fast/stages/1-resman/IAM.md +++ b/fast/stages/1-resman/IAM.md @@ -6,14 +6,11 @@ Legend: + additive, conditional. | members | roles | |---|---| -|dev-resman-dp-0
serviceAccount|[roles/orgpolicy.policyAdmin](https://cloud.google.com/iam/docs/understanding-roles#orgpolicy.policyAdmin) +
[roles/billing.user](https://cloud.google.com/iam/docs/understanding-roles#billing.user) +| -|dev-resman-gke-0
serviceAccount|[roles/billing.user](https://cloud.google.com/iam/docs/understanding-roles#billing.user) +| -|dev-resman-pf-0
serviceAccount|[roles/orgpolicy.policyAdmin](https://cloud.google.com/iam/docs/understanding-roles#orgpolicy.policyAdmin) +
[roles/billing.costsManager](https://cloud.google.com/iam/docs/understanding-roles#billing.costsManager) +
[roles/billing.user](https://cloud.google.com/iam/docs/understanding-roles#billing.user) +| -|prod-resman-dp-0
serviceAccount|[roles/orgpolicy.policyAdmin](https://cloud.google.com/iam/docs/understanding-roles#orgpolicy.policyAdmin) +
[roles/billing.user](https://cloud.google.com/iam/docs/understanding-roles#billing.user) +| -|prod-resman-gke-0
serviceAccount|[roles/billing.user](https://cloud.google.com/iam/docs/understanding-roles#billing.user) +| -|prod-resman-net-0
serviceAccount|[roles/billing.user](https://cloud.google.com/iam/docs/understanding-roles#billing.user) +
[roles/compute.orgFirewallPolicyAdmin](https://cloud.google.com/iam/docs/understanding-roles#compute.orgFirewallPolicyAdmin) +
[roles/compute.xpnAdmin](https://cloud.google.com/iam/docs/understanding-roles#compute.xpnAdmin) +| -|prod-resman-pf-0
serviceAccount|[roles/orgpolicy.policyAdmin](https://cloud.google.com/iam/docs/understanding-roles#orgpolicy.policyAdmin) +
[roles/billing.costsManager](https://cloud.google.com/iam/docs/understanding-roles#billing.costsManager) +
[roles/billing.user](https://cloud.google.com/iam/docs/understanding-roles#billing.user) +| -|prod-resman-sec-0
serviceAccount|[roles/accesscontextmanager.policyAdmin](https://cloud.google.com/iam/docs/understanding-roles#accesscontextmanager.policyAdmin) +
[roles/billing.user](https://cloud.google.com/iam/docs/understanding-roles#billing.user) +| +|egov-test-0
group|[roles/resourcemanager.organizationViewer](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.organizationViewer) +| +|dev-resman-pf-0
serviceAccount|[roles/orgpolicy.policyAdmin](https://cloud.google.com/iam/docs/understanding-roles#orgpolicy.policyAdmin) +| +|prod-resman-net-0
serviceAccount|[roles/compute.orgFirewallPolicyAdmin](https://cloud.google.com/iam/docs/understanding-roles#compute.orgFirewallPolicyAdmin) +
[roles/compute.xpnAdmin](https://cloud.google.com/iam/docs/understanding-roles#compute.xpnAdmin) +| +|prod-resman-pf-0
serviceAccount|[roles/orgpolicy.policyAdmin](https://cloud.google.com/iam/docs/understanding-roles#orgpolicy.policyAdmin) +| +|security-0
serviceAccount|[roles/accesscontextmanager.policyAdmin](https://cloud.google.com/iam/docs/understanding-roles#accesscontextmanager.policyAdmin) +| ## Folder development [#0] @@ -41,6 +38,29 @@ Legend: + additive, conditional. |---|---| |dev-resman-pf-0
serviceAccount|organizations/[org_id #0]/roles/serviceProjectNetworkAdmin
[roles/logging.admin](https://cloud.google.com/iam/docs/understanding-roles#logging.admin)
[roles/owner](https://cloud.google.com/iam/docs/understanding-roles#owner)
[roles/resourcemanager.folderAdmin](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.folderAdmin)
[roles/resourcemanager.projectCreator](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.projectCreator) | +## Folder egov test 0 - core [#1] + +| members | roles | +|---|---| +|egov-test-0
group|organizations/[org_id #0]/roles/tenantLoadBalancerAdmin
[roles/compute.instanceAdmin.v1](https://cloud.google.com/iam/docs/understanding-roles#compute.instanceAdmin.v1)
[roles/viewer](https://cloud.google.com/iam/docs/understanding-roles#viewer) | +|egov-t0-iac-0
serviceAccount|organizations/[org_id #0]/roles/tenantLoadBalancerAdmin
[roles/compute.instanceAdmin.v1](https://cloud.google.com/iam/docs/understanding-roles#compute.instanceAdmin.v1)
[roles/viewer](https://cloud.google.com/iam/docs/understanding-roles#viewer) | +|tn-egov-t0-0
serviceAccount|[roles/owner](https://cloud.google.com/iam/docs/understanding-roles#owner) | + +## Folder egov test 0 - tenant [#1] + +| members | roles | +|---|---| +|egov-test-0
group|[roles/cloudasset.owner](https://cloud.google.com/iam/docs/understanding-roles#cloudasset.owner)
[roles/compute.xpnAdmin](https://cloud.google.com/iam/docs/understanding-roles#compute.xpnAdmin)
[roles/owner](https://cloud.google.com/iam/docs/understanding-roles#owner)
[roles/resourcemanager.folderAdmin](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.folderAdmin)
[roles/resourcemanager.projectCreator](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.projectCreator)
[roles/resourcemanager.tagUser](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.tagUser) | +|egov-t0-iac-0
serviceAccount|[roles/cloudasset.owner](https://cloud.google.com/iam/docs/understanding-roles#cloudasset.owner)
[roles/compute.xpnAdmin](https://cloud.google.com/iam/docs/understanding-roles#compute.xpnAdmin)
[roles/owner](https://cloud.google.com/iam/docs/understanding-roles#owner)
[roles/resourcemanager.folderAdmin](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.folderAdmin)
[roles/resourcemanager.projectCreator](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.projectCreator)
[roles/resourcemanager.tagUser](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.tagUser) | + +## Folder egov test 0 [#1] + +| members | roles | +|---|---| +|egov-test-0
group|[roles/logging.admin](https://cloud.google.com/iam/docs/understanding-roles#logging.admin)
[roles/monitoring.admin](https://cloud.google.com/iam/docs/understanding-roles#monitoring.admin)
[roles/resourcemanager.folderViewer](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.folderViewer)
[roles/browser](https://cloud.google.com/iam/docs/understanding-roles#browser) | +|egov-t0-iac-0
serviceAccount|[roles/logging.admin](https://cloud.google.com/iam/docs/understanding-roles#logging.admin)
[roles/monitoring.admin](https://cloud.google.com/iam/docs/understanding-roles#monitoring.admin)
[roles/resourcemanager.folderViewer](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.folderViewer) | +|tn-egov-t0-0
serviceAccount|[roles/cloudasset.owner](https://cloud.google.com/iam/docs/understanding-roles#cloudasset.owner)
[roles/compute.xpnAdmin](https://cloud.google.com/iam/docs/understanding-roles#compute.xpnAdmin)
[roles/resourcemanager.folderAdmin](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.folderAdmin)
[roles/resourcemanager.projectCreator](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.projectCreator)
[roles/resourcemanager.tagUser](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.tagUser) | + ## Folder networking | members | roles | @@ -85,7 +105,13 @@ Legend: + additive, conditional. | members | roles | |---|---| |gcp-security-admins
group|[roles/viewer](https://cloud.google.com/iam/docs/understanding-roles#viewer) | -|prod-resman-sec-0
serviceAccount|[roles/logging.admin](https://cloud.google.com/iam/docs/understanding-roles#logging.admin)
[roles/owner](https://cloud.google.com/iam/docs/understanding-roles#owner)
[roles/resourcemanager.folderAdmin](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.folderAdmin)
[roles/resourcemanager.projectCreator](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.projectCreator) | +|security-0
serviceAccount|[roles/logging.admin](https://cloud.google.com/iam/docs/understanding-roles#logging.admin)
[roles/owner](https://cloud.google.com/iam/docs/understanding-roles#owner)
[roles/resourcemanager.folderAdmin](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.folderAdmin)
[roles/resourcemanager.projectCreator](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.projectCreator) | + +## Folder team 0 + +| members | roles | +|---|---| +|prod-teams-team-0-0
serviceAccount|[roles/compute.xpnAdmin](https://cloud.google.com/iam/docs/understanding-roles#compute.xpnAdmin)
[roles/logging.admin](https://cloud.google.com/iam/docs/understanding-roles#logging.admin)
[roles/owner](https://cloud.google.com/iam/docs/understanding-roles#owner)
[roles/resourcemanager.folderAdmin](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.folderAdmin)
[roles/resourcemanager.projectCreator](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.projectCreator) | ## Folder teams @@ -93,21 +119,26 @@ Legend: + additive, conditional. |---|---| |prod-resman-teams-0
serviceAccount|[roles/compute.xpnAdmin](https://cloud.google.com/iam/docs/understanding-roles#compute.xpnAdmin)
[roles/logging.admin](https://cloud.google.com/iam/docs/understanding-roles#logging.admin)
[roles/owner](https://cloud.google.com/iam/docs/understanding-roles#owner)
[roles/resourcemanager.folderAdmin](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.folderAdmin)
[roles/resourcemanager.projectCreator](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.projectCreator) | -## Folder teams test +## Project egov-t0-iac-core-0 | members | roles | |---|---| -|prod-teams-teams-test-0
serviceAccount|[roles/compute.xpnAdmin](https://cloud.google.com/iam/docs/understanding-roles#compute.xpnAdmin)
[roles/logging.admin](https://cloud.google.com/iam/docs/understanding-roles#logging.admin)
[roles/owner](https://cloud.google.com/iam/docs/understanding-roles#owner)
[roles/resourcemanager.folderAdmin](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.folderAdmin)
[roles/resourcemanager.projectCreator](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.projectCreator) | +|egov-test-0
group|[roles/iam.serviceAccountAdmin](https://cloud.google.com/iam/docs/understanding-roles#iam.serviceAccountAdmin)
[roles/iam.serviceAccountTokenCreator](https://cloud.google.com/iam/docs/understanding-roles#iam.serviceAccountTokenCreator)
[roles/iam.workloadIdentityPoolAdmin](https://cloud.google.com/iam/docs/understanding-roles#iam.workloadIdentityPoolAdmin) | +|SERVICE_IDENTITY_service-networking
serviceAccount|[roles/servicenetworking.serviceAgent](https://cloud.google.com/iam/docs/understanding-roles#servicenetworking.serviceAgent) +| ## Project prod-iac-core-0 | members | roles | |---|---| -|dev-pf-resman-pf-1
serviceAccount|[roles/logging.logWriter](https://cloud.google.com/iam/docs/understanding-roles#logging.logWriter) +| -|dev-resman-dp-1
serviceAccount|[roles/logging.logWriter](https://cloud.google.com/iam/docs/understanding-roles#logging.logWriter) +| -|dev-resman-gke-1
serviceAccount|[roles/logging.logWriter](https://cloud.google.com/iam/docs/understanding-roles#logging.logWriter) +| -|prod-pf-resman-pf-1
serviceAccount|[roles/logging.logWriter](https://cloud.google.com/iam/docs/understanding-roles#logging.logWriter) +| -|prod-resman-dp-1
serviceAccount|[roles/logging.logWriter](https://cloud.google.com/iam/docs/understanding-roles#logging.logWriter) +| -|prod-resman-gke-1
serviceAccount|[roles/logging.logWriter](https://cloud.google.com/iam/docs/understanding-roles#logging.logWriter) +| +|dev-resman-dp-0
serviceAccount|[roles/serviceusage.serviceUsageConsumer](https://cloud.google.com/iam/docs/understanding-roles#serviceusage.serviceUsageConsumer) +| +|dev-resman-gke-0
serviceAccount|[roles/serviceusage.serviceUsageConsumer](https://cloud.google.com/iam/docs/understanding-roles#serviceusage.serviceUsageConsumer) +| +|dev-resman-pf-0
serviceAccount|[roles/serviceusage.serviceUsageConsumer](https://cloud.google.com/iam/docs/understanding-roles#serviceusage.serviceUsageConsumer) +| +|dev-resman-sbox-0
serviceAccount|[roles/serviceusage.serviceUsageConsumer](https://cloud.google.com/iam/docs/understanding-roles#serviceusage.serviceUsageConsumer) +| +|prod-resman-gke-0
serviceAccount|[roles/serviceusage.serviceUsageConsumer](https://cloud.google.com/iam/docs/understanding-roles#serviceusage.serviceUsageConsumer) +| +|prod-resman-net-0
serviceAccount|[roles/serviceusage.serviceUsageConsumer](https://cloud.google.com/iam/docs/understanding-roles#serviceusage.serviceUsageConsumer) +| |prod-resman-net-1
serviceAccount|[roles/logging.logWriter](https://cloud.google.com/iam/docs/understanding-roles#logging.logWriter) +| +|prod-resman-pf-0
serviceAccount|[roles/serviceusage.serviceUsageConsumer](https://cloud.google.com/iam/docs/understanding-roles#serviceusage.serviceUsageConsumer) +| |prod-resman-sec-1
serviceAccount|[roles/logging.logWriter](https://cloud.google.com/iam/docs/understanding-roles#logging.logWriter) +| +|prod-resman-teams-0
serviceAccount|[roles/serviceusage.serviceUsageConsumer](https://cloud.google.com/iam/docs/understanding-roles#serviceusage.serviceUsageConsumer) +| +|security-0
serviceAccount|[roles/serviceusage.serviceUsageConsumer](https://cloud.google.com/iam/docs/understanding-roles#serviceusage.serviceUsageConsumer) +| +|tn-egov-t0-0
serviceAccount|[roles/serviceusage.serviceUsageConsumer](https://cloud.google.com/iam/docs/understanding-roles#serviceusage.serviceUsageConsumer) +| diff --git a/fast/stages/1-resman/branch-data-platform.tf b/fast/stages/1-resman/branch-data-platform.tf index 219c3c65..635522cf 100644 --- a/fast/stages/1-resman/branch-data-platform.tf +++ b/fast/stages/1-resman/branch-data-platform.tf @@ -88,6 +88,9 @@ module "branch-dp-dev-sa" { try(module.branch-dp-dev-sa-cicd.0.iam_email, null) ]) } + iam_project_roles = { + (var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"] + } iam_storage_roles = { (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 791305f2..3d46fec9 100644 --- a/fast/stages/1-resman/branch-gke.tf +++ b/fast/stages/1-resman/branch-gke.tf @@ -87,6 +87,9 @@ module "branch-gke-dev-sa" { ]) ) } + iam_project_roles = { + (var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"] + } iam_storage_roles = { (var.automation.outputs_bucket) = ["roles/storage.objectAdmin"] } @@ -111,6 +114,9 @@ module "branch-gke-prod-sa" { ]) ) } + iam_project_roles = { + (var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"] + } iam_storage_roles = { (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 fe457569..e1379906 100644 --- a/fast/stages/1-resman/branch-networking.tf +++ b/fast/stages/1-resman/branch-networking.tf @@ -96,6 +96,9 @@ module "branch-network-sa" { try(module.branch-network-sa-cicd.0.iam_email, null) ]) } + iam_project_roles = { + (var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"] + } iam_storage_roles = { (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 7f2fbf28..6b708b27 100644 --- a/fast/stages/1-resman/branch-project-factory.tf +++ b/fast/stages/1-resman/branch-project-factory.tf @@ -29,6 +29,9 @@ module "branch-pf-dev-sa" { try(module.branch-pf-dev-sa-cicd.0.iam_email, null) ]) } + iam_project_roles = { + (var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"] + } iam_storage_roles = { (var.automation.outputs_bucket) = ["roles/storage.objectAdmin"] } @@ -47,6 +50,9 @@ module "branch-pf-prod-sa" { try(module.branch-pf-prod-sa-cicd.0.iam_email, null) ]) } + iam_project_roles = { + (var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"] + } iam_storage_roles = { (var.automation.outputs_bucket) = ["roles/storage.objectAdmin"] } diff --git a/fast/stages/1-resman/branch-sandbox.tf b/fast/stages/1-resman/branch-sandbox.tf index 33eae4f0..3628df76 100644 --- a/fast/stages/1-resman/branch-sandbox.tf +++ b/fast/stages/1-resman/branch-sandbox.tf @@ -59,4 +59,7 @@ module "branch-sandbox-sa" { name = "dev-resman-sbox-0" display_name = "Terraform resman sandbox service account." prefix = var.prefix + iam_project_roles = { + (var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"] + } } diff --git a/fast/stages/1-resman/branch-security.tf b/fast/stages/1-resman/branch-security.tf index 31a833dc..78c98aa0 100644 --- a/fast/stages/1-resman/branch-security.tf +++ b/fast/stages/1-resman/branch-security.tf @@ -60,9 +60,7 @@ module "branch-security-sa" { ]) } iam_project_roles = { - (var.automation.project_id) = [ - "roles/serviceusage.serviceUsageConsumer", - ] + (var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"] } iam_storage_roles = { (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 9c9f5399..33026c8e 100644 --- a/fast/stages/1-resman/branch-teams.tf +++ b/fast/stages/1-resman/branch-teams.tf @@ -46,6 +46,9 @@ module "branch-teams-sa" { name = "prod-resman-teams-0" display_name = "Terraform resman teams service account." prefix = var.prefix + iam_project_roles = { + (var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"] + } iam_storage_roles = { (var.automation.outputs_bucket) = ["roles/storage.objectAdmin"] } @@ -82,6 +85,8 @@ module "branch-teams-team-folder" { group_iam = each.value.group_iam == null ? {} : each.value.group_iam } +# TODO: move into team's own IaC project + module "branch-teams-team-sa" { source = "../../../modules/iam-service-account" for_each = var.fast_features.teams ? coalesce(var.team_folders, {}) : {} diff --git a/fast/stages/1-resman/branch-tenants.tf b/fast/stages/1-resman/branch-tenants.tf index 2bbafd7d..251c63c8 100644 --- a/fast/stages/1-resman/branch-tenants.tf +++ b/fast/stages/1-resman/branch-tenants.tf @@ -135,6 +135,9 @@ module "tenant-core-sa" { name = "tn-${each.key}-0" description = "Terraform service account for tenant ${each.key}." prefix = var.prefix + iam_project_roles = { + (var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"] + } } module "tenant-core-gcs" { diff --git a/fast/stages/2-networking-a-peering/README.md b/fast/stages/2-networking-a-peering/README.md index 05478d79..e0c9f9b2 100644 --- a/fast/stages/2-networking-a-peering/README.md +++ b/fast/stages/2-networking-a-peering/README.md @@ -376,8 +376,8 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS | [outputs.tf](./outputs.tf) | Module outputs. | | google_storage_bucket_object · local_file | | [peerings.tf](./peerings.tf) | None | net-vpc-peering | | | [regions.tf](./regions.tf) | Compute short names for regions. | | | -| [spoke-dev.tf](./spoke-dev.tf) | Dev spoke VPC and related resources. | net-cloudnat · net-vpc · net-vpc-firewall · project | google_project_iam_binding | -| [spoke-prod.tf](./spoke-prod.tf) | Production spoke VPC and related resources. | net-cloudnat · net-vpc · net-vpc-firewall · project | google_project_iam_binding | +| [spoke-dev.tf](./spoke-dev.tf) | Dev spoke VPC and related resources. | net-cloudnat · net-vpc · net-vpc-firewall · project | | +| [spoke-prod.tf](./spoke-prod.tf) | Production spoke VPC and related resources. | net-cloudnat · net-vpc · net-vpc-firewall · project | | | [test-resources.tf](./test-resources.tf) | temporary instances for testing | compute-vm | | | [variables-peerings.tf](./variables-peerings.tf) | Peering related variables. | | | | [variables.tf](./variables.tf) | Module variables. | | | diff --git a/fast/stages/2-networking-a-peering/spoke-dev.tf b/fast/stages/2-networking-a-peering/spoke-dev.tf index bfff002b..898bb850 100644 --- a/fast/stages/2-networking-a-peering/spoke-dev.tf +++ b/fast/stages/2-networking-a-peering/spoke-dev.tf @@ -43,6 +43,26 @@ module "dev-spoke-project" { try(local.service_accounts.project-factory-prod, null), ]) } + # allow specific service accounts to assign a set of roles + iam_bindings = { + sa_delegated_grants = { + role = "roles/resourcemanager.projectIamAdmin" + 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 = { + title = "dev_stage3_sa_delegated_grants" + description = "Development host project delegated grants." + expression = format( + "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])", + join(",", formatlist("'%s'", local.stage3_sas_delegated_grants)) + ) + } + } + } } module "dev-spoke-vpc" { @@ -84,23 +104,3 @@ module "dev-spoke-cloudnat" { router_network = module.dev-spoke-vpc.name logging_filter = "ERRORS_ONLY" } - -# Create delegated grants for stage3 service accounts -resource "google_project_iam_binding" "dev_spoke_project_iam_delegated" { - project = module.dev-spoke-project.project_id - role = "roles/resourcemanager.projectIamAdmin" - 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 { - title = "dev_stage3_sa_delegated_grants" - description = "Development host project delegated grants." - expression = format( - "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])", - join(",", formatlist("'%s'", local.stage3_sas_delegated_grants)) - ) - } -} diff --git a/fast/stages/2-networking-a-peering/spoke-prod.tf b/fast/stages/2-networking-a-peering/spoke-prod.tf index 505005bd..3226af61 100644 --- a/fast/stages/2-networking-a-peering/spoke-prod.tf +++ b/fast/stages/2-networking-a-peering/spoke-prod.tf @@ -42,6 +42,25 @@ module "prod-spoke-project" { try(local.service_accounts.project-factory-prod, null), ]) } + # allow specific service accounts to assign a set of roles + iam_bindings = { + sa_delegated_grants = { + role = "roles/resourcemanager.projectIamAdmin" + members = compact([ + try(local.service_accounts.data-platform-prod, null), + try(local.service_accounts.project-factory-prod, null), + try(local.service_accounts.gke-prod, null), + ]) + condition = { + title = "prod_stage3_sa_delegated_grants" + description = "Production host project delegated grants." + expression = format( + "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])", + join(",", formatlist("'%s'", local.stage3_sas_delegated_grants)) + ) + } + } + } } module "prod-spoke-vpc" { @@ -83,22 +102,3 @@ module "prod-spoke-cloudnat" { router_network = module.prod-spoke-vpc.name logging_filter = "ERRORS_ONLY" } - -# Create delegated grants for stage3 service accounts -resource "google_project_iam_binding" "prod_spoke_project_iam_delegated" { - project = module.prod-spoke-project.project_id - role = "roles/resourcemanager.projectIamAdmin" - members = compact([ - try(local.service_accounts.data-platform-prod, null), - try(local.service_accounts.project-factory-prod, null), - try(local.service_accounts.gke-prod, null), - ]) - condition { - title = "prod_stage3_sa_delegated_grants" - description = "Production host project delegated grants." - expression = format( - "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])", - join(",", formatlist("'%s'", local.stage3_sas_delegated_grants)) - ) - } -} diff --git a/fast/stages/2-networking-b-vpn/README.md b/fast/stages/2-networking-b-vpn/README.md index 4de2666e..68e9a279 100644 --- a/fast/stages/2-networking-b-vpn/README.md +++ b/fast/stages/2-networking-b-vpn/README.md @@ -397,8 +397,8 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS | [monitoring.tf](./monitoring.tf) | Network monitoring dashboards. | | google_monitoring_dashboard | | [outputs.tf](./outputs.tf) | Module outputs. | | google_storage_bucket_object · local_file | | [regions.tf](./regions.tf) | Compute short names for regions. | | | -| [spoke-dev.tf](./spoke-dev.tf) | Dev spoke VPC and related resources. | net-cloudnat · net-vpc · net-vpc-firewall · project | google_project_iam_binding | -| [spoke-prod.tf](./spoke-prod.tf) | Production spoke VPC and related resources. | net-cloudnat · net-vpc · net-vpc-firewall · project | google_project_iam_binding | +| [spoke-dev.tf](./spoke-dev.tf) | Dev spoke VPC and related resources. | net-cloudnat · net-vpc · net-vpc-firewall · project | | +| [spoke-prod.tf](./spoke-prod.tf) | Production spoke VPC and related resources. | net-cloudnat · net-vpc · net-vpc-firewall · project | | | [test-resources.tf](./test-resources.tf) | temporary instances for testing | compute-vm | | | [variables-vpn.tf](./variables-vpn.tf) | None | | | | [variables.tf](./variables.tf) | Module variables. | | | diff --git a/fast/stages/2-networking-b-vpn/spoke-dev.tf b/fast/stages/2-networking-b-vpn/spoke-dev.tf index bfff002b..898bb850 100644 --- a/fast/stages/2-networking-b-vpn/spoke-dev.tf +++ b/fast/stages/2-networking-b-vpn/spoke-dev.tf @@ -43,6 +43,26 @@ module "dev-spoke-project" { try(local.service_accounts.project-factory-prod, null), ]) } + # allow specific service accounts to assign a set of roles + iam_bindings = { + sa_delegated_grants = { + role = "roles/resourcemanager.projectIamAdmin" + 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 = { + title = "dev_stage3_sa_delegated_grants" + description = "Development host project delegated grants." + expression = format( + "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])", + join(",", formatlist("'%s'", local.stage3_sas_delegated_grants)) + ) + } + } + } } module "dev-spoke-vpc" { @@ -84,23 +104,3 @@ module "dev-spoke-cloudnat" { router_network = module.dev-spoke-vpc.name logging_filter = "ERRORS_ONLY" } - -# Create delegated grants for stage3 service accounts -resource "google_project_iam_binding" "dev_spoke_project_iam_delegated" { - project = module.dev-spoke-project.project_id - role = "roles/resourcemanager.projectIamAdmin" - 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 { - title = "dev_stage3_sa_delegated_grants" - description = "Development host project delegated grants." - expression = format( - "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])", - join(",", formatlist("'%s'", local.stage3_sas_delegated_grants)) - ) - } -} diff --git a/fast/stages/2-networking-b-vpn/spoke-prod.tf b/fast/stages/2-networking-b-vpn/spoke-prod.tf index 505005bd..3226af61 100644 --- a/fast/stages/2-networking-b-vpn/spoke-prod.tf +++ b/fast/stages/2-networking-b-vpn/spoke-prod.tf @@ -42,6 +42,25 @@ module "prod-spoke-project" { try(local.service_accounts.project-factory-prod, null), ]) } + # allow specific service accounts to assign a set of roles + iam_bindings = { + sa_delegated_grants = { + role = "roles/resourcemanager.projectIamAdmin" + members = compact([ + try(local.service_accounts.data-platform-prod, null), + try(local.service_accounts.project-factory-prod, null), + try(local.service_accounts.gke-prod, null), + ]) + condition = { + title = "prod_stage3_sa_delegated_grants" + description = "Production host project delegated grants." + expression = format( + "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])", + join(",", formatlist("'%s'", local.stage3_sas_delegated_grants)) + ) + } + } + } } module "prod-spoke-vpc" { @@ -83,22 +102,3 @@ module "prod-spoke-cloudnat" { router_network = module.prod-spoke-vpc.name logging_filter = "ERRORS_ONLY" } - -# Create delegated grants for stage3 service accounts -resource "google_project_iam_binding" "prod_spoke_project_iam_delegated" { - project = module.prod-spoke-project.project_id - role = "roles/resourcemanager.projectIamAdmin" - members = compact([ - try(local.service_accounts.data-platform-prod, null), - try(local.service_accounts.project-factory-prod, null), - try(local.service_accounts.gke-prod, null), - ]) - condition { - title = "prod_stage3_sa_delegated_grants" - description = "Production host project delegated grants." - expression = format( - "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])", - join(",", formatlist("'%s'", local.stage3_sas_delegated_grants)) - ) - } -} diff --git a/fast/stages/2-networking-c-nva/README.md b/fast/stages/2-networking-c-nva/README.md index d61baf57..daee38fc 100644 --- a/fast/stages/2-networking-c-nva/README.md +++ b/fast/stages/2-networking-c-nva/README.md @@ -446,8 +446,8 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS | [nva.tf](./nva.tf) | None | compute-mig · compute-vm · simple-nva | | | [outputs.tf](./outputs.tf) | Module outputs. | | google_storage_bucket_object · local_file | | [regions.tf](./regions.tf) | Compute short names for regions. | | | -| [spoke-dev.tf](./spoke-dev.tf) | Dev spoke VPC and related resources. | net-vpc · net-vpc-firewall · net-vpc-peering · project | google_project_iam_binding | -| [spoke-prod.tf](./spoke-prod.tf) | Production spoke VPC and related resources. | net-vpc · net-vpc-firewall · net-vpc-peering · project | google_project_iam_binding | +| [spoke-dev.tf](./spoke-dev.tf) | Dev spoke VPC and related resources. | net-vpc · net-vpc-firewall · net-vpc-peering · project | | +| [spoke-prod.tf](./spoke-prod.tf) | Production spoke VPC and related resources. | net-vpc · net-vpc-firewall · net-vpc-peering · project | | | [test-resources.tf](./test-resources.tf) | temporary instances for testing | compute-vm | | | [variables.tf](./variables.tf) | Module variables. | | | | [vpn-onprem.tf](./vpn-onprem.tf) | VPN between landing and onprem. | net-vpn-ha | | diff --git a/fast/stages/2-networking-c-nva/spoke-dev.tf b/fast/stages/2-networking-c-nva/spoke-dev.tf index b90ed4dc..98c4038b 100644 --- a/fast/stages/2-networking-c-nva/spoke-dev.tf +++ b/fast/stages/2-networking-c-nva/spoke-dev.tf @@ -42,6 +42,26 @@ module "dev-spoke-project" { try(local.service_accounts.project-factory-prod, null), ]) } + # allow specific service accounts to assign a set of roles + iam_bindings = { + sa_delegated_grants = { + role = "roles/resourcemanager.projectIamAdmin" + 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 = { + title = "dev_stage3_sa_delegated_grants" + description = "Development host project delegated grants." + expression = format( + "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])", + join(",", formatlist("'%s'", local.stage3_sas_delegated_grants)) + ) + } + } + } } module "dev-spoke-vpc" { @@ -110,23 +130,3 @@ module "peering-dev" { local_network = module.dev-spoke-vpc.self_link peer_network = module.landing-trusted-vpc.self_link } - -# Create delegated grants for stage3 service accounts -resource "google_project_iam_binding" "dev_spoke_project_iam_delegated" { - project = module.dev-spoke-project.project_id - role = "roles/resourcemanager.projectIamAdmin" - 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 { - title = "dev_stage3_sa_delegated_grants" - description = "Development host project delegated grants." - expression = format( - "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])", - join(",", formatlist("'%s'", local.stage3_sas_delegated_grants)) - ) - } -} diff --git a/fast/stages/2-networking-c-nva/spoke-prod.tf b/fast/stages/2-networking-c-nva/spoke-prod.tf index a4bdb1d2..91353c97 100644 --- a/fast/stages/2-networking-c-nva/spoke-prod.tf +++ b/fast/stages/2-networking-c-nva/spoke-prod.tf @@ -41,6 +41,25 @@ module "prod-spoke-project" { try(local.service_accounts.project-factory-prod, null), ]) } + # allow specific service accounts to assign a set of roles + iam_bindings = { + sa_delegated_grants = { + role = "roles/resourcemanager.projectIamAdmin" + members = compact([ + try(local.service_accounts.data-platform-prod, null), + try(local.service_accounts.project-factory-prod, null), + try(local.service_accounts.gke-prod, null), + ]) + condition = { + title = "prod_stage3_sa_delegated_grants" + description = "Production host project delegated grants." + expression = format( + "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])", + join(",", formatlist("'%s'", local.stage3_sas_delegated_grants)) + ) + } + } + } } module "prod-spoke-vpc" { @@ -109,22 +128,3 @@ module "peering-prod" { local_network = module.prod-spoke-vpc.self_link peer_network = module.landing-trusted-vpc.self_link } - -# Create delegated grants for stage3 service accounts -resource "google_project_iam_binding" "prod_spoke_project_iam_delegated" { - project = module.prod-spoke-project.project_id - role = "roles/resourcemanager.projectIamAdmin" - members = compact([ - try(local.service_accounts.data-platform-prod, null), - try(local.service_accounts.project-factory-prod, null), - try(local.service_accounts.gke-prod, null), - ]) - condition { - title = "prod_stage3_sa_delegated_grants" - description = "Production host project delegated grants." - expression = format( - "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])", - join(",", formatlist("'%s'", local.stage3_sas_delegated_grants)) - ) - } -} diff --git a/fast/stages/2-networking-d-separate-envs/README.md b/fast/stages/2-networking-d-separate-envs/README.md index e84530e8..88f68846 100644 --- a/fast/stages/2-networking-d-separate-envs/README.md +++ b/fast/stages/2-networking-d-separate-envs/README.md @@ -320,8 +320,8 @@ Regions are defined via the `regions` variable which sets up a mapping between t | [monitoring.tf](./monitoring.tf) | Network monitoring dashboards. | | google_monitoring_dashboard | | [outputs.tf](./outputs.tf) | Module outputs. | | google_storage_bucket_object · local_file | | [regions.tf](./regions.tf) | Compute short names for regions. | | | -| [spoke-dev.tf](./spoke-dev.tf) | Dev spoke VPC and related resources. | net-cloudnat · net-vpc · net-vpc-firewall · project | google_project_iam_binding | -| [spoke-prod.tf](./spoke-prod.tf) | Production spoke VPC and related resources. | net-cloudnat · net-vpc · net-vpc-firewall · project | google_project_iam_binding | +| [spoke-dev.tf](./spoke-dev.tf) | Dev spoke VPC and related resources. | net-cloudnat · net-vpc · net-vpc-firewall · project | | +| [spoke-prod.tf](./spoke-prod.tf) | Production spoke VPC and related resources. | net-cloudnat · net-vpc · net-vpc-firewall · project | | | [test-resources.tf](./test-resources.tf) | Temporary instances for testing | compute-vm | | | [variables.tf](./variables.tf) | Module variables. | | | | [vpn-onprem.tf](./vpn-onprem.tf) | VPN between landing and onprem. | net-vpn-ha | | 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 61562f44..5cd8c355 100644 --- a/fast/stages/2-networking-d-separate-envs/spoke-dev.tf +++ b/fast/stages/2-networking-d-separate-envs/spoke-dev.tf @@ -43,6 +43,26 @@ module "dev-spoke-project" { try(local.service_accounts.project-factory-prod, null), ]) } + # allow specific service accounts to assign a set of roles + iam_bindings = { + sa_delegated_grants = { + role = "roles/resourcemanager.projectIamAdmin" + 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 = { + title = "dev_stage3_sa_delegated_grants" + description = "Development host project delegated grants." + expression = format( + "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])", + join(",", formatlist("'%s'", local.stage3_sas_delegated_grants)) + ) + } + } + } } module "dev-spoke-vpc" { @@ -84,23 +104,3 @@ module "dev-spoke-cloudnat" { router_network = module.dev-spoke-vpc.name logging_filter = "ERRORS_ONLY" } - -# Create delegated grants for stage3 service accounts -resource "google_project_iam_binding" "dev_spoke_project_iam_delegated" { - project = module.dev-spoke-project.project_id - 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" - description = "Development host project delegated grants." - expression = format( - "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])", - join(",", formatlist("'%s'", local.stage3_sas_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 7b42f546..6889bb96 100644 --- a/fast/stages/2-networking-d-separate-envs/spoke-prod.tf +++ b/fast/stages/2-networking-d-separate-envs/spoke-prod.tf @@ -42,6 +42,25 @@ module "prod-spoke-project" { try(local.service_accounts.project-factory-prod, null) ]) } + # allow specific service accounts to assign a set of roles + iam_bindings = { + sa_delegated_grants = { + role = "roles/resourcemanager.projectIamAdmin" + members = compact([ + try(local.service_accounts.data-platform-prod, null), + try(local.service_accounts.project-factory-prod, null), + try(local.service_accounts.gke-prod, null), + ]) + condition = { + title = "prod_stage3_sa_delegated_grants" + description = "Production host project delegated grants." + expression = format( + "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])", + join(",", formatlist("'%s'", local.stage3_sas_delegated_grants)) + ) + } + } + } } module "prod-spoke-vpc" { @@ -83,22 +102,3 @@ module "prod-spoke-cloudnat" { router_network = module.prod-spoke-vpc.name logging_filter = "ERRORS_ONLY" } - -# Create delegated grants for stage3 service accounts -resource "google_project_iam_binding" "prod_spoke_project_iam_delegated" { - project = module.prod-spoke-project.project_id - 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 { - title = "prod_stage3_sa_delegated_grants" - description = "Production host project delegated grants." - expression = format( - "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])", - join(",", formatlist("'%s'", local.stage3_sas_delegated_grants)) - ) - } -} diff --git a/fast/stages/2-networking-e-nva-bgp/README.md b/fast/stages/2-networking-e-nva-bgp/README.md index 4b3d6fad..e9bf8c10 100644 --- a/fast/stages/2-networking-e-nva-bgp/README.md +++ b/fast/stages/2-networking-e-nva-bgp/README.md @@ -472,8 +472,8 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS | [nva.tf](./nva.tf) | None | compute-vm · simple-nva | google_compute_address | | [outputs.tf](./outputs.tf) | Module outputs. | | google_storage_bucket_object · local_file | | [regions.tf](./regions.tf) | Compute short names for regions. | | | -| [spoke-dev.tf](./spoke-dev.tf) | Dev spoke VPC and related resources. | net-vpc · net-vpc-firewall · net-vpc-peering · project | google_project_iam_binding | -| [spoke-prod.tf](./spoke-prod.tf) | Production spoke VPC and related resources. | net-vpc · net-vpc-firewall · net-vpc-peering · project | google_project_iam_binding | +| [spoke-dev.tf](./spoke-dev.tf) | Dev spoke VPC and related resources. | net-vpc · net-vpc-firewall · net-vpc-peering · project | | +| [spoke-prod.tf](./spoke-prod.tf) | Production spoke VPC and related resources. | net-vpc · net-vpc-firewall · net-vpc-peering · project | | | [test-resources.tf](./test-resources.tf) | temporary instances for testing | compute-vm | | | [variables.tf](./variables.tf) | Module variables. | | | | [vpn-onprem.tf](./vpn-onprem.tf) | VPN between landing and onprem. | net-vpn-ha | | diff --git a/fast/stages/2-networking-e-nva-bgp/spoke-dev.tf b/fast/stages/2-networking-e-nva-bgp/spoke-dev.tf index 56b65e39..92a4a21f 100644 --- a/fast/stages/2-networking-e-nva-bgp/spoke-dev.tf +++ b/fast/stages/2-networking-e-nva-bgp/spoke-dev.tf @@ -42,6 +42,26 @@ module "dev-spoke-project" { try(local.service_accounts.project-factory-prod, null), ]) } + # allow specific service accounts to assign a set of roles + iam_bindings = { + sa_delegated_grants = { + role = "roles/resourcemanager.projectIamAdmin" + 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 = { + title = "dev_stage3_sa_delegated_grants" + description = "Development host project delegated grants." + expression = format( + "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])", + join(",", formatlist("'%s'", local.stage3_sas_delegated_grants)) + ) + } + } + } } module "dev-spoke-vpc" { @@ -80,23 +100,3 @@ module "peering-dev" { local_network = module.dev-spoke-vpc.self_link peer_network = module.landing-trusted-vpc.self_link } - -# Create delegated grants for stage3 service accounts -resource "google_project_iam_binding" "dev_spoke_project_iam_delegated" { - project = module.dev-spoke-project.project_id - role = "roles/resourcemanager.projectIamAdmin" - 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 { - title = "dev_stage3_sa_delegated_grants" - description = "Development host project delegated grants." - expression = format( - "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])", - join(",", formatlist("'%s'", local.stage3_sas_delegated_grants)) - ) - } -} diff --git a/fast/stages/2-networking-e-nva-bgp/spoke-prod.tf b/fast/stages/2-networking-e-nva-bgp/spoke-prod.tf index 6ae49dee..b5bff393 100644 --- a/fast/stages/2-networking-e-nva-bgp/spoke-prod.tf +++ b/fast/stages/2-networking-e-nva-bgp/spoke-prod.tf @@ -41,6 +41,25 @@ module "prod-spoke-project" { try(local.service_accounts.project-factory-prod, null), ]) } + # allow specific service accounts to assign a set of roles + iam_bindings = { + sa_delegated_grants = { + role = "roles/resourcemanager.projectIamAdmin" + members = compact([ + try(local.service_accounts.data-platform-prod, null), + try(local.service_accounts.project-factory-prod, null), + try(local.service_accounts.gke-prod, null), + ]) + condition = { + title = "prod_stage3_sa_delegated_grants" + description = "Production host project delegated grants." + expression = format( + "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])", + join(",", formatlist("'%s'", local.stage3_sas_delegated_grants)) + ) + } + } + } } module "prod-spoke-vpc" { @@ -79,22 +98,3 @@ module "peering-prod" { local_network = module.prod-spoke-vpc.self_link peer_network = module.landing-trusted-vpc.self_link } - -# Create delegated grants for stage3 service accounts -resource "google_project_iam_binding" "prod_spoke_project_iam_delegated" { - project = module.prod-spoke-project.project_id - role = "roles/resourcemanager.projectIamAdmin" - members = compact([ - try(local.service_accounts.data-platform-prod, null), - try(local.service_accounts.project-factory-prod, null), - try(local.service_accounts.gke-prod, null), - ]) - condition { - title = "prod_stage3_sa_delegated_grants" - description = "Production host project delegated grants." - expression = format( - "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])", - join(",", formatlist("'%s'", local.stage3_sas_delegated_grants)) - ) - } -} diff --git a/tests/fast/stages/s0_bootstrap/simple.yaml b/tests/fast/stages/s0_bootstrap/simple.yaml index 0afb9d02..70ad130a 100644 --- a/tests/fast/stages/s0_bootstrap/simple.yaml +++ b/tests/fast/stages/s0_bootstrap/simple.yaml @@ -20,8 +20,8 @@ counts: google_organization_iam_custom_role: 3 google_organization_iam_member: 13 google_project: 3 - google_project_iam_binding: 9 - google_project_iam_member: 3 + google_project_iam_binding: 10 + google_project_iam_member: 4 google_project_service: 29 google_project_service_identity: 3 google_service_account: 2