diff --git a/fast/stage-links.sh b/fast/stage-links.sh
index 5fb2a5e6f4..7a2fed3d5b 100755
--- a/fast/stage-links.sh
+++ b/fast/stage-links.sh
@@ -83,6 +83,21 @@ case $STAGE_NAME in
tenants/$TENANT/tfvars/1-resman.auto.tfvars.json"
fi
;;
+"3-network-security"*)
+ if [[ -z "$TENANT" ]]; then
+ echo "# if this is a tenant stage, set a \$TENANT variable with the tenant shortname and run the command again"
+ PROVIDER="providers/3-netsec-providers.tf"
+ TFVARS="tfvars/0-bootstrap.auto.tfvars.json
+ tfvars/1-resman.auto.tfvars.json
+ tfvars/2-networking.auto.tfvars.json"
+ else
+ unset GLOBALS
+ PROVIDER="tenants/$TENANT/providers/3-netsec-providers.tf"
+ TFVARS="tenants/$TENANT/tfvars/0-bootstrap-tenant.auto.tfvars.json
+ tenants/$TENANT/tfvars/1-resman.auto.tfvars.json
+ tenants/$TENANT/tfvars/2-networking.auto.tfvars.json"
+ fi
+ ;;
*)
# check for a "dev" stage 3
echo "no stage found, trying for parent stage 3..."
diff --git a/fast/stages/0-bootstrap/automation.tf b/fast/stages/0-bootstrap/automation.tf
index 72d1419f7d..772079b062 100644
--- a/fast/stages/0-bootstrap/automation.tf
+++ b/fast/stages/0-bootstrap/automation.tf
@@ -143,6 +143,7 @@ module "automation-project" {
"essentialcontacts.googleapis.com",
"iam.googleapis.com",
"iamcredentials.googleapis.com",
+ "networksecurity.googleapis.com",
"orgpolicy.googleapis.com",
"pubsub.googleapis.com",
"servicenetworking.googleapis.com",
diff --git a/fast/stages/0-bootstrap/data/custom-roles/network_firewall_policies_admin.yaml b/fast/stages/0-bootstrap/data/custom-roles/network_firewall_policies_admin.yaml
new file mode 100644
index 0000000000..eb78791ac6
--- /dev/null
+++ b/fast/stages/0-bootstrap/data/custom-roles/network_firewall_policies_admin.yaml
@@ -0,0 +1,22 @@
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+name: networkFirewallPoliciesAdmin
+includedPermissions:
+ - compute.networks.setFirewallPolicy
+ - networksecurity.firewallEndpointAssociations.create
+ - networksecurity.firewallEndpointAssociations.delete
+ - networksecurity.firewallEndpointAssociations.get
+ - networksecurity.firewallEndpointAssociations.list
+ - networksecurity.firewallEndpointAssociations.update
diff --git a/fast/stages/0-bootstrap/data/custom-roles/ngfw_enterprise_admin.yaml b/fast/stages/0-bootstrap/data/custom-roles/ngfw_enterprise_admin.yaml
new file mode 100644
index 0000000000..3c54a58346
--- /dev/null
+++ b/fast/stages/0-bootstrap/data/custom-roles/ngfw_enterprise_admin.yaml
@@ -0,0 +1,40 @@
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+name: ngfwEnterpriseAdmin
+includedPermissions:
+ - networksecurity.firewallEndpoints.create
+ - networksecurity.firewallEndpoints.delete
+ - networksecurity.firewallEndpoints.get
+ - networksecurity.firewallEndpoints.list
+ - networksecurity.firewallEndpoints.update
+ - networksecurity.firewallEndpoints.use
+ - networksecurity.locations.get
+ - networksecurity.locations.list
+ - networksecurity.operations.cancel
+ - networksecurity.operations.delete
+ - networksecurity.operations.get
+ - networksecurity.operations.list
+ - networksecurity.securityProfileGroups.create
+ - networksecurity.securityProfileGroups.delete
+ - networksecurity.securityProfileGroups.get
+ - networksecurity.securityProfileGroups.list
+ - networksecurity.securityProfileGroups.update
+ - networksecurity.securityProfileGroups.use
+ - networksecurity.securityProfiles.create
+ - networksecurity.securityProfiles.delete
+ - networksecurity.securityProfiles.get
+ - networksecurity.securityProfiles.list
+ - networksecurity.securityProfiles.update
+ - networksecurity.securityProfiles.use
diff --git a/fast/stages/0-bootstrap/organization-iam.tf b/fast/stages/0-bootstrap/organization-iam.tf
index b4fb4793a8..bde1b21505 100644
--- a/fast/stages/0-bootstrap/organization-iam.tf
+++ b/fast/stages/0-bootstrap/organization-iam.tf
@@ -1,5 +1,5 @@
/**
- * Copyright 2023 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/fast/stages/0-bootstrap/organization.tf b/fast/stages/0-bootstrap/organization.tf
index da570da529..b7aa68d4ab 100644
--- a/fast/stages/0-bootstrap/organization.tf
+++ b/fast/stages/0-bootstrap/organization.tf
@@ -163,23 +163,36 @@ module "organization" {
# delegated role grant for resource manager service account
iam_bindings = merge(
{
+ organization_ngfw_enterprise_admin = {
+ members = [local.principals.gcp-network-admins]
+ role = module.organization.custom_role_id["ngfw_enterprise_admin"]
+ }
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/cloudasset.viewer",
- "roles/compute.orgFirewallPolicyAdmin",
- "roles/compute.xpnAdmin",
- "roles/orgpolicy.policyAdmin",
- "roles/orgpolicy.policyViewer",
- "roles/resourcemanager.organizationViewer",
- module.organization.custom_role_id["service_project_network_admin"],
- module.organization.custom_role_id["tenant_network_admin"],
- ]))
+ expression = (
+ format(
+ <<-EOT
+ api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])
+ || api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])
+ EOT
+ , join(",", formatlist("'%s'", [
+ "roles/accesscontextmanager.policyAdmin",
+ "roles/cloudasset.viewer",
+ "roles/compute.orgFirewallPolicyAdmin",
+ "roles/compute.xpnAdmin",
+ "roles/orgpolicy.policyAdmin",
+ "roles/orgpolicy.policyViewer",
+ "roles/resourcemanager.organizationViewer"
+ ]))
+ , join(",", formatlist("'%s'", [
+ module.organization.custom_role_id["network_firewall_policies_admin"],
+ module.organization.custom_role_id["ngfw_enterprise_admin"],
+ module.organization.custom_role_id["service_project_network_admin"],
+ module.organization.custom_role_id["tenant_network_admin"]
+ ]))
+ )
)
title = "automation_sa_delegated_grants"
description = "Automation service account delegated grants."
diff --git a/fast/stages/1-resman/README.md b/fast/stages/1-resman/README.md
index cfe1ffcf6b..7159e6f7d5 100644
--- a/fast/stages/1-resman/README.md
+++ b/fast/stages/1-resman/README.md
@@ -236,6 +236,7 @@ A full reference of IAM roles managed by this stage [is available here](./IAM.md
| [branch-data-platform.tf](./branch-data-platform.tf) | Data Platform stages resources. | folder
· gcs
· iam-service-account
| |
| [branch-gcve.tf](./branch-gcve.tf) | GCVE stage resources. | folder
· gcs
· iam-service-account
| |
| [branch-gke.tf](./branch-gke.tf) | GKE multitenant stage resources. | folder
· gcs
· iam-service-account
| |
+| [branch-netsec.tf](./branch-netsec.tf) | Network security stage resources. | gcs
· iam-service-account
| |
| [branch-networking.tf](./branch-networking.tf) | Networking stage resources. | folder
· gcs
· iam-service-account
| |
| [branch-project-factory.tf](./branch-project-factory.tf) | Project factory stage resources. | gcs
· iam-service-account
| |
| [branch-sandbox.tf](./branch-sandbox.tf) | Sandbox stage resources. | folder
· gcs
· iam-service-account
| |
@@ -244,6 +245,7 @@ A full reference of IAM roles managed by this stage [is available here](./IAM.md
| [cicd-data-platform.tf](./cicd-data-platform.tf) | CI/CD resources for the data platform branch. | iam-service-account
| |
| [cicd-gcve.tf](./cicd-gcve.tf) | CI/CD resources for the GCVE branch. | iam-service-account
| |
| [cicd-gke.tf](./cicd-gke.tf) | CI/CD resources for the GKE multitenant branch. | iam-service-account
| |
+| [cicd-netsec.tf](./cicd-netsec.tf) | CI/CD resources for the networking branch. | iam-service-account
| |
| [cicd-networking.tf](./cicd-networking.tf) | CI/CD resources for the networking branch. | iam-service-account
| |
| [cicd-project-factory.tf](./cicd-project-factory.tf) | CI/CD resources for the project factories. | iam-service-account
| |
| [cicd-security.tf](./cicd-security.tf) | CI/CD resources for the security branch. | iam-service-account
| |
@@ -265,35 +267,35 @@ A full reference of IAM roles managed by this stage [is available here](./IAM.md
|---|---|:---:|:---:|:---:|:---:|
| [automation](variables-fast.tf#L19) | Automation resources created by the bootstrap stage. | object({…})
| ✓ | | 0-bootstrap
|
| [billing_account](variables-fast.tf#L42) | 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({…})
| ✓ | | 0-bootstrap
|
-| [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
| |
-| [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#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#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#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({…}))
| | {}
| |
+| [logging](variables-fast.tf#L95) | Logging configuration for tenants. | object({…})
| ✓ | | 1-tenant-factory
|
+| [organization](variables-fast.tf#L108) | Organization details. | object({…})
| ✓ | | 0-bootstrap
|
+| [prefix](variables-fast.tf#L126) | 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
| |
+| [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#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#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#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#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. | ✓ | |
+| [cicd_repositories](outputs.tf#L402) | WIF configuration for CI/CD repositories. | | |
+| [dataplatform](outputs.tf#L416) | Data for the Data Platform stage. | | |
+| [folder_ids](outputs.tf#L432) | Folder ids. | | |
+| [gcve](outputs.tf#L437) | Data for the GCVE stage. | | 03-gcve
|
+| [gke_multitenant](outputs.tf#L458) | Data for the GKE multitenant stage. | | 03-gke-multitenant
|
+| [networking](outputs.tf#L479) | Data for the networking stage. | | |
+| [project_factories](outputs.tf#L488) | Data for the project factories stage. | | |
+| [providers](outputs.tf#L507) | Terraform provider files for this stage and dependent stages. | ✓ | 02-networking
· 02-security
· 03-dataplatform
· 03-netsec
|
+| [sandbox](outputs.tf#L514) | Data for the sandbox stage. | | xx-sandbox
|
+| [security](outputs.tf#L528) | Data for the networking stage. | | 02-security
|
+| [tfvars](outputs.tf#L539) | Terraform variable files for the following stages. | ✓ | |
diff --git a/fast/stages/1-resman/branch-netsec.tf b/fast/stages/1-resman/branch-netsec.tf
new file mode 100644
index 0000000000..3d941e1f6e
--- /dev/null
+++ b/fast/stages/1-resman/branch-netsec.tf
@@ -0,0 +1,76 @@
+/**
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+# tfdoc:file:description Network security stage resources.
+
+# automation service account
+
+module "branch-netsec-sa" {
+ source = "../../../modules/iam-service-account"
+ project_id = var.automation.project_id
+ name = "prod-resman-netsec-0"
+ display_name = "Terraform resman network security service account."
+ prefix = var.prefix
+ service_account_create = var.root_node == null
+ iam = {
+ "roles/iam.serviceAccountTokenCreator" = compact([
+ try(module.branch-netsec-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"]
+ }
+}
+
+# automation read-only service account
+
+module "branch-netsec-r-sa" {
+ source = "../../../modules/iam-service-account"
+ project_id = var.automation.project_id
+ name = "prod-resman-netsec-0r"
+ display_name = "Terraform resman network security service account (read-only)."
+ prefix = var.prefix
+ iam = {
+ "roles/iam.serviceAccountTokenCreator" = compact([
+ try(module.branch-netsec-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"]]
+ }
+}
+
+# automation bucket
+
+module "branch-netsec-gcs" {
+ source = "../../../modules/gcs"
+ project_id = var.automation.project_id
+ name = "prod-resman-netsec-0"
+ prefix = var.prefix
+ location = var.locations.gcs
+ storage_class = local.gcs_storage_class
+ versioning = true
+ iam = {
+ "roles/storage.objectAdmin" = [module.branch-netsec-sa.iam_email]
+ "roles/storage.objectViewer" = [module.branch-netsec-r-sa.iam_email]
+ }
+}
diff --git a/fast/stages/1-resman/branch-networking.tf b/fast/stages/1-resman/branch-networking.tf
index 285e0f5001..cc6cac29c5 100644
--- a/fast/stages/1-resman/branch-networking.tf
+++ b/fast/stages/1-resman/branch-networking.tf
@@ -28,6 +28,9 @@ locals {
# 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]
+ # netsec service account
+ "roles/serviceusage.serviceUsageAdmin" = [module.branch-netsec-sa.iam_email]
+ (var.custom_roles["network_firewall_policies_admin"]) = [module.branch-netsec-sa.iam_email]
}
# deep-merge FAST-specific IAM with user-provided bindings in var.folder_iam
_network_folder_iam = merge(
diff --git a/fast/stages/1-resman/cicd-netsec.tf b/fast/stages/1-resman/cicd-netsec.tf
new file mode 100644
index 0000000000..42810bd942
--- /dev/null
+++ b/fast/stages/1-resman/cicd-netsec.tf
@@ -0,0 +1,85 @@
+/**
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+# tfdoc:file:description CI/CD resources for the networking branch.
+
+# read-write (apply) SA used by CI/CD workflows
+# to impersonate netsec automation SA
+
+module "branch-netsec-sa-cicd" {
+ source = "../../../modules/iam-service-account"
+ for_each = (
+ try(local.cicd_repositories.netsec.name, null) != null
+ ? { 0 = local.cicd_repositories.netsec }
+ : {}
+ )
+ project_id = var.automation.project_id
+ name = "prod-resman-netsec-1"
+ display_name = "Terraform CI/CD stage 2 network security 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"]
+ }
+}
+
+# read-only (plan) SA used by CI/CD workflows to impersonate netsec automation SA
+
+module "branch-netsec-r-sa-cicd" {
+ source = "../../../modules/iam-service-account"
+ for_each = (
+ try(local.cicd_repositories.netsec.name, null) != null
+ ? { 0 = local.cicd_repositories.netsec }
+ : {}
+ )
+ project_id = var.automation.project_id
+ name = "prod-resman-netsec-1r"
+ display_name = "Terraform CI/CD stage 2 network security 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"]
+ }
+}
diff --git a/fast/stages/1-resman/iam.tf b/fast/stages/1-resman/iam.tf
index 0a60182aaa..2b54e48545 100644
--- a/fast/stages/1-resman/iam.tf
+++ b/fast/stages/1-resman/iam.tf
@@ -24,6 +24,14 @@ locals {
member = module.branch-network-sa.iam_email
role = "roles/compute.orgFirewallPolicyAdmin"
}
+ sa_net_netsec_fw_policy_admin = {
+ member = module.branch-netsec-sa.iam_email
+ role = "roles/compute.orgFirewallPolicyAdmin"
+ }
+ sa_net_netsec_ngfw_enterprise_admin = {
+ member = module.branch-netsec-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"
diff --git a/fast/stages/1-resman/outputs.tf b/fast/stages/1-resman/outputs.tf
index 9cd19b489d..975cbbde9a 100644
--- a/fast/stages/1-resman/outputs.tf
+++ b/fast/stages/1-resman/outputs.tf
@@ -83,6 +83,17 @@ locals {
}
tf_var_files = local.cicd_workflow_var_files.stage_3
}
+ netsec = {
+ service_accounts = {
+ apply = try(module.branch-netsec-sa-cicd[0].email, null)
+ plan = try(module.branch-netsec-r-sa-cicd[0].email, null)
+ }
+ tf_providers_files = {
+ apply = "3-netsec-providers.tf"
+ plan = "3-netsec-r-providers.tf"
+ }
+ tf_var_files = local.cicd_workflow_var_files.stage_3
+ }
networking = {
service_accounts = {
apply = try(module.branch-network-sa-cicd[0].email, null)
@@ -198,6 +209,18 @@ locals {
name = "security"
sa = module.branch-security-r-sa.email
})
+ "3-netsec" = templatefile(local._tpl_providers, {
+ backend_extra = null
+ bucket = module.branch-netsec-gcs.name
+ name = "netsec"
+ sa = module.branch-netsec-sa.email
+ })
+ "3-netsec-r" = templatefile(local._tpl_providers, {
+ backend_extra = null
+ bucket = module.branch-network-gcs.name
+ name = "netsec"
+ sa = module.branch-netsec-r-sa.email
+ })
},
{
for k, v in module.top-level-sa :
@@ -347,6 +370,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)
+ netsec = module.branch-netsec-sa.email
+ netsec-r = module.branch-netsec-r-sa.email
networking = module.branch-network-sa.email
networking-r = module.branch-network-r-sa.email
project-factory = try(module.branch-pf-sa[0].email, null)
@@ -480,7 +505,7 @@ output "project_factories" {
# ready to use provider configurations for subsequent stages
output "providers" {
- # tfdoc:output:consumers 02-networking 02-security 03-dataplatform
+ # tfdoc:output:consumers 02-networking 02-security 03-dataplatform 03-netsec
description = "Terraform provider files for this stage and dependent stages."
sensitive = true
value = local.providers
diff --git a/fast/stages/1-resman/templates/providers.tf.tpl b/fast/stages/1-resman/templates/providers.tf.tpl
index d1c224c5c1..817403ceed 100644
--- a/fast/stages/1-resman/templates/providers.tf.tpl
+++ b/fast/stages/1-resman/templates/providers.tf.tpl
@@ -1,5 +1,5 @@
/**
- * Copyright 2022 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/fast/stages/1-resman/variables-fast.tf b/fast/stages/1-resman/variables-fast.tf
index cd2b76fb9e..c6b833362e 100644
--- a/fast/stages/1-resman/variables-fast.tf
+++ b/fast/stages/1-resman/variables-fast.tf
@@ -54,10 +54,12 @@ variable "custom_roles" {
# tfdoc:variable:source 0-bootstrap
description = "Custom roles defined at the org level, in key => id format."
type = object({
- gcve_network_admin = string
- organization_admin_viewer = string
- service_project_network_admin = string
- storage_viewer = string
+ gcve_network_admin = string
+ network_firewall_policies_admin = string
+ ngfw_enterprise_admin = string
+ organization_admin_viewer = string
+ service_project_network_admin = string
+ storage_viewer = string
})
default = null
}
diff --git a/fast/stages/1-resman/variables.tf b/fast/stages/1-resman/variables.tf
index c7a4ff749c..f5d8bf90f1 100644
--- a/fast/stages/1-resman/variables.tf
+++ b/fast/stages/1-resman/variables.tf
@@ -56,6 +56,12 @@ variable "cicd_repositories" {
branch = optional(string)
identity_provider = optional(string)
}))
+ netsec = optional(object({
+ name = string
+ type = string
+ branch = optional(string)
+ identity_provider = optional(string)
+ }))
networking = optional(object({
name = string
type = string
diff --git a/fast/stages/1-tenant-factory/README.md b/fast/stages/1-tenant-factory/README.md
index 2cad091e12..2716f2f032 100644
--- a/fast/stages/1-tenant-factory/README.md
+++ b/fast/stages/1-tenant-factory/README.md
@@ -309,13 +309,13 @@ gcloud storage cp gs://{prefix}-{tenant-shortname}-prod-iac-core-0/tfvars/0-boot
|---|---|:---:|:---:|:---:|:---:|
| [automation](variables-fast.tf#L19) | Automation resources created by the bootstrap stage. | object({…})
| ✓ | | 0-bootstrap
|
| [billing_account](variables-fast.tf#L42) | 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({…})
| ✓ | | 0-bootstrap
|
-| [logging](variables-fast.tf#L94) | Logging resources created by the bootstrap stage. | object({…})
| ✓ | | 0-bootstrap
|
-| [org_policy_tags](variables-fast.tf#L113) | Organization policy tags. | object({…})
| ✓ | | 0-bootstrap
|
-| [organization](variables-fast.tf#L103) | Organization details. | object({…})
| ✓ | | 0-bootstrap
|
-| [prefix](variables-fast.tf#L130) | Prefix used for resources that need unique names. Use 9 characters or less. | string
| ✓ | | 0-bootstrap
|
-| [custom_roles](variables-fast.tf#L53) | Custom roles defined at the org level, in key => id format. | object({…})
| | null
| 0-bootstrap
|
-| [groups](variables-fast.tf#L66) | 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#L81) | Optional locations for GCS, BigQuery, and logging buckets created here. | object({…})
| | {}
| 0-bootstrap
|
+| [logging](variables-fast.tf#L96) | Logging resources created by the bootstrap stage. | object({…})
| ✓ | | 0-bootstrap
|
+| [org_policy_tags](variables-fast.tf#L115) | Organization policy tags. | object({…})
| ✓ | | 0-bootstrap
|
+| [organization](variables-fast.tf#L105) | Organization details. | object({…})
| ✓ | | 0-bootstrap
|
+| [prefix](variables-fast.tf#L132) | Prefix used for resources that need unique names. Use 9 characters or less. | string
| ✓ | | 0-bootstrap
|
+| [custom_roles](variables-fast.tf#L53) | Custom roles defined at the org level, in key => id format. | object({…})
| | null
| 0-bootstrap
|
+| [groups](variables-fast.tf#L68) | 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#L83) | Optional locations for GCS, BigQuery, and logging buckets created here. | object({…})
| | {}
| 0-bootstrap
|
| [outputs_location](variables.tf#L17) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string
| | null
| |
| [root_node](variables.tf#L23) | Root folder under which tenants are created, in folders/nnnn format. Defaults to the organization if null. | string
| | null
| |
| [tag_names](variables.tf#L36) | Customized names for resource management tags. | object({…})
| | {}
| |
diff --git a/fast/stages/1-tenant-factory/variables-fast.tf b/fast/stages/1-tenant-factory/variables-fast.tf
index ca67b036ed..b7eb168cfd 100644
--- a/fast/stages/1-tenant-factory/variables-fast.tf
+++ b/fast/stages/1-tenant-factory/variables-fast.tf
@@ -54,11 +54,13 @@ variable "custom_roles" {
# tfdoc:variable:source 0-bootstrap
description = "Custom roles defined at the org level, in key => id format."
type = object({
- gcve_network_admin = string
- organization_admin_viewer = string
- service_project_network_admin = string
- storage_viewer = string
- tenant_network_admin = string
+ gcve_network_admin = string
+ network_firewall_policies_admin = string
+ ngfw_enterprise_admin = string
+ organization_admin_viewer = string
+ service_project_network_admin = string
+ storage_viewer = string
+ tenant_network_admin = string
})
default = null
}
diff --git a/fast/stages/2-networking-a-simple/net-dev.tf b/fast/stages/2-networking-a-simple/net-dev.tf
index 561d959437..f48917ae76 100644
--- a/fast/stages/2-networking-a-simple/net-dev.tf
+++ b/fast/stages/2-networking-a-simple/net-dev.tf
@@ -29,6 +29,7 @@ module "dev-spoke-project" {
"dns.googleapis.com",
"iap.googleapis.com",
"networkmanagement.googleapis.com",
+ "networksecurity.googleapis.com",
"servicenetworking.googleapis.com",
"stackdriver.googleapis.com",
"vpcaccess.googleapis.com"
diff --git a/fast/stages/2-networking-a-simple/net-prod.tf b/fast/stages/2-networking-a-simple/net-prod.tf
index 4b8f260a4f..f2e52abe5a 100644
--- a/fast/stages/2-networking-a-simple/net-prod.tf
+++ b/fast/stages/2-networking-a-simple/net-prod.tf
@@ -29,6 +29,7 @@ module "prod-spoke-project" {
"dns.googleapis.com",
"iap.googleapis.com",
"networkmanagement.googleapis.com",
+ "networksecurity.googleapis.com",
"servicenetworking.googleapis.com",
"stackdriver.googleapis.com",
"vpcaccess.googleapis.com"
diff --git a/fast/stages/2-networking-b-nva/net-dev.tf b/fast/stages/2-networking-b-nva/net-dev.tf
index 11578eb524..7e1b7e38d4 100644
--- a/fast/stages/2-networking-b-nva/net-dev.tf
+++ b/fast/stages/2-networking-b-nva/net-dev.tf
@@ -1,5 +1,5 @@
/**
- * Copyright 2023 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,6 +28,7 @@ module "dev-spoke-project" {
"dns.googleapis.com",
"iap.googleapis.com",
"networkmanagement.googleapis.com",
+ "networksecurity.googleapis.com",
"servicenetworking.googleapis.com",
"stackdriver.googleapis.com",
"vpcaccess.googleapis.com"
diff --git a/fast/stages/2-networking-b-nva/net-prod.tf b/fast/stages/2-networking-b-nva/net-prod.tf
index 43e4eff0cc..3d2447647f 100644
--- a/fast/stages/2-networking-b-nva/net-prod.tf
+++ b/fast/stages/2-networking-b-nva/net-prod.tf
@@ -1,5 +1,5 @@
/**
- * Copyright 2023 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,6 +28,7 @@ module "prod-spoke-project" {
"dns.googleapis.com",
"iap.googleapis.com",
"networkmanagement.googleapis.com",
+ "networksecurity.googleapis.com",
"servicenetworking.googleapis.com",
"stackdriver.googleapis.com",
"vpcaccess.googleapis.com"
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 0ba612055e..3ee211ba72 100644
--- a/fast/stages/2-networking-c-separate-envs/net-dev.tf
+++ b/fast/stages/2-networking-c-separate-envs/net-dev.tf
@@ -28,6 +28,7 @@ module "dev-spoke-project" {
"dns.googleapis.com",
"iap.googleapis.com",
"networkmanagement.googleapis.com",
+ "networksecurity.googleapis.com",
"servicenetworking.googleapis.com",
"stackdriver.googleapis.com",
"vpcaccess.googleapis.com"
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 ba8860e7d8..1f3432cd46 100644
--- a/fast/stages/2-networking-c-separate-envs/net-prod.tf
+++ b/fast/stages/2-networking-c-separate-envs/net-prod.tf
@@ -28,6 +28,7 @@ module "prod-spoke-project" {
"dns.googleapis.com",
"iap.googleapis.com",
"networkmanagement.googleapis.com",
+ "networksecurity.googleapis.com",
"servicenetworking.googleapis.com",
"stackdriver.googleapis.com",
"vpcaccess.googleapis.com"
diff --git a/fast/stages/3-network-security/README.md b/fast/stages/3-network-security/README.md
new file mode 100644
index 0000000000..9e5cf2ad22
--- /dev/null
+++ b/fast/stages/3-network-security/README.md
@@ -0,0 +1,172 @@
+# Network Security
+
+This stage enables NGFW Enterprise in the dev `dev` and `prod` VPCs. This includes:
+
+- security profiles
+- security profile groups
+- NGFW endpoints
+- NGFW endpoint associations
+- global network firewall policies and some recommended firewall policy rules
+
+The following diagram is a high level reference of the resources created and managed here (excludes projects and VPCs):
+
+
+ +
+ + +- [Design overview and choices](#design-overview-and-choices) +- [How to run this stage](#how-to-run-this-stage) + - [Provider and Terraform variables](#provider-and-terraform-variables) + - [Impersonating the automation service account](#impersonating-the-automation-service-account) + - [Variable configuration](#variable-configuration) + - [Running the stage](#running-the-stage) +- [Customizations](#customizations) + - [Firewall policy rules factories](#firewall-policy-rules-factories) + - [NGFW Enterprise configuration](#ngfw-enterprise-configuration) +- [Files](#files) +- [Variables](#variables) +- [Outputs](#outputs) + + +## Design overview and choices + +- We create one security profile (and security profile group) per environment in the spoke VPCs only. That's usually where inspection is needed, as it's where workloads run. +- By default, we create NGFW Enterprise endpoints in three zones in the default, primary region (europe-west1). You can adapt this, depending on where your workloads run, using the dedicated variable. +- We install default firewall policy rules in each spoke, so that we allow and inspect all traffic going to the Internet and we allow egress towards RFC-1918 addresses. In ingress, you'll need to add your own rules. We provided some examples that need to be adapted to your topology (number of regions, subnets). +- We use global network firewall policies, as legacy VPC firewall rules are not compatible with NGFW Enterprise. These policies coexist with the legacy VPC firewall rules that we create in the netwroking stage. +- For your convenience, firewall policy rules leverage factories, so that you can define firewall policy rules using yaml files. The path of these files is configurable. Look in the [Customization](#customizations) section for more details. +- NGFW Enterprise endpoints are org-level resources that need to reference a quota project for billing purposes. By default, we create a dedicated `xxx-net-ngfw-0` quota project. Anyway, you can choose to leverage an existing project. Look in the [Customization](#customizations) section for more details. + +## How to run this stage + +This stage is meant to be executed after any [networking](../2-networking-a-simple) stage has run and it leverages dedicated automation service accounts and a bucket created in the [resman](../1-resman) stage. + +It's to run this stage in isolation, but that's outside the scope of this document, and you would need to refer to the code for the bootstrap and resman stages for the roles needed. + +Before running this stage, you need to make sure you have the correct credentials and permissions, and localize variables by assigning values that match your configuration. + +### Provider and Terraform variables + +As all other FAST stages, the [mechanism used to pass variable values and pre-built provider files from one stage to the next](../0-bootstrap/README.md#output-files-and-cross-stage-variables) is also leveraged here. + +The commands to link or copy the provider and terraform variable files can be easily derived from the `stage-links.sh` script in the FAST root folder, passing it a single argument with the local output files folder (if configured) or the GCS output bucket in the automation project (derived from stage 0 outputs). The following examples demonstrate both cases, and the resulting commands that then need to be copy/pasted and run. + +```bash +../../stage-links.sh ~/fast-config + +# copy and paste the following commands for '3-network-security' + +ln -s ~/fast-config/providers/3-netsec-providers.tf ./ +ln -s ~/fast-config/tfvars/0-globals.auto.tfvars.json ./ +ln -s ~/fast-config/tfvars/0-bootstrap.auto.tfvars.json ./ +ln -s ~/fast-config/tfvars/1-resman.auto.tfvars.json ./ +ln -s ~/fast-config/tfvars/2-networking.auto.tfvars.json ./ +``` + +```bash +../../stage-links.sh gs://xxx-prod-iac-core-outputs-0 + +# copy and paste the following commands for '3-network-security' + +gcloud storage cp gs://xxx-prod-iac-core-outputs-0/providers/3-netsec-providers.tf ./ +gcloud storage cp gs://xxx-prod-iac-core-outputs-0/tfvars/0-globals.auto.tfvars.json ./ +gcloud storage cp gs://xxx-prod-iac-core-outputs-0/tfvars/0-bootstrap.auto.tfvars.json ./ +gcloud storage cp gs://xxx-prod-iac-core-outputs-0/tfvars/1-resman.auto.tfvars.json ./ +gcloud storage cp gs://xxx-prod-iac-core-outputs-0/tfvars/2-networking.auto.tfvars.json ./ +``` + +### Impersonating the automation service account + +The preconfigured provider file uses impersonation to run with this stage's automation service account's credentials. The `gcp-devops` and `organization-admins` groups have the necessary IAM bindings in place to do that, so make sure the current user is a member of one of those groups. + +### Variable configuration + +Variables in this stage -- like most other FAST stages -- are broadly divided into three separate sets: + +- variables which refer to global values for the whole organization (org id, billing account id, prefix, etc.), which are pre-populated via the `0-globals.auto.tfvars.json` file linked or copied above +- variables which refer to resources managed by previous stages, which are prepopulated here via the `0-bootstrap.auto.tfvars.json`, `1-resman.auto.tfvars.json` and `2-networking.auto.tfvars.json` files linked or copied above +- and finally variables that optionally control this stage's behaviour and customizations, and can to be set in a custom `terraform.tfvars` file + +The latter set is explained in the [Customization](#customizations) sections below, and the full list can be found in the [Variables](#variables) table at the bottom of this document. + +Note that the `outputs_location` variable is disabled by default, you need to explicitly set it in your `terraform.tfvars` file if you want output files to be generated by this stage. This is a sample `terraform.tfvars` that configures it, refer to the [bootstrap stage documentation](../0-bootstrap/README.md#output-files-and-cross-stage-variables) for more details: + +```tfvars +outputs_location = "~/fast-config" +``` + +### Running the stage + +Once provider and variable values are in place and the correct user is configured, the stage can be run: + +```bash +terraform init +terraform apply +``` + +## Customizations + +You can optionally customize a few options adding a `terraform.tfvars` file to this stage. + +### Firewall policy rules factories + +By default, firewall policy rules yaml files are contained in the `data` folder within this module. Anyway, you can customize this location. + +### NGFW Enterprise configuration + +You can decide the zones where to deploy the NGFW Enterprise endpoints. These are set by default to `europe-west1-b`, `europe-west1-c` and `europe-west1-d`. + +```tfvars +ngfw_enterprise_config = { + endpoint_zones = [ + "us-east4-a", + "us-east4-b", + "australia-southeast1-b", + "australia-southeast1-c" + ] +} +``` + +Instead of creating a dedicated NGFW Enterprise billing/quota project, you can choose to leverage an existing project. These can even be one of your existing networking projects. +You'll need to make sure your network security service account can activate the `networksecurity.googleapis.com` on that project (for example, assigning the `roles/serviceusage.serviceUsageAdmin` role). + +```tfvars +ngfw_enterprise_config = { + quota_project_id = "your-quota-project-id" +} +``` + + + +## Files + +| name | description | modules | resources | +|---|---|---|---| +| [main.tf](./main.tf) | Next-Generation Firewall Enterprise configuration. |project
| google_network_security_firewall_endpoint
|
+| [net-dev.tf](./net-dev.tf) | Security components for dev spoke VPC. | net-firewall-policy
| google_network_security_firewall_endpoint_association
· google_network_security_security_profile
· google_network_security_security_profile_group
|
+| [net-prod.tf](./net-prod.tf) | Security components for prod spoke VPC. | net-firewall-policy
| google_network_security_firewall_endpoint_association
· google_network_security_security_profile
· google_network_security_security_profile_group
|
+| [outputs.tf](./outputs.tf) | Module outputs. | | |
+| [variables-fast.tf](./variables-fast.tf) | None | | |
+| [variables.tf](./variables.tf) | Module variables. | | |
+
+## Variables
+
+| name | description | type | required | default | producer |
+|---|---|:---:|:---:|:---:|:---:|
+| [billing_account](variables-fast.tf#L17) | Billing account id. If billing account is not part of the same org set `is_org_level` to false. | object({…})
| ✓ | | 0-bootstrap
|
+| [folder_ids](variables-fast.tf#L30) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | object({…})
| ✓ | | 1-resman
|
+| [organization](variables-fast.tf#L52) | Organization details. | object({…})
| ✓ | | 00-globals
|
+| [prefix](variables-fast.tf#L62) | Prefix used for resources that need unique names. Use a maximum of 9 chars for organizations, and 11 chars for tenants. | string
| ✓ | | 0-bootstrap
|
+| [vpc_self_links](variables-fast.tf#L72) | Self link for the shared VPC. | object({…})
| ✓ | | 2-networking
|
+| [factories_config](variables.tf#L17) | Configuration for network resource factories. | object({…})
| | {…}
| |
+| [host_project_ids](variables-fast.tf#L41) | Host project for the shared VPC. | object({…})
| | {}
| 2-networking
|
+| [ngfw_enterprise_config](variables.tf#L35) | NGFW Enterprise configuration. | object({…})
| | {…}
| |
+
+## Outputs
+
+| name | description | sensitive | consumers |
+|---|---|:---:|---|
+| [ngfw_enterprise_endpoint_ids](outputs.tf#L17) | The NGFW Enterprise endpoint ids. | | |
+| [ngfw_enterprise_endpoints_quota_project](outputs.tf#L25) | The NGFW Enterprise endpoints quota project. | | |
+
diff --git a/fast/stages/3-network-security/data/cidrs.yaml b/fast/stages/3-network-security/data/cidrs.yaml
new file mode 100644
index 0000000000..3591e95a0a
--- /dev/null
+++ b/fast/stages/3-network-security/data/cidrs.yaml
@@ -0,0 +1,18 @@
+# skip boilerplate check
+---
+# Terraform will be unable to decode this file if it does not contain valid YAML
+# You can retain `---` (start of the document) to indicate an empty document.
+
+healthchecks:
+ - 35.191.0.0/16
+ - 130.211.0.0/22
+ - 209.85.152.0/22
+ - 209.85.204.0/22
+
+rfc1918:
+ - 10.0.0.0/8
+ - 172.16.0.0/12
+ - 192.168.0.0/16
+
+onprem_probes:
+ - 10.255.255.254/32
diff --git a/fast/stages/3-network-security/data/firewall-policy-rules/dev/egress.yaml b/fast/stages/3-network-security/data/firewall-policy-rules/dev/egress.yaml
new file mode 100644
index 0000000000..a6edadf1cd
--- /dev/null
+++ b/fast/stages/3-network-security/data/firewall-policy-rules/dev/egress.yaml
@@ -0,0 +1,18 @@
+# skip boilerplate check
+---
+egress-allow-rfc1918:
+ description: "Allow all hosts to RFC-1918"
+ priority: 2147483546
+ match:
+ destination_ranges:
+ - rfc1918
+ action: "allow"
+
+egress-inspect-internet:
+ description: "Inspect egress traffic from all dev hosts to Internet"
+ priority: 2147483547
+ match:
+ destination_ranges:
+ - "0.0.0.0/0"
+ action: "apply_security_profile_group"
+ security_profile_group: "dev"
diff --git a/fast/stages/3-network-security/data/firewall-policy-rules/dev/ingress.yaml b/fast/stages/3-network-security/data/firewall-policy-rules/dev/ingress.yaml
new file mode 100644
index 0000000000..272431fa9c
--- /dev/null
+++ b/fast/stages/3-network-security/data/firewall-policy-rules/dev/ingress.yaml
@@ -0,0 +1,21 @@
+# skip boilerplate check
+---
+# Following are some NGFW Enterprise ingress rules examples
+
+# ingress-allow-inspect-cross:
+# description: "Allow and inspect cross-env traffic from prod."
+# priority: 1
+# match:
+# source_ranges:
+# - prod (to be defined)
+# action: "apply_security_profile_group"
+# security_profile_group: "dev"
+
+# ingress-allow-inspect-intra:
+# description: "Allow and inspect same-env (intra-vpc) traffic."
+# priority: 2
+# match:
+# source_ranges:
+# - dev (to be defined)
+# action: "apply_security_profile_group"
+# security_profile_group: "dev"
diff --git a/fast/stages/3-network-security/data/firewall-policy-rules/prod/egress.yaml b/fast/stages/3-network-security/data/firewall-policy-rules/prod/egress.yaml
new file mode 100644
index 0000000000..397acebe20
--- /dev/null
+++ b/fast/stages/3-network-security/data/firewall-policy-rules/prod/egress.yaml
@@ -0,0 +1,18 @@
+# skip boilerplate check
+---
+egress-allow-rfc1918:
+ description: "Allow all hosts to RFC-1918"
+ priority: 2147483546
+ match:
+ destination_ranges:
+ - rfc1918
+ action: "allow"
+
+egress-inspect-internet:
+ description: "Inspect egress traffic from all prod hosts to Internet"
+ priority: 2147483547
+ match:
+ destination_ranges:
+ - "0.0.0.0/0"
+ action: "apply_security_profile_group"
+ security_profile_group: "prod"
diff --git a/fast/stages/3-network-security/data/firewall-policy-rules/prod/ingress.yaml b/fast/stages/3-network-security/data/firewall-policy-rules/prod/ingress.yaml
new file mode 100644
index 0000000000..e0aa293c5b
--- /dev/null
+++ b/fast/stages/3-network-security/data/firewall-policy-rules/prod/ingress.yaml
@@ -0,0 +1,21 @@
+# skip boilerplate check
+---
+# Following are some NGFW Enterprise ingress rules examples
+
+# ingress-allow-inspect-cross:
+# description: "Allow and inspect cross-env traffic."
+# priority: 1
+# match:
+# source_ranges:
+# - dev (to be defined)
+# action: "apply_security_profile_group"
+# security_profile_group: "prod"
+
+# ingress-allow-inspect-intra:
+# description: "Allow and inspect intra-VPC traffic."
+# priority: 2
+# match:
+# source_ranges:
+# - prod (to be defined)
+# action: "apply_security_profile_group"
+# security_profile_group: "prod"
diff --git a/fast/stages/3-network-security/diagram.png b/fast/stages/3-network-security/diagram.png
new file mode 100644
index 0000000000..960cbff204
Binary files /dev/null and b/fast/stages/3-network-security/diagram.png differ
diff --git a/fast/stages/3-network-security/diagram.svg b/fast/stages/3-network-security/diagram.svg
new file mode 100644
index 0000000000..3c586b458b
--- /dev/null
+++ b/fast/stages/3-network-security/diagram.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/fast/stages/3-network-security/main.tf b/fast/stages/3-network-security/main.tf
new file mode 100644
index 0000000000..946dba43f3
--- /dev/null
+++ b/fast/stages/3-network-security/main.tf
@@ -0,0 +1,68 @@
+/**
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+# tfdoc:file:description Next-Generation Firewall Enterprise configuration.
+
+locals {
+ create_quota_project = (
+ var.ngfw_enterprise_config.quota_project_id == null
+ ? true
+ : false
+ )
+ vpc_ids = {
+ for k, v in var.vpc_self_links
+ : k => replace(v, "https://www.googleapis.com/compute/v1/", "")
+ }
+}
+
+# Dedicated quota project for ngfw enterprise endpoints
+module "ngfw-quota-project" {
+ source = "../../../modules/project"
+ name = (
+ local.create_quota_project
+ ? "net-ngfw-0"
+ : var.ngfw_enterprise_config.quota_project_id
+ )
+ billing_account = (
+ local.create_quota_project
+ ? var.billing_account.id
+ : null
+ )
+ parent = (
+ local.create_quota_project
+ ? var.folder_ids.networking
+ : null
+ )
+ prefix = (
+ local.create_quota_project
+ ? var.prefix
+ : null
+ )
+ project_create = (
+ local.create_quota_project
+ ? true
+ : false
+ )
+ services = ["networksecurity.googleapis.com"]
+}
+
+resource "google_network_security_firewall_endpoint" "firewall_endpoint" {
+ for_each = toset(var.ngfw_enterprise_config.endpoint_zones)
+ name = "${var.prefix}-ngfw-endpoint-${each.key}"
+ parent = "organizations/${var.organization.id}"
+ location = each.value
+ billing_project_id = module.ngfw-quota-project.id
+}
diff --git a/fast/stages/3-network-security/net-dev.tf b/fast/stages/3-network-security/net-dev.tf
new file mode 100644
index 0000000000..408a4e4ec0
--- /dev/null
+++ b/fast/stages/3-network-security/net-dev.tf
@@ -0,0 +1,59 @@
+/**
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+# tfdoc:file:description Security components for dev spoke VPC.
+
+resource "google_network_security_security_profile" "dev_sec_profile" {
+ name = "${var.prefix}-dev-sp-0"
+ type = "THREAT_PREVENTION"
+ parent = "organizations/${var.organization.id}"
+ location = "global"
+}
+
+resource "google_network_security_security_profile_group" "dev_sec_profile_group" {
+ name = "${var.prefix}-dev-spg-0"
+ parent = "organizations/${var.organization.id}"
+ location = "global"
+ description = "Dev security profile group."
+ threat_prevention_profile = try(google_network_security_security_profile.dev_sec_profile.id, null)
+}
+
+resource "google_network_security_firewall_endpoint_association" "dev_fw_ep_association" {
+ for_each = toset(var.ngfw_enterprise_config.endpoint_zones)
+ name = "${var.prefix}-dev-epa-${each.key}"
+ parent = "projects/${try(var.host_project_ids.dev-spoke-0, null)}"
+ location = each.value
+ firewall_endpoint = google_network_security_firewall_endpoint.firewall_endpoint[each.key].id
+ network = try(local.vpc_ids.dev-spoke-0, null)
+}
+
+module "dev-spoke-firewall-policy" {
+ source = "../../../modules/net-firewall-policy"
+ name = "${var.prefix}-dev-fw-policy"
+ parent_id = try(var.host_project_ids.dev-spoke-0, null)
+ region = "global"
+ security_profile_group_ids = {
+ dev = "//networksecurity.googleapis.com/${try(google_network_security_security_profile_group.dev_sec_profile_group.id, "")}"
+ }
+ attachments = {
+ dev-spoke = try(var.vpc_self_links.dev-spoke-0, null)
+ }
+ factories_config = {
+ cidr_file_path = var.factories_config.cidrs
+ egress_rules_file_path = "${var.factories_config.firewall_policy_rules.dev}/egress.yaml"
+ ingress_rules_file_path = "${var.factories_config.firewall_policy_rules.dev}/ingress.yaml"
+ }
+}
diff --git a/fast/stages/3-network-security/net-prod.tf b/fast/stages/3-network-security/net-prod.tf
new file mode 100644
index 0000000000..bffdf133c8
--- /dev/null
+++ b/fast/stages/3-network-security/net-prod.tf
@@ -0,0 +1,59 @@
+/**
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+# tfdoc:file:description Security components for prod spoke VPC.
+
+resource "google_network_security_security_profile" "prod_sec_profile" {
+ name = "${var.prefix}-prod-sp-0"
+ type = "THREAT_PREVENTION"
+ parent = "organizations/${var.organization.id}"
+ location = "global"
+}
+
+resource "google_network_security_security_profile_group" "prod_sec_profile_group" {
+ name = "${var.prefix}-prod-spg-0"
+ parent = "organizations/${var.organization.id}"
+ location = "global"
+ description = "prod security profile group."
+ threat_prevention_profile = try(google_network_security_security_profile.prod_sec_profile.id, null)
+}
+
+resource "google_network_security_firewall_endpoint_association" "prod_fw_ep_association" {
+ for_each = toset(var.ngfw_enterprise_config.endpoint_zones)
+ name = "${var.prefix}-prod-epa-${each.key}"
+ parent = "projects/${try(var.host_project_ids.prod-spoke-0, null)}"
+ location = each.value
+ firewall_endpoint = google_network_security_firewall_endpoint.firewall_endpoint[each.key].id
+ network = try(local.vpc_ids.prod-spoke-0, null)
+}
+
+module "prod-spoke-firewall-policy" {
+ source = "../../../modules/net-firewall-policy"
+ name = "${var.prefix}-prod-fw-policy"
+ parent_id = try(var.host_project_ids.prod-spoke-0, null)
+ region = "global"
+ security_profile_group_ids = {
+ prod = "//networksecurity.googleapis.com/${try(google_network_security_security_profile_group.prod_sec_profile_group.id, "")}"
+ }
+ attachments = {
+ prod-spoke = try(var.vpc_self_links.prod-spoke-0, null)
+ }
+ factories_config = {
+ cidr_file_path = var.factories_config.cidrs
+ egress_rules_file_path = "${var.factories_config.firewall_policy_rules.prod}/egress.yaml"
+ ingress_rules_file_path = "${var.factories_config.firewall_policy_rules.prod}/ingress.yaml"
+ }
+}
diff --git a/fast/stages/3-network-security/outputs.tf b/fast/stages/3-network-security/outputs.tf
new file mode 100644
index 0000000000..ce93d8e512
--- /dev/null
+++ b/fast/stages/3-network-security/outputs.tf
@@ -0,0 +1,28 @@
+/**
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+output "ngfw_enterprise_endpoint_ids" {
+ description = "The NGFW Enterprise endpoint ids."
+ value = {
+ for _, v in google_network_security_firewall_endpoint.firewall_endpoint
+ : v.location => v.id
+ }
+}
+
+output "ngfw_enterprise_endpoints_quota_project" {
+ description = "The NGFW Enterprise endpoints quota project."
+ value = module.ngfw-quota-project.id
+}
diff --git a/fast/stages/3-network-security/variables-fast.tf b/fast/stages/3-network-security/variables-fast.tf
new file mode 100644
index 0000000000..7a65658b0f
--- /dev/null
+++ b/fast/stages/3-network-security/variables-fast.tf
@@ -0,0 +1,80 @@
+/**
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+variable "billing_account" {
+ # tfdoc:variable:source 0-bootstrap
+ description = "Billing account id. If billing account is not part of the same org set `is_org_level` to false."
+ type = object({
+ id = string
+ is_org_level = optional(bool, true)
+ })
+ validation {
+ condition = var.billing_account.is_org_level != null
+ error_message = "Invalid `null` value for `billing_account.is_org_level`."
+ }
+}
+
+variable "folder_ids" {
+ # tfdoc:variable:source 1-resman
+ description = "Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created."
+ type = object({
+ networking = string
+ networking-dev = string
+ networking-prod = string
+ })
+ nullable = false
+}
+
+variable "host_project_ids" {
+ # tfdoc:variable:source 2-networking
+ description = "Host project for the shared VPC."
+ type = object({
+ dev-spoke-0 = optional(string)
+ prod-spoke-0 = optional(string)
+ })
+ nullable = false
+ default = {}
+}
+
+variable "organization" {
+ # tfdoc:variable:source 00-globals
+ description = "Organization details."
+ type = object({
+ domain = string
+ id = number
+ customer_id = string
+ })
+}
+
+variable "prefix" {
+ # tfdoc:variable:source 0-bootstrap
+ description = "Prefix used for resources that need unique names. Use a maximum of 9 chars for organizations, and 11 chars for tenants."
+ type = string
+ validation {
+ condition = try(length(var.prefix), 0) < 12
+ error_message = "Use a maximum of 9 chars for organizations, and 11 chars for tenants."
+ }
+}
+
+variable "vpc_self_links" {
+ # tfdoc:variable:source 2-networking
+ description = "Self link for the shared VPC."
+ type = object({
+ dev-spoke-0 = string
+ prod-spoke-0 = string
+ })
+ nullable = false
+}
diff --git a/fast/stages/3-network-security/variables.tf b/fast/stages/3-network-security/variables.tf
new file mode 100644
index 0000000000..d291577fc7
--- /dev/null
+++ b/fast/stages/3-network-security/variables.tf
@@ -0,0 +1,49 @@
+/**
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+variable "factories_config" {
+ description = "Configuration for network resource factories."
+ type = object({
+ cidrs = optional(string, "data/cidrs.yaml")
+ firewall_policy_rules = optional(object({
+ dev = string
+ prod = string
+ }))
+ })
+ nullable = false
+ default = {
+ firewall_policy_rules = {
+ dev = "data/firewall-policy-rules/dev"
+ prod = "data/firewall-policy-rules/prod"
+ }
+ }
+}
+
+variable "ngfw_enterprise_config" {
+ description = "NGFW Enterprise configuration."
+ type = object({
+ endpoint_zones = list(string)
+ quota_project_id = optional(string, null)
+ })
+ nullable = false
+ default = {
+ endpoint_zones = [
+ "europe-west1-b",
+ "europe-west1-c",
+ "europe-west1-d"
+ ]
+ }
+}
diff --git a/tests/fast/stages/s0_bootstrap/checklist.yaml b/tests/fast/stages/s0_bootstrap/checklist.yaml
index 17ceb250e6..61d5a41c1f 100644
--- a/tests/fast/stages/s0_bootstrap/checklist.yaml
+++ b/tests/fast/stages/s0_bootstrap/checklist.yaml
@@ -201,7 +201,10 @@ 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/cloudasset.viewer','roles/compute.orgFirewallPolicyAdmin','roles/compute.xpnAdmin','roles/orgpolicy.policyAdmin','roles/orgpolicy.policyViewer','roles/resourcemanager.organizationViewer','organizations/123456789012/roles/serviceProjectNetworkAdmin','organizations/123456789012/roles/tenantNetworkAdmin'])
+ expression: |
+ api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly(['roles/accesscontextmanager.policyAdmin','roles/cloudasset.viewer','roles/compute.orgFirewallPolicyAdmin','roles/compute.xpnAdmin','roles/orgpolicy.policyAdmin','roles/orgpolicy.policyViewer','roles/resourcemanager.organizationViewer'])
+ || api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly(['organizations/123456789012/roles/networkFirewallPoliciesAdmin','organizations/123456789012/roles/ngfwEnterpriseAdmin','organizations/123456789012/roles/serviceProjectNetworkAdmin','organizations/123456789012/roles/tenantNetworkAdmin'])
+
title: automation_sa_delegated_grants
members:
- serviceAccount:fast-prod-resman-0@fast-prod-iac-core-0.iam.gserviceaccount.com
@@ -376,15 +379,15 @@ counts:
google_logging_organization_sink: 4
google_logging_project_bucket_config: 4
google_org_policy_policy: 22
- google_organization_iam_binding: 28
- google_organization_iam_custom_role: 7
+ google_organization_iam_binding: 29
+ google_organization_iam_custom_role: 9
google_organization_iam_member: 41
google_project: 3
google_project_iam_audit_config: 1
google_project_iam_binding: 19
google_project_iam_member: 16
- google_project_service: 30
- google_project_service_identity: 6
+ google_project_service: 31
+ google_project_service_identity: 7
google_service_account: 6
google_service_account_iam_binding: 2
google_service_account_iam_member: 1
@@ -396,4 +399,4 @@ counts:
google_tags_tag_key: 1
google_tags_tag_value: 1
modules: 21
- resources: 230
+ resources: 235
diff --git a/tests/fast/stages/s0_bootstrap/simple.yaml b/tests/fast/stages/s0_bootstrap/simple.yaml
index f31425e692..76a2521437 100644
--- a/tests/fast/stages/s0_bootstrap/simple.yaml
+++ b/tests/fast/stages/s0_bootstrap/simple.yaml
@@ -20,15 +20,15 @@ counts:
google_logging_organization_sink: 4
google_logging_project_bucket_config: 4
google_org_policy_policy: 22
- google_organization_iam_binding: 28
- google_organization_iam_custom_role: 7
+ google_organization_iam_binding: 29
+ google_organization_iam_custom_role: 9
google_organization_iam_member: 28
google_project: 3
google_project_iam_audit_config: 1
google_project_iam_binding: 19
google_project_iam_member: 16
- google_project_service: 30
- google_project_service_identity: 6
+ google_project_service: 31
+ google_project_service_identity: 7
google_service_account: 6
google_service_account_iam_binding: 2
google_service_account_iam_member: 1
@@ -41,11 +41,16 @@ counts:
google_tags_tag_value: 1
local_file: 10
modules: 20
- resources: 224
+ resources: 229
+
outputs:
+ automation: __missing__
+ billing_dataset: __missing__
cicd_repositories: {}
custom_roles:
gcve_network_admin: organizations/123456789012/roles/gcveNetworkAdmin
+ network_firewall_policies_admin: organizations/123456789012/roles/networkFirewallPoliciesAdmin
+ ngfw_enterprise_admin: organizations/123456789012/roles/ngfwEnterpriseAdmin
organization_admin_viewer: organizations/123456789012/roles/organizationAdminViewer
organization_iam_admin: organizations/123456789012/roles/organizationIamAdmin
service_project_network_admin: organizations/123456789012/roles/serviceProjectNetworkAdmin
@@ -66,4 +71,3 @@ outputs:
workload_identity_pool:
pool: null
providers: {}
-
diff --git a/tests/fast/stages/s1_resman/checklist.tfvars b/tests/fast/stages/s1_resman/checklist.tfvars
index cd037f897b..7629428051 100644
--- a/tests/fast/stages/s1_resman/checklist.tfvars
+++ b/tests/fast/stages/s1_resman/checklist.tfvars
@@ -13,10 +13,12 @@ billing_account = {
}
custom_roles = {
# organization_iam_admin = "organizations/123456789012/roles/organizationIamAdmin",
- gcve_network_admin = "organizations/123456789012/roles/gcveNetworkAdmin"
- organization_admin_viewer = "organizations/123456789012/roles/organizationAdminViewer"
- service_project_network_admin = "organizations/123456789012/roles/xpnServiceAdmin"
- storage_viewer = "organizations/123456789012/roles/storageViewer"
+ gcve_network_admin = "organizations/123456789012/roles/gcveNetworkAdmin"
+ network_firewall_policies_admin = "organizations/123456789012/roles/networkFirewallPoliciesAdmin"
+ ngfw_enterprise_admin = "organizations/123456789012/roles/ngfwEnterpriseAdmin"
+ organization_admin_viewer = "organizations/123456789012/roles/organizationAdminViewer"
+ service_project_network_admin = "organizations/123456789012/roles/xpnServiceAdmin"
+ storage_viewer = "organizations/123456789012/roles/storageViewer"
}
factories_config = {
checklist_data = "checklist-data.json"
diff --git a/tests/fast/stages/s1_resman/checklist.yaml b/tests/fast/stages/s1_resman/checklist.yaml
index eed5d8498c..5128a8291b 100644
--- a/tests/fast/stages/s1_resman/checklist.yaml
+++ b/tests/fast/stages/s1_resman/checklist.yaml
@@ -416,17 +416,17 @@ values:
counts:
google_folder: 56
- google_folder_iam_binding: 69
- google_organization_iam_member: 6
- google_project_iam_member: 4
- google_service_account: 4
- google_service_account_iam_binding: 4
- google_storage_bucket: 2
- google_storage_bucket_iam_binding: 4
- google_storage_bucket_iam_member: 4
- google_storage_bucket_object: 5
+ google_folder_iam_binding: 71
+ google_organization_iam_member: 8
+ google_project_iam_member: 6
+ google_service_account: 6
+ google_service_account_iam_binding: 6
+ google_storage_bucket: 3
+ google_storage_bucket_iam_binding: 6
+ google_storage_bucket_iam_member: 6
+ google_storage_bucket_object: 7
google_tags_tag_binding: 4
google_tags_tag_key: 2
google_tags_tag_value: 9
- modules: 63
- resources: 173
+ modules: 66
+ resources: 190
diff --git a/tests/fast/stages/s1_resman/simple.tfvars b/tests/fast/stages/s1_resman/simple.tfvars
index 520722b48f..16c762f1f2 100644
--- a/tests/fast/stages/s1_resman/simple.tfvars
+++ b/tests/fast/stages/s1_resman/simple.tfvars
@@ -13,10 +13,12 @@ billing_account = {
}
custom_roles = {
# organization_iam_admin = "organizations/123456789012/roles/organizationIamAdmin",
- gcve_network_admin = "organizations/123456789012/roles/gcveNetworkAdmin"
- organization_admin_viewer = "organizations/123456789012/roles/organizationAdminViewer"
- service_project_network_admin = "organizations/123456789012/roles/xpnServiceAdmin"
- storage_viewer = "organizations/123456789012/roles/storageViewer"
+ gcve_network_admin = "organizations/123456789012/roles/gcveNetworkAdmin"
+ network_firewall_policies_admin = "organizations/123456789012/roles/networkFirewallPoliciesAdmin"
+ ngfw_enterprise_admin = "organizations/123456789012/roles/ngfwEnterpriseAdmin"
+ organization_admin_viewer = "organizations/123456789012/roles/organizationAdminViewer"
+ service_project_network_admin = "organizations/123456789012/roles/xpnServiceAdmin"
+ storage_viewer = "organizations/123456789012/roles/storageViewer"
}
groups = {
gcp-billing-admins = "gcp-billing-admins",
diff --git a/tests/fast/stages/s1_resman/simple.yaml b/tests/fast/stages/s1_resman/simple.yaml
index 06108848e3..fdcd50cce2 100644
--- a/tests/fast/stages/s1_resman/simple.yaml
+++ b/tests/fast/stages/s1_resman/simple.yaml
@@ -14,17 +14,17 @@
counts:
google_folder: 4
- google_folder_iam_binding: 23
- google_organization_iam_member: 6
- google_project_iam_member: 4
- google_service_account: 4
- google_service_account_iam_binding: 4
- google_storage_bucket: 2
- google_storage_bucket_iam_binding: 4
- google_storage_bucket_iam_member: 4
- google_storage_bucket_object: 5
+ google_folder_iam_binding: 25
+ google_organization_iam_member: 8
+ google_project_iam_member: 6
+ google_service_account: 6
+ google_service_account_iam_binding: 6
+ google_storage_bucket: 3
+ google_storage_bucket_iam_binding: 6
+ google_storage_bucket_iam_member: 6
+ google_storage_bucket_object: 7
google_tags_tag_binding: 4
google_tags_tag_key: 2
google_tags_tag_value: 9
- modules: 11
- resources: 75
+ modules: 14
+ resources: 92
diff --git a/tests/fast/stages/s1_tenant_factory/simple.tfvars b/tests/fast/stages/s1_tenant_factory/simple.tfvars
index dc6636d13f..cad9f280d8 100644
--- a/tests/fast/stages/s1_tenant_factory/simple.tfvars
+++ b/tests/fast/stages/s1_tenant_factory/simple.tfvars
@@ -14,11 +14,13 @@ billing_account = {
}
custom_roles = {
# organization_iam_admin = "organizations/123456789012/roles/organizationIamAdmin",
- gcve_network_admin = "organizations/123456789012/roles/gcveNetworkAdmin"
- organization_admin_viewer = "organizations/123456789012/roles/organizationAdminViewer"
- service_project_network_admin = "organizations/123456789012/roles/xpnServiceAdmin"
- storage_viewer = "organizations/123456789012/roles/storageViewer"
- tenant_network_admin = "organizations/123456789012/roles/tenantNetworkAdmin"
+ gcve_network_admin = "organizations/123456789012/roles/gcveNetworkAdmin"
+ network_firewall_policies_admin = "organizations/123456789012/roles/networkFirewallPoliciesAdmin"
+ ngfw_enterprise_admin = "organizations/123456789012/roles/ngfwEnterpriseAdmin"
+ organization_admin_viewer = "organizations/123456789012/roles/organizationAdminViewer"
+ service_project_network_admin = "organizations/123456789012/roles/xpnServiceAdmin"
+ storage_viewer = "organizations/123456789012/roles/storageViewer"
+ tenant_network_admin = "organizations/123456789012/roles/tenantNetworkAdmin"
}
groups = {
gcp-billing-admins = "gcp-billing-admins",
diff --git a/tests/fast/stages/s2_networking_a_simple/ncc.yaml b/tests/fast/stages/s2_networking_a_simple/ncc.yaml
index 997240ce9f..1e8f149deb 100644
--- a/tests/fast/stages/s2_networking_a_simple/ncc.yaml
+++ b/tests/fast/stages/s2_networking_a_simple/ncc.yaml
@@ -38,8 +38,9 @@ counts:
google_project: 3
google_project_iam_binding: 4
google_project_iam_member: 18
- google_project_service: 22
- google_project_service_identity: 16
+ google_project_service: 24
+ google_project_service_identity: 18
google_storage_bucket_object: 2
+ google_vpc_access_connector: 2
modules: 24
- resources: 169
+ resources: 173
diff --git a/tests/fast/stages/s2_networking_a_simple/simple.yaml b/tests/fast/stages/s2_networking_a_simple/simple.yaml
index be0dc8ab80..844d6216f1 100644
--- a/tests/fast/stages/s2_networking_a_simple/simple.yaml
+++ b/tests/fast/stages/s2_networking_a_simple/simple.yaml
@@ -42,10 +42,10 @@ counts:
google_project: 3
google_project_iam_binding: 4
google_project_iam_member: 17
- google_project_service: 21
- google_project_service_identity: 15
+ google_project_service: 23
+ google_project_service_identity: 17
google_storage_bucket_object: 2
google_vpc_access_connector: 2
modules: 29
random_id: 1
- resources: 181
+ resources: 185
diff --git a/tests/fast/stages/s2_networking_a_simple/vpn.yaml b/tests/fast/stages/s2_networking_a_simple/vpn.yaml
index dc854c64d1..a967425615 100644
--- a/tests/fast/stages/s2_networking_a_simple/vpn.yaml
+++ b/tests/fast/stages/s2_networking_a_simple/vpn.yaml
@@ -40,10 +40,10 @@ counts:
google_project: 3
google_project_iam_binding: 4
google_project_iam_member: 17
- google_project_service: 21
- google_project_service_identity: 15
+ google_project_service: 23
+ google_project_service_identity: 17
google_storage_bucket_object: 2
google_vpc_access_connector: 2
modules: 31
random_id: 5
- resources: 218
+ resources: 222
diff --git a/tests/fast/stages/s2_networking_b_nva/ncc-ra.yaml b/tests/fast/stages/s2_networking_b_nva/ncc-ra.yaml
index 7734e77147..69c26f8c46 100644
--- a/tests/fast/stages/s2_networking_b_nva/ncc-ra.yaml
+++ b/tests/fast/stages/s2_networking_b_nva/ncc-ra.yaml
@@ -45,10 +45,10 @@ counts:
google_project: 3
google_project_iam_binding: 4
google_project_iam_member: 18
- google_project_service: 22
- google_project_service_identity: 16
+ google_project_service: 24
+ google_project_service_identity: 18
google_storage_bucket_object: 2
google_vpc_access_connector: 2
modules: 39
random_id: 2
- resources: 249
+ resources: 253
diff --git a/tests/fast/stages/s2_networking_b_nva/simple.yaml b/tests/fast/stages/s2_networking_b_nva/simple.yaml
index c367869b8f..d88b77b4a9 100644
--- a/tests/fast/stages/s2_networking_b_nva/simple.yaml
+++ b/tests/fast/stages/s2_networking_b_nva/simple.yaml
@@ -47,10 +47,10 @@ counts:
google_project: 3
google_project_iam_binding: 4
google_project_iam_member: 17
- google_project_service: 21
- google_project_service_identity: 15
+ google_project_service: 23
+ google_project_service_identity: 17
google_storage_bucket_object: 2
google_vpc_access_connector: 2
modules: 43
random_id: 2
- resources: 232
+ resources: 236
diff --git a/tests/fast/stages/s2_networking_c_separate_envs/simple.yaml b/tests/fast/stages/s2_networking_c_separate_envs/simple.yaml
index 582ff98c0a..e76d911b18 100644
--- a/tests/fast/stages/s2_networking_c_separate_envs/simple.yaml
+++ b/tests/fast/stages/s2_networking_c_separate_envs/simple.yaml
@@ -40,10 +40,10 @@ counts:
google_project: 2
google_project_iam_binding: 4
google_project_iam_member: 14
- google_project_service: 16
- google_project_service_identity: 12
+ google_project_service: 18
+ google_project_service_identity: 14
google_storage_bucket_object: 2
google_vpc_access_connector: 2
modules: 22
random_id: 2
- resources: 200
+ resources: 204
diff --git a/tests/fast/stages/s3_network_security/__init__.py b/tests/fast/stages/s3_network_security/__init__.py
new file mode 100644
index 0000000000..633bb7f1e4
--- /dev/null
+++ b/tests/fast/stages/s3_network_security/__init__.py
@@ -0,0 +1,13 @@
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/tests/fast/stages/s3_network_security/simple.tfvars b/tests/fast/stages/s3_network_security/simple.tfvars
new file mode 100644
index 0000000000..f713e5af7e
--- /dev/null
+++ b/tests/fast/stages/s3_network_security/simple.tfvars
@@ -0,0 +1,22 @@
+billing_account = {
+ id = "000000-111111-222222"
+}
+folder_ids = {
+ networking = "folders/12345678900"
+ networking-dev = "folders/12345678901"
+ networking-prod = "folders/12345678902"
+}
+host_project_ids = {
+ dev-spoke-0 = "dev-project"
+ prod-spoke-0 = "prod-project"
+}
+organization = {
+ domain = "fast.example.com"
+ id = 123456789012
+ customer_id = "C00000000"
+}
+prefix = "fast2"
+vpc_self_links = {
+ dev-spoke-0 = "https://www.googleapis.com/compute/v1/projects/123456789/networks/vpc-1"
+ prod-spoke-0 = "https://www.googleapis.com/compute/v1/projects/123456789/networks/vpc-2"
+}
diff --git a/tests/fast/stages/s3_network_security/simple.yaml b/tests/fast/stages/s3_network_security/simple.yaml
new file mode 100644
index 0000000000..4deac063da
--- /dev/null
+++ b/tests/fast/stages/s3_network_security/simple.yaml
@@ -0,0 +1,27 @@
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+counts:
+ google_compute_network_firewall_policy: 2
+ google_compute_network_firewall_policy_association: 2
+ google_compute_network_firewall_policy_rule: 4
+ google_network_security_firewall_endpoint: 3
+ google_network_security_firewall_endpoint_association: 6
+ google_network_security_security_profile: 2
+ google_network_security_security_profile_group: 2
+ google_project: 1
+ google_project_service: 1
+ google_project_service_identity: 1
+ modules: 3
+ resources: 24