diff --git a/fast/stages/0-bootstrap/README.md b/fast/stages/0-bootstrap/README.md
index 1ad86d0d5e..51e59a8ace 100644
--- a/fast/stages/0-bootstrap/README.md
+++ b/fast/stages/0-bootstrap/README.md
@@ -626,7 +626,7 @@ The `fast_features` variable consists of 4 toggles:
| name | description | type | required | default | producer |
|---|---|:---:|:---:|:---:|:---:|
| [billing_account](variables.tf#L17) | Billing account id. If billing account is not part of the same org set `is_org_level` to `false`. To disable handling of billing IAM roles set `no_iam` to `true`. | object({…})
| ✓ | | |
-| [organization](variables.tf#L229) | Organization details. | object({…})
| ✓ | | |
+| [organization](variables.tf#L229) | Organization details. | object({…})
| ✓ | | |
| [prefix](variables.tf#L244) | Prefix used for resources that need unique names. Use 9 characters or less. | string
| ✓ | | |
| [bootstrap_user](variables.tf#L27) | Email of the nominal user running this stage for the first time. | string
| | null
| |
| [cicd_repositories](variables.tf#L33) | CI/CD repository configuration. Identity providers reference keys in the `federated_identity_providers` variable. Set to null to disable, or set individual repositories to null if not needed. | object({…})
| | null
| |
diff --git a/fast/stages/0-bootstrap/data/org-policies/compute.yaml b/fast/stages/0-bootstrap/data/org-policies/compute.yaml
index 652ac64569..98fa6c6512 100644
--- a/fast/stages/0-bootstrap/data/org-policies/compute.yaml
+++ b/fast/stages/0-bootstrap/data/org-policies/compute.yaml
@@ -34,22 +34,25 @@ compute.trustedImageProjects:
rules:
- allow:
values:
- - "projects/centos-cloud"
- - "projects/cos-cloud"
- - "projects/debian-cloud"
- - "projects/fedora-cloud"
- - "projects/fedora-coreos-cloud"
- - "projects/opensuse-cloud"
- - "projects/rhel-cloud"
- - "projects/rhel-sap-cloud"
- - "projects/rocky-linux-cloud"
- - "projects/suse-cloud"
- - "projects/suse-byos-cloud"
- - "projects/suse-sap-cloud"
- - "projects/ubuntu-os-cloud"
- - "projects/ubuntu-os-pro-cloud"
- - "projects/windows-cloud"
- - "projects/windows-sql-cloud"
+ - "is:projects/centos-cloud"
+ - "is:projects/cos-cloud"
+ - "is:projects/debian-cloud"
+ - "is:projects/fedora-cloud"
+ - "is:projects/fedora-coreos-cloud"
+ - "is:projects/opensuse-cloud"
+ - "is:projects/rhel-cloud"
+ - "is:projects/rhel-sap-cloud"
+ - "is:projects/rocky-linux-cloud"
+ - "is:projects/suse-cloud"
+ - "is:projects/suse-sap-cloud"
+ - "is:projects/ubuntu-os-cloud"
+ - "is:projects/ubuntu-os-pro-cloud"
+ - "is:projects/windows-cloud"
+ - "is:projects/windows-sql-cloud"
+ - "is:projects/confidential-vm-images"
+ - "is:projects/backupdr-images"
+ - "is:projects/deeplearning-platform-release"
+ - "is:projects/serverless-vpc-access-images"
# compute.disableInternetNetworkEndpointGroup:
# rules:
diff --git a/fast/stages/0-bootstrap/data/org-policies/serverless.yaml b/fast/stages/0-bootstrap/data/org-policies/serverless.yaml
index 1fce1a9b05..1c07905a1d 100644
--- a/fast/stages/0-bootstrap/data/org-policies/serverless.yaml
+++ b/fast/stages/0-bootstrap/data/org-policies/serverless.yaml
@@ -10,7 +10,6 @@ run.allowedIngress:
rules:
- allow:
values:
- - is:internal
- is:internal-and-cloud-load-balancing
# run.allowedVPCEgress:
# rules:
diff --git a/fast/stages/0-bootstrap/organization-iam.tf b/fast/stages/0-bootstrap/organization-iam.tf
index 514d9af347..6ca44a24da 100644
--- a/fast/stages/0-bootstrap/organization-iam.tf
+++ b/fast/stages/0-bootstrap/organization-iam.tf
@@ -22,7 +22,7 @@ locals {
"roles/billing.creator"
]
# domain IAM bindings
- iam_domain_bindings = {
+ iam_domain_bindings = var.organization.domain == null ? {} : {
"domain:${var.organization.domain}" = {
authoritative = ["roles/browser"]
additive = []
diff --git a/fast/stages/0-bootstrap/organization.tf b/fast/stages/0-bootstrap/organization.tf
index 8cdb70b217..44bd78c2dd 100644
--- a/fast/stages/0-bootstrap/organization.tf
+++ b/fast/stages/0-bootstrap/organization.tf
@@ -46,7 +46,7 @@ locals {
]
])
drs_domains = concat(
- [var.organization.customer_id],
+ var.organization.customer_id == null ? [] : [var.organization.customer_id],
var.org_policies_config.constraints.allowed_policy_member_domains
)
drs_tag_name = "${var.organization.id}/${var.org_policies_config.tag_name}"
@@ -104,26 +104,28 @@ locals {
iam_roles_additive = distinct([
for k, v in local._iam_bindings_additive : v.role
])
- # import org policies only when not using bootstrap user
- import_org_policies = var.org_policies_config.import_defaults && var.bootstrap_user != null
}
# TODO: add a check block to ensure our custom roles exist in the factory files
# import org policy constraints enabled by default in new orgs since February 2024
import {
- for_each = !local.import_org_policies ? toset([]) : toset([
- "compute.requireOsLogin",
- "compute.skipDefaultNetworkCreation",
- "compute.vmExternalIpAccess",
- "iam.allowedPolicyMemberDomains",
- "iam.automaticIamGrantsForDefaultServiceAccounts",
- "iam.disableServiceAccountKeyCreation",
- "iam.disableServiceAccountKeyUpload",
- "sql.restrictAuthorizedNetworks",
- "sql.restrictPublicIp",
- "storage.uniformBucketLevelAccess",
- ])
+ for_each = (
+ !var.org_policies_config.import_defaults || var.bootstrap_user != null
+ ? toset([])
+ : toset([
+ "compute.requireOsLogin",
+ "compute.skipDefaultNetworkCreation",
+ "compute.vmExternalIpAccess",
+ "iam.allowedPolicyMemberDomains",
+ "iam.automaticIamGrantsForDefaultServiceAccounts",
+ "iam.disableServiceAccountKeyCreation",
+ "iam.disableServiceAccountKeyUpload",
+ "sql.restrictAuthorizedNetworks",
+ "sql.restrictPublicIp",
+ "storage.uniformBucketLevelAccess",
+ ])
+ )
id = "organizations/${var.organization.id}/policies/${each.key}"
to = module.organization.google_org_policy_policy.default[each.key]
}
@@ -151,34 +153,48 @@ module "organization" {
var.iam_bindings_additive
)
# delegated role grant for resource manager service account
- iam_bindings = {
- organization_iam_admin_conditional = {
- members = [module.automation-tf-resman-sa.iam_email]
- role = module.organization.custom_role_id["organization_iam_admin"]
- condition = {
- expression = format(
- "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])",
- join(",", formatlist("'%s'", concat(
- [
+ iam_bindings = merge(
+ {
+ organization_iam_admin_conditional = {
+ members = [module.automation-tf-resman-sa.iam_email]
+ role = module.organization.custom_role_id["organization_iam_admin"]
+ condition = {
+ expression = format(
+ "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])",
+ join(",", formatlist("'%s'", [
"roles/accesscontextmanager.policyAdmin",
"roles/compute.orgFirewallPolicyAdmin",
"roles/compute.xpnAdmin",
"roles/orgpolicy.policyAdmin",
+ "roles/orgpolicy.policyViewer",
"roles/resourcemanager.organizationViewer",
module.organization.custom_role_id["tenant_network_admin"]
- ],
- local.billing_mode == "org" ? [
+ ]))
+ )
+ title = "automation_sa_delegated_grants"
+ description = "Automation service account delegated grants."
+ }
+ }
+ },
+ local.billing_mode != "org" ? {} : {
+ organization_billing_conditional = {
+ members = [module.automation-tf-resman-sa.iam_email]
+ role = module.organization.custom_role_id["organization_iam_admin"]
+ condition = {
+ expression = format(
+ "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])",
+ join(",", formatlist("'%s'", [
"roles/billing.admin",
"roles/billing.costsManager",
"roles/billing.user",
- ] : []
- )))
- )
- title = "automation_sa_delegated_grants"
- description = "Automation service account delegated grants."
+ ]))
+ )
+ title = "automation_sa_delegated_grants"
+ description = "Automation service account delegated grants."
+ }
}
}
- }
+ )
custom_roles = var.custom_roles
factories_config = {
custom_roles = var.factories_config.custom_roles
diff --git a/fast/stages/0-bootstrap/variables.tf b/fast/stages/0-bootstrap/variables.tf
index a3d0bb53c4..d2d47a1fee 100644
--- a/fast/stages/0-bootstrap/variables.tf
+++ b/fast/stages/0-bootstrap/variables.tf
@@ -229,9 +229,9 @@ variable "org_policies_config" {
variable "organization" {
description = "Organization details."
type = object({
- domain = string
id = number
- customer_id = string
+ domain = optional(string)
+ customer_id = optional(string)
})
}
diff --git a/fast/stages/1-resman/README.md b/fast/stages/1-resman/README.md
index a28451a149..a84c704f9d 100644
--- a/fast/stages/1-resman/README.md
+++ b/fast/stages/1-resman/README.md
@@ -254,7 +254,7 @@ This is an example that shows how to populate the relevant variables.
```tfvars
tenants = {
tn0 = {
- admin_group_email = "tn-0-admins@tenant.example.org"
+ admin_principal = "group:tn-0-admins@tenant.example.org"
descriptive_name = "Tenant 0"
# an optional billing account and org can be specified for the tenant
organization = {
@@ -264,7 +264,7 @@ tenants = {
}
}
tnq = {
- admin_group_email = "tn-1-admins@example.org"
+ admin_principal = "group:tn-1-admins@example.org"
descriptive_name = "Tenant 1"
}
}
diff --git a/fast/stages/1-resman/branch-security.tf b/fast/stages/1-resman/branch-security.tf
index b688d935a6..5e8288128e 100644
--- a/fast/stages/1-resman/branch-security.tf
+++ b/fast/stages/1-resman/branch-security.tf
@@ -34,8 +34,8 @@ module "branch-security-folder" {
"roles/resourcemanager.folderAdmin" = [module.branch-security-sa.iam_email]
"roles/resourcemanager.projectCreator" = [module.branch-security-sa.iam_email]
# read-only (plan) automation service account
- "roles/viewer" = [module.branch-network-r-sa.iam_email]
- "roles/resourcemanager.folderViewer" = [module.branch-network-r-sa.iam_email]
+ "roles/viewer" = [module.branch-security-r-sa.iam_email]
+ "roles/resourcemanager.folderViewer" = [module.branch-security-r-sa.iam_email]
}
tag_bindings = {
context = try(
diff --git a/fast/stages/1-resman/branch-tenants.tf b/fast/stages/1-resman/branch-tenants.tf
index aab02c0d37..150f8eeed8 100644
--- a/fast/stages/1-resman/branch-tenants.tf
+++ b/fast/stages/1-resman/branch-tenants.tf
@@ -21,7 +21,7 @@
locals {
tenant_iam = {
for k, v in var.tenants : k => [
- "group:${v.admin_group_email}",
+ v.admin_principal,
module.tenant-self-iac-sa[k].iam_email
]
}
diff --git a/fast/stages/1-resman/organization-iam.tf b/fast/stages/1-resman/organization-iam.tf
index 28764a25cf..c5c17b909d 100644
--- a/fast/stages/1-resman/organization-iam.tf
+++ b/fast/stages/1-resman/organization-iam.tf
@@ -127,13 +127,13 @@ locals {
},
{
for k, v in var.tenants : "org-viewer-tenant_${k}_admin" => {
- member = "group:${v.admin_group_email}"
+ member = v.admin_principal
role = "roles/resourcemanager.organizationViewer"
}
},
local.billing_mode != "org" ? {} : {
for k, v in var.tenants : "billing_user-tenant_${k}_billing_admin" => {
- member = "group:${v.admin_group_email}"
+ member = v.admin_principal
role = "roles/billing.user"
}
},
diff --git a/tests/fast/stages/s0_bootstrap/checklist.yaml b/tests/fast/stages/s0_bootstrap/checklist.yaml
index a1f92cb04d..a111eb02c4 100644
--- a/tests/fast/stages/s0_bootstrap/checklist.yaml
+++ b/tests/fast/stages/s0_bootstrap/checklist.yaml
@@ -194,7 +194,7 @@ values:
module.organization.google_organization_iam_binding.bindings["organization_iam_admin_conditional"]:
condition:
- description: Automation service account delegated grants.
- expression: api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly(['roles/accesscontextmanager.policyAdmin','roles/compute.orgFirewallPolicyAdmin','roles/compute.xpnAdmin','roles/orgpolicy.policyAdmin','roles/resourcemanager.organizationViewer','organizations/123456789012/roles/tenantNetworkAdmin','roles/billing.admin','roles/billing.costsManager','roles/billing.user'])
+ expression: api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly(['roles/accesscontextmanager.policyAdmin','roles/compute.orgFirewallPolicyAdmin','roles/compute.xpnAdmin','roles/orgpolicy.policyAdmin','roles/orgpolicy.policyViewer','roles/resourcemanager.organizationViewer','organizations/123456789012/roles/tenantNetworkAdmin'])
title: automation_sa_delegated_grants
members:
- serviceAccount:fast-prod-resman-0@fast-prod-iac-core-0.iam.gserviceaccount.com
@@ -363,7 +363,7 @@ counts:
google_logging_organization_sink: 3
google_logging_project_bucket_config: 3
google_org_policy_policy: 20
- google_organization_iam_binding: 26
+ google_organization_iam_binding: 27
google_organization_iam_custom_role: 6
google_organization_iam_member: 35
google_project: 3
@@ -381,4 +381,4 @@ counts:
google_tags_tag_key: 1
google_tags_tag_value: 1
modules: 16
- resources: 190
+ resources: 191
diff --git a/tests/fast/stages/s0_bootstrap/simple.yaml b/tests/fast/stages/s0_bootstrap/simple.yaml
index 0a1e628a9a..2180aa4540 100644
--- a/tests/fast/stages/s0_bootstrap/simple.yaml
+++ b/tests/fast/stages/s0_bootstrap/simple.yaml
@@ -42,7 +42,7 @@ counts:
google_logging_organization_sink: 3
google_logging_project_bucket_config: 3
google_org_policy_policy: 20
- google_organization_iam_binding: 26
+ google_organization_iam_binding: 27
google_organization_iam_custom_role: 6
google_organization_iam_member: 22
google_project: 3
@@ -61,7 +61,7 @@ counts:
google_tags_tag_value: 1
local_file: 7
modules: 15
- resources: 181
+ resources: 182
outputs:
custom_roles: