diff --git a/fast/stages/1-resman/README.md b/fast/stages/1-resman/README.md
index 533b66b4f..d85829e00 100644
--- a/fast/stages/1-resman/README.md
+++ b/fast/stages/1-resman/README.md
@@ -273,29 +273,29 @@ A full reference of IAM roles managed by this stage [is available here](./IAM.md
| [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#L122) | Configuration for the resource factories or external data. | object({…}) | | {} | |
-| [fast_features](variables.tf#L133) | Selective control for top-level FAST features. | object({…}) | | {} | |
-| [folder_iam](variables.tf#L145) | Authoritative IAM for top-level folders. | object({…}) | | {} | |
+| [fast_features](variables.tf#L133) | Selective control for top-level FAST features. | object({…}) | | {} | |
+| [folder_iam](variables.tf#L146) | Authoritative IAM for top-level folders. | object({…}) | | {} | |
| [groups](variables-fast.tf#L67) | 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#L82) | Optional locations for GCS, BigQuery, and logging buckets created here. | object({…}) | | {} | 0-bootstrap |
-| [outputs_location](variables.tf#L159) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable. | string | | null | |
+| [outputs_location](variables.tf#L160) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable. | string | | null | |
| [root_node](variables-fast.tf#L132) | Root node for the hierarchy, if running in tenant mode. | string | | null | 0-bootstrap |
-| [tag_names](variables.tf#L165) | Customized names for resource management tags. | object({…}) | | {} | |
-| [tags](variables.tf#L179) | 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#L200) | 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#L166) | Customized names for resource management tags. | object({…}) | | {} | |
+| [tags](variables.tf#L180) | 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#L201) | 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#L374) | WIF configuration for CI/CD repositories. | | |
-| [dataplatform](outputs.tf#L388) | Data for the Data Platform stage. | | |
-| [folder_ids](outputs.tf#L404) | Folder ids. | | |
-| [gcve](outputs.tf#L409) | Data for the GCVE stage. | | 03-gcve |
-| [gke_multitenant](outputs.tf#L430) | Data for the GKE multitenant stage. | | 03-gke-multitenant |
-| [networking](outputs.tf#L451) | Data for the networking stage. | | |
-| [project_factories](outputs.tf#L460) | Data for the project factories stage. | | |
-| [providers](outputs.tf#L479) | Terraform provider files for this stage and dependent stages. | ✓ | 02-networking · 02-security · 03-dataplatform · 03-network-security |
-| [sandbox](outputs.tf#L486) | Data for the sandbox stage. | | xx-sandbox |
-| [security](outputs.tf#L500) | Data for the networking stage. | | 02-security |
-| [tfvars](outputs.tf#L511) | Terraform variable files for the following stages. | ✓ | |
+| [cicd_repositories](outputs.tf#L376) | WIF configuration for CI/CD repositories. | | |
+| [dataplatform](outputs.tf#L390) | Data for the Data Platform stage. | | |
+| [folder_ids](outputs.tf#L406) | Folder ids. | | |
+| [gcve](outputs.tf#L411) | Data for the GCVE stage. | | 03-gcve |
+| [gke_multitenant](outputs.tf#L432) | Data for the GKE multitenant stage. | | 03-gke-multitenant |
+| [networking](outputs.tf#L453) | Data for the networking stage. | | |
+| [project_factories](outputs.tf#L462) | Data for the project factories stage. | | |
+| [providers](outputs.tf#L481) | Terraform provider files for this stage and dependent stages. | ✓ | 02-networking · 02-security · 03-dataplatform · 03-network-security |
+| [sandbox](outputs.tf#L488) | Data for the sandbox stage. | | xx-sandbox |
+| [security](outputs.tf#L502) | Data for the networking stage. | | 02-security |
+| [tfvars](outputs.tf#L513) | Terraform variable files for the following stages. | ✓ | |
diff --git a/fast/stages/1-resman/branch-networking.tf b/fast/stages/1-resman/branch-networking.tf
index ca2791d70..1fb575a71 100644
--- a/fast/stages/1-resman/branch-networking.tf
+++ b/fast/stages/1-resman/branch-networking.tf
@@ -18,20 +18,28 @@
locals {
# FAST-specific IAM
- _network_folder_fast_iam = {
- # read-write (apply) automation service account
- "roles/logging.admin" = [module.branch-network-sa.iam_email]
- "roles/owner" = [module.branch-network-sa.iam_email]
- "roles/resourcemanager.folderAdmin" = [module.branch-network-sa.iam_email]
- "roles/resourcemanager.projectCreator" = [module.branch-network-sa.iam_email]
- "roles/compute.xpnAdmin" = [module.branch-network-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]
- # nsec service account
- "roles/serviceusage.serviceUsageAdmin" = [module.branch-nsec-sa.iam_email]
- (var.custom_roles["network_firewall_policies_admin"]) = [module.branch-nsec-sa.iam_email]
- }
+ _network_folder_fast_iam = merge(
+ {
+ # read-write (apply) automation service account
+ "roles/logging.admin" = [module.branch-network-sa.iam_email]
+ "roles/owner" = [module.branch-network-sa.iam_email]
+ "roles/resourcemanager.folderAdmin" = [module.branch-network-sa.iam_email]
+ "roles/resourcemanager.projectCreator" = [module.branch-network-sa.iam_email]
+ "roles/compute.xpnAdmin" = [module.branch-network-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]
+ },
+ var.fast_features.nsec != true ? {} : {
+ # nsec service account
+ "roles/serviceusage.serviceUsageAdmin" = [
+ try(module.branch-nsec-sa[0].iam_email, null)
+ ]
+ (var.custom_roles["network_firewall_policies_admin"]) = [
+ try(module.branch-nsec-sa[0].iam_email, null)
+ ]
+ }
+ )
# deep-merge FAST-specific IAM with user-provided bindings in var.folder_iam
_network_folder_iam = merge(
var.folder_iam.network,
diff --git a/fast/stages/1-resman/branch-nsec.tf b/fast/stages/1-resman/branch-nsec.tf
index 0fb0299c3..cb1c56cd1 100644
--- a/fast/stages/1-resman/branch-nsec.tf
+++ b/fast/stages/1-resman/branch-nsec.tf
@@ -18,8 +18,14 @@
# automation service account
+moved {
+ from = module.branch-nsec-sa
+ to = module.branch-nsec-sa[0]
+}
+
module "branch-nsec-sa" {
source = "../../../modules/iam-service-account"
+ count = var.fast_features.nsec ? 1 : 0
project_id = var.automation.project_id
name = "prod-resman-nsec-0"
display_name = "Terraform resman network security service account."
@@ -40,8 +46,14 @@ module "branch-nsec-sa" {
# automation read-only service account
+moved {
+ from = module.branch-nsec-r-sa
+ to = module.branch-nsec-r-sa[0]
+}
+
module "branch-nsec-r-sa" {
source = "../../../modules/iam-service-account"
+ count = var.fast_features.nsec ? 1 : 0
project_id = var.automation.project_id
name = "prod-resman-nsec-0r"
display_name = "Terraform resman network security service account (read-only)."
@@ -61,8 +73,14 @@ module "branch-nsec-r-sa" {
# automation bucket
+moved {
+ from = module.branch-nsec-gcs
+ to = module.branch-nsec-gcs[0]
+}
+
module "branch-nsec-gcs" {
source = "../../../modules/gcs"
+ count = var.fast_features.nsec ? 1 : 0
project_id = var.automation.project_id
name = "prod-resman-nsec-0"
prefix = var.prefix
@@ -70,7 +88,7 @@ module "branch-nsec-gcs" {
storage_class = local.gcs_storage_class
versioning = true
iam = {
- "roles/storage.objectAdmin" = [module.branch-nsec-sa.iam_email]
- "roles/storage.objectViewer" = [module.branch-nsec-r-sa.iam_email]
+ "roles/storage.objectAdmin" = [module.branch-nsec-sa[0].iam_email]
+ "roles/storage.objectViewer" = [module.branch-nsec-r-sa[0].iam_email]
}
}
diff --git a/fast/stages/1-resman/iam.tf b/fast/stages/1-resman/iam.tf
index b396541ad..44706fe97 100644
--- a/fast/stages/1-resman/iam.tf
+++ b/fast/stages/1-resman/iam.tf
@@ -24,14 +24,6 @@ locals {
member = module.branch-network-sa.iam_email
role = "roles/compute.orgFirewallPolicyAdmin"
}
- sa_net_nsec_fw_policy_admin = {
- member = module.branch-nsec-sa.iam_email
- role = "roles/compute.orgFirewallPolicyAdmin"
- }
- sa_net_nsec_ngfw_enterprise_admin = {
- member = module.branch-nsec-sa.iam_email
- role = local.custom_roles["ngfw_enterprise_admin"],
- }
sa_net_xpn_admin = {
member = module.branch-network-sa.iam_email
role = "roles/compute.xpnAdmin"
@@ -46,6 +38,17 @@ locals {
# role = "roles/accesscontextmanager.policyAdmin"
# }
},
+ # optional network security
+ var.fast_features.nsec != true ? {} : {
+ sa_net_nsec_fw_policy_admin = {
+ member = module.branch-nsec-sa[0].iam_email
+ role = "roles/compute.orgFirewallPolicyAdmin"
+ }
+ sa_net_nsec_ngfw_enterprise_admin = {
+ member = module.branch-nsec-sa[0].iam_email
+ role = local.custom_roles["ngfw_enterprise_admin"],
+ }
+ },
# optional billing roles for network and security
local.billing_mode != "org" ? {} : {
sa_net_billing = {
diff --git a/fast/stages/1-resman/main.tf b/fast/stages/1-resman/main.tf
index de21be519..80beb5b49 100644
--- a/fast/stages/1-resman/main.tf
+++ b/fast/stages/1-resman/main.tf
@@ -33,8 +33,8 @@ locals {
gke-dev-r = try(module.branch-gke-dev-r-sa[0].email, null)
gke-prod = try(module.branch-gke-prod-sa[0].email, null)
gke-prod-r = try(module.branch-gke-prod-r-sa[0].email, null)
- nsec = module.branch-nsec-sa.email
- nsec-r = module.branch-nsec-r-sa.email
+ nsec = try(module.branch-nsec-sa[0].email, null)
+ nsec-r = try(module.branch-nsec-r-sa[0].email, null)
networking = module.branch-network-sa.email
networking-r = module.branch-network-r-sa.email
project-factory = module.branch-pf-sa.email
diff --git a/fast/stages/1-resman/outputs.tf b/fast/stages/1-resman/outputs.tf
index a552c05ba..f640c3392 100644
--- a/fast/stages/1-resman/outputs.tf
+++ b/fast/stages/1-resman/outputs.tf
@@ -245,18 +245,6 @@ locals {
name = "security"
sa = module.branch-security-r-sa.email
})
- "3-network-security" = templatefile(local._tpl_providers, {
- backend_extra = null
- bucket = module.branch-nsec-gcs.name
- name = "network-security"
- sa = module.branch-nsec-sa.email
- })
- "3-network-security-r" = templatefile(local._tpl_providers, {
- backend_extra = null
- bucket = module.branch-network-gcs.name
- name = "network-security"
- sa = module.branch-nsec-r-sa.email
- })
},
{
for k, v in module.top-level-sa :
@@ -345,6 +333,20 @@ locals {
sa = module.branch-gcve-prod-r-sa[0].email
})
},
+ !var.fast_features.nsec ? {} : {
+ "3-network-security" = templatefile(local._tpl_providers, {
+ backend_extra = null
+ bucket = module.branch-nsec-gcs[0].name
+ name = "network-security"
+ sa = module.branch-nsec-sa[0].email
+ })
+ "3-network-security-r" = templatefile(local._tpl_providers, {
+ backend_extra = null
+ bucket = module.branch-nsec-gcs[0].name
+ name = "network-security"
+ sa = module.branch-nsec-r-sa[0].email
+ })
+ },
!var.fast_features.sandbox ? {} : {
"9-sandbox" = templatefile(local._tpl_providers, {
backend_extra = null
diff --git a/fast/stages/1-resman/variables.tf b/fast/stages/1-resman/variables.tf
index c111404f8..2d10a8d60 100644
--- a/fast/stages/1-resman/variables.tf
+++ b/fast/stages/1-resman/variables.tf
@@ -136,6 +136,7 @@ variable "fast_features" {
data_platform = optional(bool, false)
gke = optional(bool, false)
gcve = optional(bool, false)
+ nsec = optional(bool, false)
sandbox = optional(bool, false)
})
default = {}
diff --git a/tests/fast/stages/s1_resman/checklist.yaml b/tests/fast/stages/s1_resman/checklist.yaml
index 2a1c0e3f5..c3208c0ba 100644
--- a/tests/fast/stages/s1_resman/checklist.yaml
+++ b/tests/fast/stages/s1_resman/checklist.yaml
@@ -416,18 +416,18 @@ values:
counts:
google_folder: 57
- google_folder_iam_binding: 76
- google_organization_iam_member: 16
- google_project_iam_member: 12
- google_service_account: 12
- google_service_account_iam_binding: 12
- google_storage_bucket: 6
- google_storage_bucket_iam_binding: 12
- google_storage_bucket_iam_member: 12
- google_storage_bucket_object: 13
+ google_folder_iam_binding: 74
+ google_organization_iam_member: 14
+ google_project_iam_member: 10
+ google_service_account: 10
+ google_service_account_iam_binding: 10
+ google_storage_bucket: 5
+ google_storage_bucket_iam_binding: 10
+ google_storage_bucket_iam_member: 10
+ google_storage_bucket_object: 11
google_tags_tag_binding: 5
google_tags_tag_key: 2
google_tags_tag_value: 9
google_tags_tag_value_iam_binding: 2
- modules: 76
- resources: 246
+ modules: 73
+ resources: 229
diff --git a/tests/fast/stages/s1_resman/simple.yaml b/tests/fast/stages/s1_resman/simple.yaml
index 25823e40d..6a2bd8830 100644
--- a/tests/fast/stages/s1_resman/simple.yaml
+++ b/tests/fast/stages/s1_resman/simple.yaml
@@ -42,18 +42,18 @@ values:
counts:
google_folder: 5
- google_folder_iam_binding: 30
- google_organization_iam_member: 16
- google_project_iam_member: 12
- google_service_account: 12
- google_service_account_iam_binding: 12
- google_storage_bucket: 6
- google_storage_bucket_iam_binding: 12
- google_storage_bucket_iam_member: 12
- google_storage_bucket_object: 13
+ google_folder_iam_binding: 28
+ google_organization_iam_member: 14
+ google_project_iam_member: 10
+ google_service_account: 10
+ google_service_account_iam_binding: 10
+ google_storage_bucket: 5
+ google_storage_bucket_iam_binding: 10
+ google_storage_bucket_iam_member: 10
+ google_storage_bucket_object: 11
google_tags_tag_binding: 5
google_tags_tag_key: 2
google_tags_tag_value: 9
google_tags_tag_value_iam_binding: 2
- modules: 24
- resources: 148
+ modules: 21
+ resources: 131