From c4d36cc66b05de2f848abf9ed055e545bbbc938c Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Thu, 10 Feb 2022 19:12:07 +0100 Subject: [PATCH 1/4] Allow specifying custom role names --- fast/stages/00-bootstrap/organization.tf | 6 +++--- fast/stages/00-bootstrap/outputs.tf | 8 ++++++-- fast/stages/00-bootstrap/variables.tf | 8 ++++++++ fast/stages/02-networking-vpn/vpc-spoke-dev.tf | 2 +- fast/stages/02-networking-vpn/vpc-spoke-prod.tf | 2 +- 5 files changed, 19 insertions(+), 7 deletions(-) diff --git a/fast/stages/00-bootstrap/organization.tf b/fast/stages/00-bootstrap/organization.tf index ea2e4cef..689f378b 100644 --- a/fast/stages/00-bootstrap/organization.tf +++ b/fast/stages/00-bootstrap/organization.tf @@ -147,12 +147,12 @@ module "organization" { iam_additive = local.iam_additive custom_roles = { # this is needed for use in additive IAM bindings, to avoid conflicts - "organizationIamAdmin" = [ + (var.custom_role_names.organization_iam_admin) = [ "resourcemanager.organizations.get", "resourcemanager.organizations.getIamPolicy", "resourcemanager.organizations.setIamPolicy" ] - "serviceProjectNetworkAdmin" = [ + (var.custom_role_names.service_project_network_admin) = [ "compute.globalOperations.get", "compute.organizations.disableXpnResource", "compute.organizations.enableXpnResource", @@ -182,7 +182,7 @@ module "organization" { resource "google_organization_iam_binding" "org_admin_delegated" { org_id = var.organization.id - role = module.organization.custom_role_id.organizationIamAdmin + role = module.organization.custom_role_id[var.custom_role_names.organization_iam_admin] members = [module.automation-tf-resman-sa.iam_email] condition { title = "automation_sa_delegated_grants" diff --git a/fast/stages/00-bootstrap/outputs.tf b/fast/stages/00-bootstrap/outputs.tf index d7924781..d074d91f 100644 --- a/fast/stages/00-bootstrap/outputs.tf +++ b/fast/stages/00-bootstrap/outputs.tf @@ -15,6 +15,10 @@ */ locals { + _custom_roles = { + for k, v in var.custom_role_names : + k => module.organization.custom_role_id[v] + } providers = { "00-bootstrap" = templatefile("${path.module}/../../assets/templates/providers.tpl", { bucket = module.automation-tf-bootstrap-gcs.name @@ -31,14 +35,14 @@ locals { "01-resman" = jsonencode({ automation_project_id = module.automation-project.project_id billing_account = var.billing_account - custom_roles = module.organization.custom_role_id + custom_roles = local._custom_roles groups = var.groups organization = var.organization prefix = var.prefix }) "02-networking" = jsonencode({ billing_account_id = var.billing_account.id - custom_roles = module.organization.custom_role_id + custom_roles = local._custom_roles organization = var.organization prefix = var.prefix }) diff --git a/fast/stages/00-bootstrap/variables.tf b/fast/stages/00-bootstrap/variables.tf index 1bf0e2de..8fe53c7f 100644 --- a/fast/stages/00-bootstrap/variables.tf +++ b/fast/stages/00-bootstrap/variables.tf @@ -28,6 +28,14 @@ variable "bootstrap_user" { default = null } +variable "custom_role_names" { + description = "Names of custom roles defined at the org level." + type = object({ + organization_iam_admin = "organizationIamAdmin" + service_project_network_admin = "serviceProjectNetworkAdmin" + }) +} + variable "groups" { # https://cloud.google.com/docs/enterprise/setup-checklist description = "Group names to grant organization-level permissions." diff --git a/fast/stages/02-networking-vpn/vpc-spoke-dev.tf b/fast/stages/02-networking-vpn/vpc-spoke-dev.tf index 9b3c0f9e..4a3f0f25 100644 --- a/fast/stages/02-networking-vpn/vpc-spoke-dev.tf +++ b/fast/stages/02-networking-vpn/vpc-spoke-dev.tf @@ -40,7 +40,7 @@ module "dev-spoke-project" { metric_scopes = [module.landing-project.project_id] iam = { "roles/dns.admin" = [var.project_factory_sa.dev] - (var.custom_roles.serviceProjectNetworkAdmin) = [ + (var.custom_roles.service_project_network_admin) = [ var.project_factory_sa.prod ] } diff --git a/fast/stages/02-networking-vpn/vpc-spoke-prod.tf b/fast/stages/02-networking-vpn/vpc-spoke-prod.tf index 7f42ab2c..3be90c2e 100644 --- a/fast/stages/02-networking-vpn/vpc-spoke-prod.tf +++ b/fast/stages/02-networking-vpn/vpc-spoke-prod.tf @@ -40,7 +40,7 @@ module "prod-spoke-project" { metric_scopes = [module.landing-project.project_id] iam = { "roles/dns.admin" = [var.project_factory_sa.prod] - (var.custom_roles.serviceProjectNetworkAdmin) = [ + (var.custom_roles.service_project_network_admin) = [ var.project_factory_sa.prod ] } From 3246d1c08d836a1298b331375add796629d0e749 Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Thu, 10 Feb 2022 19:13:55 +0100 Subject: [PATCH 2/4] fix variable --- fast/stages/00-bootstrap/variables.tf | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fast/stages/00-bootstrap/variables.tf b/fast/stages/00-bootstrap/variables.tf index 8fe53c7f..33709703 100644 --- a/fast/stages/00-bootstrap/variables.tf +++ b/fast/stages/00-bootstrap/variables.tf @@ -31,9 +31,13 @@ variable "bootstrap_user" { variable "custom_role_names" { description = "Names of custom roles defined at the org level." type = object({ + organization_iam_admin = string + service_project_network_admin = string + }) + default = { organization_iam_admin = "organizationIamAdmin" service_project_network_admin = "serviceProjectNetworkAdmin" - }) + } } variable "groups" { From 677f3c8df120905e8868e5ddf419b2d0b53ba87e Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Thu, 10 Feb 2022 19:16:13 +0100 Subject: [PATCH 3/4] use custom role name for billing org too --- fast/stages/00-bootstrap/billing.tf | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fast/stages/00-bootstrap/billing.tf b/fast/stages/00-bootstrap/billing.tf index e6abc31d..e8227041 100644 --- a/fast/stages/00-bootstrap/billing.tf +++ b/fast/stages/00-bootstrap/billing.tf @@ -73,7 +73,10 @@ resource "google_organization_iam_binding" "billing_org_ext_admin_delegated" { org_id = var.billing_account.organization_id # if the billing org does not have our custom role, user the predefined one # role = "roles/resourcemanager.organizationAdmin" - role = "organizations/${var.billing_account.organization_id}/roles/organizationIamAdmin" + role = join("", [ + "organizations/${var.billing_account.organization_id}/", + "roles/${var.custom_role_names.organization_iam_admin}" + ]) members = [module.automation-tf-resman-sa.iam_email] condition { title = "automation_sa_delegated_grants" From bb974869878d30ad32c321812238eee43d88db8e Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Thu, 10 Feb 2022 19:17:35 +0100 Subject: [PATCH 4/4] tfdoc --- fast/stages/00-bootstrap/README.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/fast/stages/00-bootstrap/README.md b/fast/stages/00-bootstrap/README.md index f5bf29d0..a9b804e9 100644 --- a/fast/stages/00-bootstrap/README.md +++ b/fast/stages/00-bootstrap/README.md @@ -327,22 +327,23 @@ Names used in internal references (e.g. `module.foo-prod.id`) are only used by T | name | description | type | required | default | producer | |---|---|:---:|:---:|:---:|:---:| | [billing_account](variables.tf#L17) | Billing account id and organization id ('nnnnnnnn' or null). | object({…}) | ✓ | | | -| [organization](variables.tf#L84) | Organization details. | object({…}) | ✓ | | | -| [prefix](variables.tf#L99) | Prefix used for resources that need unique names. | string | ✓ | | | +| [organization](variables.tf#L96) | Organization details. | object({…}) | ✓ | | | +| [prefix](variables.tf#L111) | Prefix used for resources that need unique names. | string | ✓ | | | | [bootstrap_user](variables.tf#L25) | Email of the nominal user running this stage for the first time. | string | | null | | -| [groups](variables.tf#L31) | Group names to grant organization-level permissions. | map(string) | | {…} | | -| [iam](variables.tf#L45) | Organization-level custom IAM settings in role => [principal] format. | map(list(string)) | | {} | | -| [iam_additive](variables.tf#L51) | Organization-level custom IAM settings in role => [principal] format for non-authoritative bindings. | map(list(string)) | | {} | | -| [log_sinks](variables.tf#L59) | Org-level log sinks, in name => {type, filter} format. | map(object({…})) | | {…} | | -| [outputs_location](variables.tf#L93) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string | | null | | +| [custom_role_names](variables.tf#L31) | Names of custom roles defined at the org level. | object({…}) | | {…} | | +| [groups](variables.tf#L43) | Group names to grant organization-level permissions. | map(string) | | {…} | | +| [iam](variables.tf#L57) | Organization-level custom IAM settings in role => [principal] format. | map(list(string)) | | {} | | +| [iam_additive](variables.tf#L63) | Organization-level custom IAM settings in role => [principal] format for non-authoritative bindings. | map(list(string)) | | {} | | +| [log_sinks](variables.tf#L71) | Org-level log sinks, in name => {type, filter} format. | map(object({…})) | | {…} | | +| [outputs_location](variables.tf#L105) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string | | null | | ## Outputs | name | description | sensitive | consumers | |---|---|:---:|---| -| [billing_dataset](outputs.tf#L85) | BigQuery dataset prepared for billing export. | | | -| [project_ids](outputs.tf#L90) | Projects created by this stage. | | | -| [providers](outputs.tf#L101) | Terraform provider files for this stage and dependent stages. | ✓ | stage-01 | -| [tfvars](outputs.tf#L110) | Terraform variable files for the following stages. | ✓ | | +| [billing_dataset](outputs.tf#L89) | BigQuery dataset prepared for billing export. | | | +| [project_ids](outputs.tf#L94) | Projects created by this stage. | | | +| [providers](outputs.tf#L105) | Terraform provider files for this stage and dependent stages. | ✓ | stage-01 | +| [tfvars](outputs.tf#L114) | Terraform variable files for the following stages. | ✓ | |