diff --git a/fast/stage-links.sh b/fast/stage-links.sh
index 5fb2a5e6f..7a2fed3d5 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 72d1419f7..772079b06 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 000000000..eb78791ac
--- /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 000000000..3c54a5834
--- /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 b4fb4793a..bde1b2150 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 da570da52..b7aa68d4a 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 cfe1ffcf6..7159e6f7d 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 000000000..3d941e1f6
--- /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 285e0f500..cc6cac29c 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 000000000..42810bd94
--- /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 0a60182aa..2b54e4854 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 9cd19b489..975cbbde9 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 d1c224c5c..817403cee 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 cd2b76fb9..c6b833362 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 c7a4ff749..f5d8bf90f 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 2cad091e1..2716f2f03 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 ca67b036e..b7eb168cf 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 561d95943..f48917ae7 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 4b8f260a4..f2e52abe5 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 11578eb52..7e1b7e38d 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 43e4eff0c..3d2447647 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 0ba612055..3ee211ba7 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 ba8860e7d..1f3432cd4 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 000000000..9e5cf2ad2
--- /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):
+
+
+
+
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 000000000..3591e95a0
--- /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 000000000..a6edadf1c
--- /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 000000000..272431fa9
--- /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 000000000..397acebe2
--- /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 000000000..e0aa293c5
--- /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 000000000..960cbff20
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 000000000..3c586b458
--- /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 000000000..946dba43f
--- /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 000000000..408a4e4ec
--- /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 000000000..bffdf133c
--- /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 000000000..ce93d8e51
--- /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 000000000..7a65658b0
--- /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 000000000..d291577fc
--- /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 17ceb250e..61d5a41c1 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 f31425e69..76a252143 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 cd037f897..762942805 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 eed5d8498..5128a8291 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 520722b48..16c762f1f 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 06108848e..fdcd50cce 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 dc6636d13..cad9f280d 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 997240ce9..1e8f149de 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 be0dc8ab8..844d6216f 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 dc854c64d..a96742561 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 7734e7714..69c26f8c4 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 c367869b8..d88b77b4a 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 582ff98c0..e76d911b1 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 000000000..633bb7f1e
--- /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 000000000..f713e5af7
--- /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 000000000..4deac063d
--- /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