diff --git a/fast/stages/1-resman/README.md b/fast/stages/1-resman/README.md index f0d291cc70..5f220e794a 100644 --- a/fast/stages/1-resman/README.md +++ b/fast/stages/1-resman/README.md @@ -268,32 +268,32 @@ A full reference of IAM roles managed by this stage [is available here](./IAM.md | [logging](variables-fast.tf#L93) | Logging configuration for tenants. | object({…}) | ✓ | | 1-tenant-factory | | [organization](variables-fast.tf#L106) | Organization details. | object({…}) | ✓ | | 0-bootstrap | | [prefix](variables-fast.tf#L124) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 0-bootstrap | -| [cicd_repositories](variables.tf#L20) | CI/CD repository configuration. Identity providers reference keys in the `automation.federated_identity_providers` variable. Set to null to disable, or set individual repositories to null if not needed. | object({…}) | | null | | +| [cicd_repositories](variables.tf#L20) | CI/CD repository configuration. Identity providers reference keys in the `automation.federated_identity_providers` variable. Set to null to disable, or set individual repositories to null if not needed. | object({…}) | | null | | | [custom_roles](variables-fast.tf#L53) | Custom roles defined at the org level, in key => id format. | object({…}) | | null | 0-bootstrap | -| [factories_config](variables.tf#L110) | Configuration for the resource factories or external data. | object({…}) | | {} | | -| [fast_features](variables.tf#L121) | Selective control for top-level FAST features. | object({…}) | | {} | | -| [folder_iam](variables.tf#L134) | Authoritative IAM for top-level folders. | object({…}) | | {} | | +| [factories_config](variables.tf#L116) | Configuration for the resource factories or external data. | object({…}) | | {} | | +| [fast_features](variables.tf#L127) | Selective control for top-level FAST features. | object({…}) | | {} | | +| [folder_iam](variables.tf#L140) | Authoritative IAM for top-level folders. | object({…}) | | {} | | | [groups](variables-fast.tf#L65) | Group names or IAM-format principals to grant organization-level permissions. If just the name is provided, the 'group:' principal and organization domain are interpolated. | object({…}) | | {} | 0-bootstrap | | [locations](variables-fast.tf#L80) | Optional locations for GCS, BigQuery, and logging buckets created here. | object({…}) | | {} | 0-bootstrap | -| [outputs_location](variables.tf#L148) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable. | string | | null | | +| [outputs_location](variables.tf#L154) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable. | string | | null | | | [root_node](variables-fast.tf#L130) | Root node for the hierarchy, if running in tenant mode. | string | | null | 0-bootstrap | -| [tag_names](variables.tf#L154) | Customized names for resource management tags. | object({…}) | | {} | | -| [tags](variables.tf#L168) | Custom secure tags by key name. The `iam` attribute behaves like the similarly named one at module level. | map(object({…})) | | {} | | -| [top_level_folders](variables.tf#L189) | Additional top-level folders. Keys are used for service account and bucket names, values implement the folders module interface with the addition of the 'automation' attribute. | map(object({…})) | | {} | | +| [tag_names](variables.tf#L160) | Customized names for resource management tags. | object({…}) | | {} | | +| [tags](variables.tf#L174) | Custom secure tags by key name. The `iam` attribute behaves like the similarly named one at module level. | map(object({…})) | | {} | | +| [top_level_folders](variables.tf#L195) | Additional top-level folders. Keys are used for service account and bucket names, values implement the folders module interface with the addition of the 'automation' attribute. | map(object({…})) | | {} | | ## Outputs | name | description | sensitive | consumers | |---|---|:---:|---| -| [cicd_repositories](outputs.tf#L352) | WIF configuration for CI/CD repositories. | | | -| [dataplatform](outputs.tf#L366) | Data for the Data Platform stage. | | | -| [folder_ids](outputs.tf#L382) | Folder ids. | | | -| [gcve](outputs.tf#L387) | Data for the GCVE stage. | | 03-gcve | -| [gke_multitenant](outputs.tf#L408) | Data for the GKE multitenant stage. | | 03-gke-multitenant | -| [networking](outputs.tf#L429) | Data for the networking stage. | | | -| [project_factories](outputs.tf#L438) | Data for the project factories stage. | | | -| [providers](outputs.tf#L453) | Terraform provider files for this stage and dependent stages. | ✓ | 02-networking · 02-security · 03-dataplatform | -| [sandbox](outputs.tf#L460) | Data for the sandbox stage. | | xx-sandbox | -| [security](outputs.tf#L474) | Data for the networking stage. | | 02-security | -| [tfvars](outputs.tf#L485) | Terraform variable files for the following stages. | ✓ | | +| [cicd_repositories](outputs.tf#L377) | WIF configuration for CI/CD repositories. | | | +| [dataplatform](outputs.tf#L391) | Data for the Data Platform stage. | | | +| [folder_ids](outputs.tf#L407) | Folder ids. | | | +| [gcve](outputs.tf#L412) | Data for the GCVE stage. | | 03-gcve | +| [gke_multitenant](outputs.tf#L433) | Data for the GKE multitenant stage. | | 03-gke-multitenant | +| [networking](outputs.tf#L454) | Data for the networking stage. | | | +| [project_factories](outputs.tf#L463) | Data for the project factories stage. | | | +| [providers](outputs.tf#L482) | Terraform provider files for this stage and dependent stages. | ✓ | 02-networking · 02-security · 03-dataplatform | +| [sandbox](outputs.tf#L489) | Data for the sandbox stage. | | xx-sandbox | +| [security](outputs.tf#L503) | Data for the networking stage. | | 02-security | +| [tfvars](outputs.tf#L514) | Terraform variable files for the following stages. | ✓ | | diff --git a/fast/stages/1-resman/billing.tf b/fast/stages/1-resman/billing.tf index 64b87c265a..afa6958dcd 100644 --- a/fast/stages/1-resman/billing.tf +++ b/fast/stages/1-resman/billing.tf @@ -29,6 +29,7 @@ locals { local.branch_optional_sa_lists.gke-prod, local.branch_optional_sa_lists.gcve-dev, local.branch_optional_sa_lists.gcve-prod, + local.branch_optional_sa_lists.pf, local.branch_optional_sa_lists.pf-dev, local.branch_optional_sa_lists.pf-prod, ) diff --git a/fast/stages/1-resman/branch-networking.tf b/fast/stages/1-resman/branch-networking.tf index e4937bb67f..285e0f5001 100644 --- a/fast/stages/1-resman/branch-networking.tf +++ b/fast/stages/1-resman/branch-networking.tf @@ -68,6 +68,7 @@ module "branch-network-prod-folder" { local.branch_optional_sa_lists.dp-prod, local.branch_optional_sa_lists.gke-prod, local.branch_optional_sa_lists.gcve-prod, + local.branch_optional_sa_lists.pf, local.branch_optional_sa_lists.pf-prod, ) # read-only (plan) automation service accounts @@ -75,6 +76,7 @@ module "branch-network-prod-folder" { local.branch_optional_r_sa_lists.dp-prod, local.branch_optional_r_sa_lists.gke-prod, local.branch_optional_r_sa_lists.gcve-prod, + local.branch_optional_r_sa_lists.pf, local.branch_optional_r_sa_lists.pf-prod, ) (local.custom_roles.gcve_network_admin) = local.branch_optional_sa_lists.gcve-prod @@ -97,6 +99,7 @@ module "branch-network-dev-folder" { local.branch_optional_sa_lists.dp-dev, local.branch_optional_sa_lists.gke-dev, local.branch_optional_sa_lists.gcve-dev, + local.branch_optional_sa_lists.pf, local.branch_optional_sa_lists.pf-dev, ) # read-only (plan) automation service accounts @@ -104,6 +107,7 @@ module "branch-network-dev-folder" { local.branch_optional_r_sa_lists.dp-dev, local.branch_optional_r_sa_lists.gke-dev, local.branch_optional_r_sa_lists.gcve-dev, + local.branch_optional_r_sa_lists.pf, local.branch_optional_r_sa_lists.pf-dev, ) (local.custom_roles.gcve_network_admin) = local.branch_optional_sa_lists.gcve-dev diff --git a/fast/stages/1-resman/branch-project-factory.tf b/fast/stages/1-resman/branch-project-factory.tf index 76512ba11f..519fa587b6 100644 --- a/fast/stages/1-resman/branch-project-factory.tf +++ b/fast/stages/1-resman/branch-project-factory.tf @@ -18,6 +18,26 @@ # automation service accounts +module "branch-pf-sa" { + source = "../../../modules/iam-service-account" + count = var.fast_features.project_factory ? 1 : 0 + project_id = var.automation.project_id + name = "resman-pf-0" + display_name = "Terraform project factory main service account." + prefix = var.prefix + iam = { + "roles/iam.serviceAccountTokenCreator" = compact([ + try(module.branch-pf-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"] + } +} + module "branch-pf-dev-sa" { source = "../../../modules/iam-service-account" count = var.fast_features.project_factory ? 1 : 0 @@ -60,6 +80,26 @@ module "branch-pf-prod-sa" { # automation read-only service accounts +module "branch-pf-r-sa" { + source = "../../../modules/iam-service-account" + count = var.fast_features.project_factory ? 1 : 0 + project_id = var.automation.project_id + name = "resman-pf-0r" + display_name = "Terraform project factory main service account (read-only)." + prefix = var.prefix + iam = { + "roles/iam.serviceAccountTokenCreator" = compact([ + try(module.branch-pf-r-sa-cicd[0].iam_email, null) + ]) + } + iam_project_roles = { + (var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"] + } + iam_storage_roles = { + (var.automation.outputs_bucket) = [var.custom_roles["storage_viewer"]] + } +} + module "branch-pf-dev-r-sa" { source = "../../../modules/iam-service-account" count = var.fast_features.project_factory ? 1 : 0 @@ -102,6 +142,21 @@ module "branch-pf-prod-r-sa" { # automation buckets +module "branch-pf-gcs" { + source = "../../../modules/gcs" + count = var.fast_features.project_factory ? 1 : 0 + project_id = var.automation.project_id + name = "resman-pf-0" + prefix = var.prefix + location = var.locations.gcs + storage_class = local.gcs_storage_class + versioning = true + iam = { + "roles/storage.objectAdmin" = [module.branch-pf-sa[0].iam_email] + "roles/storage.objectViewer" = [module.branch-pf-r-sa[0].iam_email] + } +} + module "branch-pf-dev-gcs" { source = "../../../modules/gcs" count = var.fast_features.project_factory ? 1 : 0 diff --git a/fast/stages/1-resman/cicd-project-factory.tf b/fast/stages/1-resman/cicd-project-factory.tf index a5c244818b..92ba95296a 100644 --- a/fast/stages/1-resman/cicd-project-factory.tf +++ b/fast/stages/1-resman/cicd-project-factory.tf @@ -18,6 +18,41 @@ # read-write (apply) SAs used by CI/CD workflows to impersonate automation SAs +module "branch-pf-sa-cicd" { + source = "../../../modules/iam-service-account" + for_each = ( + try(local.cicd_repositories.project_factory.name, null) != null + ? { 0 = local.cicd_repositories.project_factory } + : {} + ) + project_id = var.automation.project_id + name = "pf-resman-pf-1" + display_name = "Terraform CI/CD project factory main service account." + prefix = var.prefix + iam = { + "roles/iam.workloadIdentityUser" = [ + each.value.branch == null + ? format( + local.identity_providers[each.value.identity_provider].principal_repo, + var.automation.federated_identity_pool, + each.value.name + ) + : format( + local.identity_providers[each.value.identity_provider].principal_branch, + var.automation.federated_identity_pool, + each.value.name, + each.value.branch + ) + ] + } + iam_project_roles = { + (var.automation.project_id) = ["roles/logging.logWriter"] + } + iam_storage_roles = { + (var.automation.outputs_bucket) = ["roles/storage.objectViewer"] + } +} + module "branch-pf-dev-sa-cicd" { source = "../../../modules/iam-service-account" for_each = ( @@ -90,6 +125,34 @@ module "branch-pf-prod-sa-cicd" { # read-only (plan) SAs used by CI/CD workflows to impersonate automation SAs +module "branch-pf-r-sa-cicd" { + source = "../../../modules/iam-service-account" + for_each = ( + try(local.cicd_repositories.project_factory.name, null) != null + ? { 0 = local.cicd_repositories.project_factory } + : {} + ) + project_id = var.automation.project_id + name = "resman-pf-1r" + display_name = "Terraform CI/CD project factory main service account (read-only)." + prefix = var.prefix + iam = { + "roles/iam.workloadIdentityUser" = [ + format( + local.identity_providers[each.value.identity_provider].principal_repo, + var.automation.federated_identity_pool, + each.value.name + ) + ] + } + iam_project_roles = { + (var.automation.project_id) = ["roles/logging.logWriter"] + } + iam_storage_roles = { + (var.automation.outputs_bucket) = ["roles/storage.objectViewer"] + } +} + module "branch-pf-dev-r-sa-cicd" { source = "../../../modules/iam-service-account" for_each = ( diff --git a/fast/stages/1-resman/iam.tf b/fast/stages/1-resman/iam.tf index c29969bf49..0a60182aaa 100644 --- a/fast/stages/1-resman/iam.tf +++ b/fast/stages/1-resman/iam.tf @@ -72,6 +72,14 @@ locals { }, # optional billing roles for project factory local.billing_mode != "org" || !var.fast_features.project_factory ? {} : { + sa_pf_billing = { + member = module.branch-pf-sa[0].iam_email + role = "roles/billing.user" + } + sa_pf_costs_manager = { + member = module.branch-pf-sa[0].iam_email + role = "roles/billing.costsManager" + } sa_pf_dev_billing = { member = module.branch-pf-dev-sa[0].iam_email role = "roles/billing.user" @@ -90,8 +98,19 @@ locals { } }, # scoped org policy admin grants for project factory - # TODO: exclude security and networking + # TODO: change to use context and environment tags, and tag bindings in stage 2s !var.fast_features.project_factory || var.root_node != null ? {} : { + sa_pf_conditional_org_policy = { + member = module.branch-pf-sa[0].iam_email + role = "roles/orgpolicy.policyAdmin" + condition = { + title = "org_policy_tag_pf_scoped" + description = "Org policy tag scoped grant for project factory main." + expression = <<-END + resource.matchTag('${local.tag_root}/${var.tag_names.context}', 'project-factory') + END + } + } sa_pf_dev_conditional_org_policy = { member = module.branch-pf-dev-sa[0].iam_email role = "roles/orgpolicy.policyAdmin" diff --git a/fast/stages/1-resman/main.tf b/fast/stages/1-resman/main.tf index cd156224a6..d94321acc4 100644 --- a/fast/stages/1-resman/main.tf +++ b/fast/stages/1-resman/main.tf @@ -29,6 +29,7 @@ locals { gcve-prod = compact([try(module.branch-gcve-prod-sa[0].iam_email, "")]) gke-dev = compact([try(module.branch-gke-dev-sa[0].iam_email, "")]) gke-prod = compact([try(module.branch-gke-prod-sa[0].iam_email, "")]) + pf = compact([try(module.branch-pf-sa[0].iam_email, "")]) pf-dev = compact([try(module.branch-pf-dev-sa[0].iam_email, "")]) pf-prod = compact([try(module.branch-pf-prod-sa[0].iam_email, "")]) } @@ -39,6 +40,7 @@ locals { gcve-prod = compact([try(module.branch-gcve-prod-r-sa[0].iam_email, "")]) gke-dev = compact([try(module.branch-gke-dev-r-sa[0].iam_email, "")]) gke-prod = compact([try(module.branch-gke-prod-r-sa[0].iam_email, "")]) + pf = compact([try(module.branch-pf-r-sa[0].iam_email, "")]) pf-dev = compact([try(module.branch-pf-dev-r-sa[0].iam_email, "")]) pf-prod = compact([try(module.branch-pf-prod-r-sa[0].iam_email, "")]) } diff --git a/fast/stages/1-resman/organization.tf b/fast/stages/1-resman/organization.tf index 6c2fb09c8c..0ba05f9d86 100644 --- a/fast/stages/1-resman/organization.tf +++ b/fast/stages/1-resman/organization.tf @@ -61,6 +61,9 @@ module "organization" { networking = { iam = try(local.tags.context.values.networking.iam, {}) } + project-factory = { + iam = try(local.tags.context.values.project-factory.iam, {}) + } sandbox = { iam = try(local.tags.context.values.sandbox.iam, {}) } diff --git a/fast/stages/1-resman/outputs.tf b/fast/stages/1-resman/outputs.tf index 2834f30e05..9cd19b489d 100644 --- a/fast/stages/1-resman/outputs.tf +++ b/fast/stages/1-resman/outputs.tf @@ -94,6 +94,17 @@ locals { } tf_var_files = local.cicd_workflow_var_files.stage_2 } + project_factory = { + service_accounts = { + apply = try(module.branch-pf-sa-cicd[0].email, null) + plan = try(module.branch-pf-r-sa-cicd[0].email, null) + } + tf_providers_files = { + apply = "3-project-factory-providers.tf" + plan = "3-project-factory-r-providers.tf" + } + tf_var_files = local.cicd_workflow_var_files.stage_3 + } project_factory_dev = { service_accounts = { apply = try(module.branch-pf-dev-sa-cicd[0].email, null) @@ -276,28 +287,40 @@ locals { }) }, !var.fast_features.project_factory ? {} : { + "3-project-factory" = templatefile(local._tpl_providers, { + backend_extra = null + bucket = module.branch-pf-gcs[0].name + name = "project-factory" + sa = module.branch-pf-sa[0].email + }) + "3-project-factory-r" = templatefile(local._tpl_providers, { + backend_extra = null + bucket = module.branch-pf-gcs[0].name + name = "project-factory" + sa = module.branch-pf-r-sa[0].email + }) "3-project-factory-dev" = templatefile(local._tpl_providers, { backend_extra = null bucket = module.branch-pf-dev-gcs[0].name - name = "team-dev" + name = "project-factory-dev" sa = module.branch-pf-dev-sa[0].email }) "3-project-factory-dev-r" = templatefile(local._tpl_providers, { backend_extra = null bucket = module.branch-pf-dev-gcs[0].name - name = "team-dev" + name = "project-factory-dev" sa = module.branch-pf-dev-r-sa[0].email }) "3-project-factory-prod" = templatefile(local._tpl_providers, { backend_extra = null bucket = module.branch-pf-prod-gcs[0].name - name = "team-prod" + name = "project-factory-prod" sa = module.branch-pf-prod-sa[0].email }) "3-project-factory-prod-r" = templatefile(local._tpl_providers, { backend_extra = null bucket = module.branch-pf-prod-gcs[0].name - name = "team-prod" + name = "project-factory-prod" sa = module.branch-pf-prod-r-sa[0].email }) }, @@ -326,6 +349,8 @@ locals { gke-prod-r = try(module.branch-gke-prod-r-sa[0].email, null) networking = module.branch-network-sa.email networking-r = module.branch-network-r-sa.email + project-factory = try(module.branch-pf-sa[0].email, null) + project-factory-r = try(module.branch-pf-r-sa[0].email, null) project-factory-dev = try(module.branch-pf-dev-sa[0].email, null) project-factory-dev-r = try(module.branch-pf-dev-r-sa[0].email, null) project-factory-prod = try(module.branch-pf-prod-sa[0].email, null) @@ -442,6 +467,10 @@ output "project_factories" { bucket = module.branch-pf-dev-gcs[0].name sa = module.branch-pf-dev-sa[0].email } + main = { + bucket = module.branch-pf-gcs[0].name + sa = module.branch-pf-sa[0].email + } prod = { bucket = module.branch-pf-prod-gcs[0].name sa = module.branch-pf-prod-sa[0].email diff --git a/fast/stages/1-resman/variables.tf b/fast/stages/1-resman/variables.tf index aadd3bf7b5..c7a4ff749c 100644 --- a/fast/stages/1-resman/variables.tf +++ b/fast/stages/1-resman/variables.tf @@ -62,6 +62,12 @@ variable "cicd_repositories" { branch = optional(string) identity_provider = optional(string) })) + project_factory = optional(object({ + name = string + type = string + branch = optional(string) + identity_provider = optional(string) + })) project_factory_dev = optional(object({ name = string type = string diff --git a/fast/stages/2-networking-a-simple/README.md b/fast/stages/2-networking-a-simple/README.md index 860311148b..5c32c0fa0c 100644 --- a/fast/stages/2-networking-a-simple/README.md +++ b/fast/stages/2-networking-a-simple/README.md @@ -470,7 +470,7 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS | [outputs_location](variables.tf#L92) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string | | null | | | [psa_ranges](variables.tf#L98) | IP ranges used for Private Service Access (CloudSQL, etc.). | object({…}) | | {} | | | [regions](variables.tf#L118) | Region definitions. | object({…}) | | {…} | | -| [service_accounts](variables-fast.tf#L89) | Automation service accounts in name => email format. | object({…}) | | null | 1-resman | +| [service_accounts](variables-fast.tf#L89) | Automation service accounts in name => email format. | object({…}) | | null | 1-resman | | [spoke_configs](variables.tf#L130) | Spoke connectivity configurations. | object({…}) | | {…} | | | [vpn_onprem_primary_config](variables.tf#L180) | VPN gateway configuration for onprem interconnection in the primary region. | object({…}) | | null | | diff --git a/fast/stages/2-networking-a-simple/net-dev.tf b/fast/stages/2-networking-a-simple/net-dev.tf index 12b301e9bc..7322bce135 100644 --- a/fast/stages/2-networking-a-simple/net-dev.tf +++ b/fast/stages/2-networking-a-simple/net-dev.tf @@ -46,6 +46,7 @@ module "dev-spoke-project" { iam = { "roles/dns.admin" = compact([ try(local.service_accounts.gke-dev, null), + try(local.service_accounts.project-factory, null), try(local.service_accounts.project-factory-dev, null), try(local.service_accounts.project-factory-prod, null), ]) @@ -56,6 +57,7 @@ module "dev-spoke-project" { role = "roles/resourcemanager.projectIamAdmin" members = compact([ try(local.service_accounts.data-platform-dev, null), + try(local.service_accounts.project-factory, null), try(local.service_accounts.project-factory-dev, null), try(local.service_accounts.project-factory-prod, null), try(local.service_accounts.gke-dev, null), diff --git a/fast/stages/2-networking-a-simple/net-landing.tf b/fast/stages/2-networking-a-simple/net-landing.tf index b1f1249753..3c4c7c3196 100644 --- a/fast/stages/2-networking-a-simple/net-landing.tf +++ b/fast/stages/2-networking-a-simple/net-landing.tf @@ -34,9 +34,11 @@ module "landing-project" { } iam = { "roles/dns.admin" = compact([ + try(local.service_accounts.project-factory, null), try(local.service_accounts.project-factory-prod, null) ]) (local.custom_roles.service_project_network_admin) = compact([ + try(local.service_accounts.project-factory, null), try(local.service_accounts.project-factory-prod, null) ]) } diff --git a/fast/stages/2-networking-a-simple/net-prod.tf b/fast/stages/2-networking-a-simple/net-prod.tf index 2e1f3f7ad1..fe2d0b6b55 100644 --- a/fast/stages/2-networking-a-simple/net-prod.tf +++ b/fast/stages/2-networking-a-simple/net-prod.tf @@ -46,6 +46,7 @@ module "prod-spoke-project" { iam = { "roles/dns.admin" = compact([ try(local.service_accounts.gke-prod, null), + try(local.service_accounts.project-factory, null), try(local.service_accounts.project-factory-prod, null), ]) } @@ -55,6 +56,7 @@ module "prod-spoke-project" { role = "roles/resourcemanager.projectIamAdmin" members = compact([ try(local.service_accounts.data-platform-prod, null), + try(local.service_accounts.project-factory, null), try(local.service_accounts.project-factory-prod, null), try(local.service_accounts.gke-prod, null), ]) diff --git a/fast/stages/2-networking-a-simple/variables-fast.tf b/fast/stages/2-networking-a-simple/variables-fast.tf index 71805b067c..85f102368d 100644 --- a/fast/stages/2-networking-a-simple/variables-fast.tf +++ b/fast/stages/2-networking-a-simple/variables-fast.tf @@ -94,6 +94,7 @@ variable "service_accounts" { data-platform-prod = string gke-dev = string gke-prod = string + project-factory = string project-factory-dev = string project-factory-prod = string }) diff --git a/fast/stages/2-networking-b-nva/README.md b/fast/stages/2-networking-b-nva/README.md index 7997d586dc..5b28c70aa9 100644 --- a/fast/stages/2-networking-b-nva/README.md +++ b/fast/stages/2-networking-b-nva/README.md @@ -534,7 +534,7 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS | [outputs_location](variables.tf#L114) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string | | null | | | [psa_ranges](variables.tf#L120) | IP ranges used for Private Service Access (e.g. CloudSQL). Ranges is in name => range format. | object({…}) | | {} | | | [regions](variables.tf#L140) | Region definitions. | object({…}) | | {…} | | -| [service_accounts](variables-fast.tf#L87) | Automation service accounts in name => email format. | object({…}) | | null | 1-resman | +| [service_accounts](variables-fast.tf#L87) | Automation service accounts in name => email format. | object({…}) | | null | 1-resman | | [vpn_onprem_primary_config](variables.tf#L152) | VPN gateway configuration for onprem interconnection in the primary region. | object({…}) | | null | | | [vpn_onprem_secondary_config](variables.tf#L195) | VPN gateway configuration for onprem interconnection in the secondary region. | object({…}) | | null | | diff --git a/fast/stages/2-networking-b-nva/net-dev.tf b/fast/stages/2-networking-b-nva/net-dev.tf index d887f0729d..1efc3ea775 100644 --- a/fast/stages/2-networking-b-nva/net-dev.tf +++ b/fast/stages/2-networking-b-nva/net-dev.tf @@ -45,6 +45,7 @@ module "dev-spoke-project" { iam = { "roles/dns.admin" = compact([ try(local.service_accounts.gke-dev, null), + try(local.service_accounts.project-factory, null), try(local.service_accounts.project-factory-dev, null), try(local.service_accounts.project-factory-prod, null), ]) @@ -55,6 +56,7 @@ module "dev-spoke-project" { role = "roles/resourcemanager.projectIamAdmin" members = compact([ try(local.service_accounts.data-platform-dev, null), + try(local.service_accounts.project-factory, null), try(local.service_accounts.project-factory-dev, null), try(local.service_accounts.project-factory-prod, null), try(local.service_accounts.gke-dev, null), diff --git a/fast/stages/2-networking-b-nva/net-landing.tf b/fast/stages/2-networking-b-nva/net-landing.tf index 34f24a558a..faff17982e 100644 --- a/fast/stages/2-networking-b-nva/net-landing.tf +++ b/fast/stages/2-networking-b-nva/net-landing.tf @@ -40,9 +40,11 @@ module "landing-project" { } iam = { "roles/dns.admin" = compact([ + try(local.service_accounts.project-factory, null), try(local.service_accounts.project-factory-prod, null) ]) (local.custom_roles.service_project_network_admin) = compact([ + try(local.service_accounts.project-factory, null), try(local.service_accounts.project-factory-prod, null) ]) } diff --git a/fast/stages/2-networking-b-nva/net-prod.tf b/fast/stages/2-networking-b-nva/net-prod.tf index 9e92ef200c..1a1d6aa34e 100644 --- a/fast/stages/2-networking-b-nva/net-prod.tf +++ b/fast/stages/2-networking-b-nva/net-prod.tf @@ -45,6 +45,7 @@ module "prod-spoke-project" { iam = { "roles/dns.admin" = compact([ try(local.service_accounts.gke-prod, null), + try(local.service_accounts.project-factory, null), try(local.service_accounts.project-factory-prod, null), ]) } @@ -54,6 +55,7 @@ module "prod-spoke-project" { role = "roles/resourcemanager.projectIamAdmin" members = compact([ try(local.service_accounts.data-platform-prod, null), + try(local.service_accounts.project-factory, null), try(local.service_accounts.project-factory-prod, null), try(local.service_accounts.gke-prod, null), ]) diff --git a/fast/stages/2-networking-b-nva/variables-fast.tf b/fast/stages/2-networking-b-nva/variables-fast.tf index 8185e94f5e..e3c44bf631 100644 --- a/fast/stages/2-networking-b-nva/variables-fast.tf +++ b/fast/stages/2-networking-b-nva/variables-fast.tf @@ -92,6 +92,7 @@ variable "service_accounts" { data-platform-prod = string gke-dev = string gke-prod = string + project-factory = string project-factory-dev = string project-factory-prod = string }) diff --git a/fast/stages/2-networking-c-separate-envs/README.md b/fast/stages/2-networking-c-separate-envs/README.md index 9bb9fea641..732c3d7aa4 100644 --- a/fast/stages/2-networking-c-separate-envs/README.md +++ b/fast/stages/2-networking-c-separate-envs/README.md @@ -354,7 +354,7 @@ Regions are defined via the `regions` variable which sets up a mapping between t | [outputs_location](variables.tf#L87) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string | | null | | | [psa_ranges](variables.tf#L93) | IP ranges used for Private Service Access (e.g. CloudSQL). | object({…}) | | {} | | | [regions](variables.tf#L113) | Region definitions. | object({…}) | | {…} | | -| [service_accounts](variables-fast.tf#L78) | Automation service accounts in name => email format. | object({…}) | | null | 1-resman | +| [service_accounts](variables-fast.tf#L78) | Automation service accounts in name => email format. | object({…}) | | null | 1-resman | | [vpn_onprem_dev_primary_config](variables.tf#L123) | VPN gateway configuration for onprem interconnection from dev in the primary region. | object({…}) | | null | | | [vpn_onprem_prod_primary_config](variables.tf#L166) | VPN gateway configuration for onprem interconnection from prod in the primary region. | object({…}) | | null | | diff --git a/fast/stages/2-networking-c-separate-envs/net-dev.tf b/fast/stages/2-networking-c-separate-envs/net-dev.tf index addc5a104b..c129576324 100644 --- a/fast/stages/2-networking-c-separate-envs/net-dev.tf +++ b/fast/stages/2-networking-c-separate-envs/net-dev.tf @@ -45,6 +45,7 @@ module "dev-spoke-project" { iam = { "roles/dns.admin" = compact([ try(local.service_accounts.gke-dev, null), + try(local.service_accounts.project-factory, null), try(local.service_accounts.project-factory-dev, null), try(local.service_accounts.project-factory-prod, null), ]) @@ -55,6 +56,7 @@ module "dev-spoke-project" { role = "roles/resourcemanager.projectIamAdmin" members = compact([ try(local.service_accounts.data-platform-dev, null), + try(local.service_accounts.project-factory, null), try(local.service_accounts.project-factory-dev, null), try(local.service_accounts.project-factory-prod, null), try(local.service_accounts.gke-dev, null), diff --git a/fast/stages/2-networking-c-separate-envs/net-prod.tf b/fast/stages/2-networking-c-separate-envs/net-prod.tf index c0dbff37df..552d31184f 100644 --- a/fast/stages/2-networking-c-separate-envs/net-prod.tf +++ b/fast/stages/2-networking-c-separate-envs/net-prod.tf @@ -45,6 +45,7 @@ module "prod-spoke-project" { iam = { "roles/dns.admin" = compact([ try(local.service_accounts.gke-prod, null), + try(local.service_accounts.project-factory, null), try(local.service_accounts.project-factory-prod, null) ]) } @@ -54,6 +55,7 @@ module "prod-spoke-project" { role = "roles/resourcemanager.projectIamAdmin" members = compact([ try(local.service_accounts.data-platform-prod, null), + try(local.service_accounts.project-factory, null), try(local.service_accounts.project-factory-prod, null), try(local.service_accounts.gke-prod, null), ]) diff --git a/fast/stages/2-networking-c-separate-envs/variables-fast.tf b/fast/stages/2-networking-c-separate-envs/variables-fast.tf index 0ec719f9f6..bdb3ae8d7f 100644 --- a/fast/stages/2-networking-c-separate-envs/variables-fast.tf +++ b/fast/stages/2-networking-c-separate-envs/variables-fast.tf @@ -83,6 +83,7 @@ variable "service_accounts" { data-platform-prod = string gke-dev = string gke-prod = string + project-factory = string project-factory-dev = string project-factory-prod = string }) diff --git a/fast/stages/2-security/README.md b/fast/stages/2-security/README.md index bb88d02cbb..98c1544213 100644 --- a/fast/stages/2-security/README.md +++ b/fast/stages/2-security/README.md @@ -242,7 +242,7 @@ Some references that might be useful in setting up this stage: | [folder_ids](variables-fast.tf#L45) | Folder name => id mappings, the 'security' folder name must exist. | object({…}) | ✓ | | 1-resman | | [organization](variables-fast.tf#L63) | Organization details. | object({…}) | ✓ | | 0-bootstrap | | [prefix](variables-fast.tf#L73) | Prefix used for resources that need unique names. Use a maximum of 9 chars for organizations, and 11 chars for tenants. | string | ✓ | | 0-bootstrap | -| [service_accounts](variables-fast.tf#L97) | Automation service accounts that can assign the encrypt/decrypt roles on keys. | object({…}) | ✓ | | 1-resman | +| [service_accounts](variables-fast.tf#L97) | Automation service accounts that can assign the encrypt/decrypt roles on keys. | object({…}) | ✓ | | 1-resman | | [access_policy](variables-fast.tf#L17) | Access policy id for tenant-level VPC-SC configurations. | number | | null | 0-bootstrap | | [essential_contacts](variables.tf#L17) | Email used for essential contacts, unset if null. | string | | null | | | [factories_config](variables.tf#L23) | Paths to folders that enable factory functionality. | object({…}) | | {} | | diff --git a/fast/stages/2-security/core-dev.tf b/fast/stages/2-security/core-dev.tf index 6f71318daf..b44aca42dd 100644 --- a/fast/stages/2-security/core-dev.tf +++ b/fast/stages/2-security/core-dev.tf @@ -18,6 +18,7 @@ locals { dev_kms_restricted_admins = [ for sa in distinct(compact([ var.service_accounts.data-platform-dev, + var.service_accounts.project-factory, var.service_accounts.project-factory-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 1d53624950..393627a477 100644 --- a/fast/stages/2-security/core-prod.tf +++ b/fast/stages/2-security/core-prod.tf @@ -18,6 +18,7 @@ locals { prod_kms_restricted_admins = [ for sa in distinct(compact([ var.service_accounts.data-platform-prod, + var.service_accounts.project-factory, var.service_accounts.project-factory-prod ])) : "serviceAccount:${sa}" ] diff --git a/fast/stages/2-security/variables-fast.tf b/fast/stages/2-security/variables-fast.tf index 048e2d5328..063048a635 100644 --- a/fast/stages/2-security/variables-fast.tf +++ b/fast/stages/2-security/variables-fast.tf @@ -100,6 +100,7 @@ variable "service_accounts" { type = object({ data-platform-dev = string data-platform-prod = string + project-factory = string project-factory-dev = string project-factory-prod = string }) diff --git a/tests/fast/stages/s1_resman/checklist.yaml b/tests/fast/stages/s1_resman/checklist.yaml index 0e21a222d3..eed5d8498c 100644 --- a/tests/fast/stages/s1_resman/checklist.yaml +++ b/tests/fast/stages/s1_resman/checklist.yaml @@ -427,6 +427,6 @@ counts: google_storage_bucket_object: 5 google_tags_tag_binding: 4 google_tags_tag_key: 2 - google_tags_tag_value: 8 + google_tags_tag_value: 9 modules: 63 - resources: 172 + resources: 173 diff --git a/tests/fast/stages/s1_resman/simple.yaml b/tests/fast/stages/s1_resman/simple.yaml index 07af2b0cb4..06108848e3 100644 --- a/tests/fast/stages/s1_resman/simple.yaml +++ b/tests/fast/stages/s1_resman/simple.yaml @@ -25,6 +25,6 @@ counts: google_storage_bucket_object: 5 google_tags_tag_binding: 4 google_tags_tag_key: 2 - google_tags_tag_value: 8 + google_tags_tag_value: 9 modules: 11 - resources: 74 + resources: 75 diff --git a/tests/fast/stages/s2_networking_a_simple/simple.tfvars b/tests/fast/stages/s2_networking_a_simple/simple.tfvars index 543bcfb54c..74d3dfb36a 100644 --- a/tests/fast/stages/s2_networking_a_simple/simple.tfvars +++ b/tests/fast/stages/s2_networking_a_simple/simple.tfvars @@ -26,6 +26,7 @@ service_accounts = { data-platform-prod = "string" gke-dev = "string" gke-prod = "string" + project-factory = "string" project-factory-dev = "string" project-factory-prod = "string" } diff --git a/tests/fast/stages/s2_networking_a_simple/vpn.tfvars b/tests/fast/stages/s2_networking_a_simple/vpn.tfvars index c6125171b7..e37c0436c0 100644 --- a/tests/fast/stages/s2_networking_a_simple/vpn.tfvars +++ b/tests/fast/stages/s2_networking_a_simple/vpn.tfvars @@ -32,6 +32,7 @@ service_accounts = { data-platform-prod = "string" gke-dev = "string" gke-prod = "string" + project-factory = "string" project-factory-dev = "string" project-factory-prod = "string" } diff --git a/tests/fast/stages/s2_networking_b_nva/ncc-ra.tfvars b/tests/fast/stages/s2_networking_b_nva/ncc-ra.tfvars index 2b3d63f87e..78af2e15c8 100644 --- a/tests/fast/stages/s2_networking_b_nva/ncc-ra.tfvars +++ b/tests/fast/stages/s2_networking_b_nva/ncc-ra.tfvars @@ -28,6 +28,7 @@ service_accounts = { data-platform-prod = "string" gke-dev = "string" gke-prod = "string" + project-factory = "string" project-factory-dev = "string" project-factory-prod = "string" } diff --git a/tests/fast/stages/s2_networking_b_nva/simple.tfvars b/tests/fast/stages/s2_networking_b_nva/simple.tfvars index d1dff817d7..8be6685020 100644 --- a/tests/fast/stages/s2_networking_b_nva/simple.tfvars +++ b/tests/fast/stages/s2_networking_b_nva/simple.tfvars @@ -28,6 +28,7 @@ service_accounts = { data-platform-prod = "string" gke-dev = "string" gke-prod = "string" + project-factory = "string" project-factory-dev = "string" project-factory-prod = "string" } diff --git a/tests/fast/stages/s2_networking_c_separate_envs/simple.tfvars b/tests/fast/stages/s2_networking_c_separate_envs/simple.tfvars index 8522e2b2f0..e72ed28f81 100644 --- a/tests/fast/stages/s2_networking_c_separate_envs/simple.tfvars +++ b/tests/fast/stages/s2_networking_c_separate_envs/simple.tfvars @@ -27,6 +27,7 @@ service_accounts = { data-platform-prod = "string" gke-dev = "string" gke-prod = "string" + project-factory = "string" project-factory-dev = "string" project-factory-prod = "string" } diff --git a/tests/fast/stages/s2_security/simple.tfvars b/tests/fast/stages/s2_security/simple.tfvars index 65558e1f9e..cc2bb42b4b 100644 --- a/tests/fast/stages/s2_security/simple.tfvars +++ b/tests/fast/stages/s2_security/simple.tfvars @@ -28,6 +28,7 @@ service_accounts = { security = "foobar@iam.gserviceaccount.com" data-platform-dev = "foobar@iam.gserviceaccount.com" data-platform-prod = "foobar@iam.gserviceaccount.com" + project-factory = "foobar@iam.gserviceaccount.com" project-factory-dev = "foobar@iam.gserviceaccount.com" project-factory-prod = "foobar@iam.gserviceaccount.com" }