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"
}