diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 5866f9506..95c9f041a 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -17,6 +17,7 @@ on: pull_request: branches: - master + - fast-dev jobs: linting: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 42b19dc1c..a05d3d736 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -19,6 +19,7 @@ on: pull_request: branches: - master + - fast-dev workflow_dispatch: inputs: terraform_version: diff --git a/CHANGELOG.md b/CHANGELOG.md index fadcf264a..3d01e91d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,38 @@ All notable changes to this project will be documented in this file. -## [Unreleased] +## [Unreleased] + +## [36.0.0] - 2024-11-22 + +### BLUEPRINTS + +- [[#2648](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2648)] Refactor of FAST resource management and subsequent stages ([ludoo](https://github.com/ludoo)) + +### FAST + +- [[#2714](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2714)] Remove stale resman validation ([juliocc](https://github.com/juliocc)) +- [[#2707](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2707)] Expose `factories_config` for resman top level folders ([juliocc](https://github.com/juliocc)) +- [[#2701](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2701)] Allow disabling network security stage ([juliocc](https://github.com/juliocc)) +- [[#2697](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2697)] Remove REGIONAL/MULTI_REGIONAL buckets from FAST ([juliocc](https://github.com/juliocc)) +- [[#2693](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2693)] Unify usage of top level folders short_name ([juliocc](https://github.com/juliocc)) +- [[#2694](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2694)] Make project iam viewer name consistent with GCP naming ([juliocc](https://github.com/juliocc)) +- [[#2688](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2688)] Streamline environments variable across stages ([ludoo](https://github.com/ludoo)) +- [[#2685](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2685)] Add missing billing roles to project factory ro SA in stage 1 ([ludoo](https://github.com/ludoo)) +- [[#2683](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2683)] Add missing roles to project factory ro SA in stage 1 ([ludoo](https://github.com/ludoo)) +- [[#2656](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2656)] Fix permadiff in bootstrap IAM ([ludoo](https://github.com/ludoo)) +- [[#2652](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2652)] Final fixes for v36.0.0-rc1 ([ludoo](https://github.com/ludoo)) +- [[#2648](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2648)] **incompatible change:** Refactor of FAST resource management and subsequent stages ([ludoo](https://github.com/ludoo)) + +### MODULES + +- [[#2648](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2648)] Refactor of FAST resource management and subsequent stages ([ludoo](https://github.com/ludoo)) + +### TOOLS + +- [[#2688](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2688)] Streamline environments variable across stages ([ludoo](https://github.com/ludoo)) +- [[#2660](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2660)] Refactor changelog for the new release process ([ludoo](https://github.com/ludoo)) +- [[#2648](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2648)] Refactor of FAST resource management and subsequent stages ([ludoo](https://github.com/ludoo)) ## [35.1.0] - 2024-11-22 @@ -59,11 +90,6 @@ All notable changes to this project will be documented in this file. - [[#2631](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2631)] fix Vertex-ML-Ops e2e tests ([wiktorn](https://github.com/wiktorn)) - [[#2653](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2653)] Add required enabled field introduced in Terraform version 5.41.0 ([jacobmammoliti](https://github.com/jacobmammoliti)) -### TOOLS - -- [[#2717](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2717)] Change tfdoc pre-commit hook script to use while read ([rosmo](https://github.com/rosmo)) -- [[#2712](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2712)] Add hierarchical namespace support to GCS module ([juliocc](https://github.com/juliocc)) - ## [35.0.0] - 2024-10-30 @@ -2593,7 +2619,8 @@ All notable changes to this project will be documented in this file. - merge development branch with suite of new modules and end-to-end examples -[Unreleased]: https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/compare/v35.1.0...HEAD +[Unreleased]: https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/compare/v36.0.0...HEAD +[36.0.0]: https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/compare/v35.1.0...v36.0.0 [35.1.0]: https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/compare/v35.0.0...v35.1.0 [35.0.0]: https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/compare/v34.1.0...v35.0.0 [34.1.0]: https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/compare/v34.0.0...v34.1.0 diff --git a/blueprints/README.md b/blueprints/README.md index b3d8d423c..5554d57c1 100644 --- a/blueprints/README.md +++ b/blueprints/README.md @@ -8,7 +8,7 @@ Currently available blueprints: - **cloud operations** - [Active Directory Federation Services](./cloud-operations/adfs), [Cloud Asset Inventory feeds for resource change tracking and remediation](./cloud-operations/asset-inventory-feed-remediation), [Fine-grained Cloud DNS IAM via Service Directory](./cloud-operations/dns-fine-grained-iam), [Cloud DNS & Shared VPC design](./cloud-operations/dns-shared-vpc), [Delegated Role Grants](./cloud-operations/iam-delegated-role-grants), [Network Quota Monitoring](./cloud-operations/network-quota-monitoring), [Managing on-prem service account keys by uploading public keys](./cloud-operations/onprem-sa-key-management), [Compute Image builder with Hashicorp Packer](./cloud-operations/packer-image-builder), [Packer example](./cloud-operations/packer-image-builder/packer), [Compute Engine quota monitoring](./cloud-operations/compute-quota-monitoring), [Scheduled Cloud Asset Inventory Export to Bigquery](./cloud-operations/scheduled-asset-inventory-export-bq), [Configuring workload identity federation with Terraform Cloud/Enterprise workflows](./cloud-operations/terraform-cloud-dynamic-credentials), [TCP healthcheck and restart for unmanaged GCE instances](./cloud-operations/unmanaged-instances-healthcheck), [Migrate for Compute Engine (v5) blueprints](./cloud-operations/vm-migration), [Configuring workload identity federation to access Google Cloud resources from apps running on Azure](./cloud-operations/workload-identity-federation) - **data solutions** - [GCE and GCS CMEK via centralized Cloud KMS](./data-solutions/cmek-via-centralized-kms), [Cloud Composer version 2 private instance, supporting Shared VPC and external CMEK key](./data-solutions/composer-2), [Cloud SQL instance with multi-region read replicas](./data-solutions/cloudsql-multiregion), [Data Platform](./data-solutions/data-platform-foundations), [Minimal Data Platform](./data-solutions/data-platform-minimal), [Spinning up a foundation data pipeline on Google Cloud using Cloud Storage, Dataflow and BigQuery](./data-solutions/gcs-to-bq-with-least-privileges), [#SQL Server Always On Groups blueprint](./data-solutions/sqlserver-alwayson), [Data Playground](./data-solutions/data-playground), [MLOps with Vertex AI](./data-solutions/vertex-mlops), [Shielded Folder](./data-solutions/shielded-folder), [BigQuery ML and Vertex AI Pipeline](./data-solutions/bq-ml) - **factories** - [Fabric resource factories](./factories) -- **GKE** - [Binary Authorization Pipeline Blueprint](./gke/binauthz), [Storage API](./gke/binauthz/image), [Multi-cluster mesh on GKE (fleet API)](./gke/multi-cluster-mesh-gke-fleet-api), [GKE Multitenant Blueprint](./gke/multitenant-fleet), [Shared VPC with GKE support](./networking/shared-vpc-gke/), [GKE Autopilot](./gke/autopilot) +- **GKE** - [Binary Authorization Pipeline Blueprint](./gke/binauthz), [Storage API](./gke/binauthz/image), [Multi-cluster mesh on GKE (fleet API)](./gke/multi-cluster-mesh-gke-fleet-api), [GKE Multitenant](../fast/stages/3-gke-dev), [Shared VPC with GKE support](./networking/shared-vpc-gke/), [GKE Autopilot](./gke/autopilot) - **networking** - [Calling a private Cloud Function from On-premises](./networking/private-cloud-function-from-onprem), [HA VPN over Interconnect](./networking/ha-vpn-over-interconnect/), [GLB and multi-regional daisy-chaining through hybrid NEGs](./networking/glb-hybrid-neg-internal), [Hybrid connectivity to on-premise services through PSC](./networking/psc-hybrid), [HTTP Load Balancer with Cloud Armor](./networking/glb-and-armor), [Internal Load Balancer as Next Hop](./networking/ilb-next-hop), On-prem DNS and Google Private Access, [PSC Producer](./networking/psc-hybrid/psc-producer), [PSC Consumer](./networking/psc-hybrid/psc-consumer), [Shared VPC with optional GKE cluster](./networking/shared-vpc-gke), [VPC Connectivity Lab](./networking/vpc-connectivity-lab/) - **SecOps** - [SecOps GKE Forwarder](./secops/secops-gke-forwarder) - **serverless** - [Cloud Run series](./serverless/cloud-run-explore) diff --git a/blueprints/data-solutions/data-platform-foundations/README.md b/blueprints/data-solutions/data-platform-foundations/README.md index 1a9f2ddad..14d74b865 100644 --- a/blueprints/data-solutions/data-platform-foundations/README.md +++ b/blueprints/data-solutions/data-platform-foundations/README.md @@ -23,7 +23,7 @@ The approach adapts to different high-level requirements: - least privilege principle - rely on service account impersonation -The code in this blueprint doesn't address Organization-level configurations (Organization policy, VPC-SC, centralized logs). We expect those elements to be managed by automation stages external to this script like those in [FAST](../../../fast) and this blueprint deployed on top of them as one of the [stages](../../../fast/stages/3-data-platform/dev/README.md). +The code in this blueprint doesn't address Organization-level configurations (Organization policy, VPC-SC, centralized logs). We expect those elements to be managed by automation stages external to this script like those in [FAST](../../../fast). ### Project structure diff --git a/blueprints/data-solutions/data-platform-minimal/README.md b/blueprints/data-solutions/data-platform-minimal/README.md index 1f6e73968..ab0f0880c 100644 --- a/blueprints/data-solutions/data-platform-minimal/README.md +++ b/blueprints/data-solutions/data-platform-minimal/README.md @@ -49,7 +49,7 @@ The approach adapts to different high-level requirements: - least privilege principle - rely on service account impersonation -The code in this blueprint doesn't address Organization-level configurations (Organization policy, VPC-SC, centralized logs). We expect those elements to be managed by automation stages external to this script like those in [FAST](../../../fast) and this blueprint deployed on top of them as one of the [stages](../../../fast/stages/3-data-platform/dev/README.md). +The code in this blueprint doesn't address Organization-level configurations (Organization policy, VPC-SC, centralized logs). We expect those elements to be managed by automation stages external to this script like those in [FAST](../../../fast). ## Project structure diff --git a/blueprints/gcve/pc-minimal/README.md b/blueprints/gcve/pc-minimal/README.md deleted file mode 100644 index f225de3e3..000000000 --- a/blueprints/gcve/pc-minimal/README.md +++ /dev/null @@ -1,106 +0,0 @@ -# GCVE Private Cloud Minimal - -This blueprint presents an opinionated architecture to handle different Google VMware Engine deployment scenarios: from a simple single region private cloud to multi-region private clouds spread across different locations. The general idea behind this blueprint is to deploy a single project hosting one or more GCVE private clouds connected to a shared VMware Engine Network (VEN). -Optionally this blueprint can deploy the VMWare Engine Network peerings to pre-existing VPCs. - -Multiple deployments of this blueprint allow the user to achieve more complex design solutions as for example GCVE private clouds deployed on different projects or connected to independent VMWare Engine Networks. - -This blueprint is used as part of the [FAST GCVE stage](../../../fast/stages/3-gcve/) but it can also be used independently if desired. - -
-
-
gcve-private-cloud | google_vmwareengine_network_peering |
-| [main.tf](./main.tf) | Project. | project | |
-| [output.tf](./output.tf) | Output variables. | | |
-| [variables.tf](./variables.tf) | Module variables. | | |
-
-## Variables
-
-| name | description | type | required | default |
-|---|---|:---:|:---:|:---:|
-| [billing_account_id](variables.tf#L17) | Billing account ID. | string | ✓ | |
-| [folder_id](variables.tf#L22) | Folder used for the GCVE project in folders/nnnnnnnnnnn format. | string | ✓ | |
-| [groups](variables.tf#L27) | GCVE groups. | object({…}) | ✓ | |
-| [prefix](variables.tf#L81) | Prefix used for resource names. | string | ✓ | |
-| [private_cloud_configs](variables.tf#L90) | The VMware private cloud configurations. The key is the unique private cloud name suffix. | map(object({…})) | ✓ | |
-| [project_id](variables.tf#L112) | ID of the project that will contain the GCVE private cloud. | string | ✓ | |
-| [iam](variables.tf#L36) | Project-level authoritative IAM bindings for users and service accounts in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} |
-| [iam_by_principals](variables.tf#L43) | Authoritative IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid cycle errors. Merged internally with the `iam` variable. | map(list(string)) | | {} |
-| [labels](variables.tf#L50) | Project-level labels. | map(string) | | {} |
-| [network_peerings](variables.tf#L56) | The network peerings between users' VPCs and the VMware Engine networks. The key is the peering name suffix. | map(object({…})) | | {} |
-| [project_services](variables.tf#L117) | Additional project services to enable. | list(string) | | [] |
-
diff --git a/blueprints/gcve/pc-minimal/gcve-pc.tf b/blueprints/gcve/pc-minimal/gcve-pc.tf
deleted file mode 100644
index 2cbd1e1e2..000000000
--- a/blueprints/gcve/pc-minimal/gcve-pc.tf
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * 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 GCVE private cloud.
-locals {
- ven_peerings = {
- for k, v in var.network_peerings : k => {
- peer_network = v.peer_network
- description = v.description
- export_custom_routes = v.custom_routes.export_to_peer
- export_custom_routes_with_public_ip = v.custom_routes_with_public_ip.export_to_peer
- import_custom_routes = v.custom_routes.import_from_peer
- import_custom_routes_with_public_ip = v.custom_routes_with_public_ip.import_from_peer
- peer_to_vmware_engine_network = v.peer_to_vmware_engine_network
- }
- }
-}
-module "gcve-pc" {
- source = "../../../modules/gcve-private-cloud"
- prefix = var.prefix
- project_id = module.gcve-project-0.id
-
- vmw_network_config = {
- create = true
- name = "default"
- }
- vmw_network_peerings = local.ven_peerings
-
- vmw_private_cloud_configs = var.private_cloud_configs
-}
-
-resource "google_vmwareengine_network_peering" "vmw_engine_network_peerings" {
- provider = google-beta
- for_each = { for k, v in var.network_peerings : k => v if v.configure_peer_network }
- peer_network = each.value.peer_network
- name = "${var.prefix}-${each.key}"
- description = each.value.description
- export_custom_routes = each.value.custom_routes.export_to_ven
- export_custom_routes_with_public_ip = each.value.custom_routes_with_public_ip.export_to_ven
- import_custom_routes = each.value.custom_routes.import_from_ven
- import_custom_routes_with_public_ip = each.value.custom_routes_with_public_ip.import_from_ven
- peer_network_type = "STANDARD"
- project = each.value.peer_project_id
- vmware_engine_network = module.gcve-pc.vmw_private_cloud_network.id
-}
diff --git a/blueprints/gcve/pc-minimal/main.tf b/blueprints/gcve/pc-minimal/main.tf
deleted file mode 100644
index 2d9f5c8ef..000000000
--- a/blueprints/gcve/pc-minimal/main.tf
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * 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 Project.
-
-module "gcve-project-0" {
- source = "../../../modules/project"
- billing_account = var.billing_account_id
- name = var.project_id
- parent = var.folder_id
- prefix = var.prefix
- iam_by_principals = merge({
- (var.groups.gcp-gcve-admins) = ["roles/vmwareengine.vmwareengineAdmin"]
- (var.groups.gcp-gcve-viewers) = ["roles/vmwareengine.vmwareengineViewer"]
- },
- var.iam_by_principals
- )
- iam = var.iam
- labels = var.labels
- services = concat([
- "vmwareengine.googleapis.com",
- ],
- var.project_services
- )
- # specify project-level org policies here if you need them
-}
diff --git a/blueprints/gke/README.md b/blueprints/gke/README.md
index acba2a8f4..2e1575231 100644
--- a/blueprints/gke/README.md
+++ b/blueprints/gke/README.md
@@ -20,7 +20,7 @@ They are meant to be used as minimal but complete starting points to create actu
### Multitenant GKE fleet
-
This [blueprint](./multitenant-fleet/) allows simple centralized management of similar sets of GKE clusters and their nodepools in a single project, and optional fleet management via GKE Hub templated configurations.
+
This [blueprint](../../fast/stages/3-gke-dev/) allows simple centralized management of similar sets of GKE clusters and their nodepools in a single project, and optional fleet management via GKE Hub templated configurations.
-
-
gke-cluster-standard |
-| [gke-hub.tf](./gke-hub.tf) | GKE hub configuration. | gke-hub |
-| [gke-nodepools.tf](./gke-nodepools.tf) | GKE nodepools. | gke-nodepool |
-| [main.tf](./main.tf) | Project and usage dataset. | bigquery-dataset · iam-service-account · project |
-| [outputs.tf](./outputs.tf) | Output variables. | |
-| [variables.tf](./variables.tf) | Module variables. | |
-
-## Variables
-
-| name | description | type | required | default |
-|---|---|:---:|:---:|:---:|
-| [billing_account_id](variables.tf#L17) | Billing account ID. | string | ✓ | |
-| [folder_id](variables.tf#L131) | Folder used for the GKE project in folders/nnnnnnnnnnn format. | string | ✓ | |
-| [prefix](variables.tf#L189) | Prefix used for resource names. | string | ✓ | |
-| [project_id](variables.tf#L198) | ID of the project that will contain all the clusters. | string | ✓ | |
-| [vpc_config](variables.tf#L210) | Shared VPC project and VPC details. | object({…}) | ✓ | |
-| [clusters](variables.tf#L22) | Clusters configuration. Refer to the gke-cluster module for type details. | map(object({…})) | | {} |
-| [deletion_protection](variables.tf#L89) | Prevent Terraform from destroying data storage resources (storage buckets, GKE clusters, CloudSQL instances) in this blueprint. When this field is set in Terraform state, a terraform destroy or terraform apply that would delete data storage resources will fail. | bool | | false |
-| [fleet_configmanagement_clusters](variables.tf#L96) | Config management features enabled on specific sets of member clusters, in config name => [cluster name] format. | map(list(string)) | | {} |
-| [fleet_configmanagement_templates](variables.tf#L103) | Sets of config management configurations that can be applied to member clusters, in config name => {options} format. | map(any) | | {} |
-| [fleet_features](variables.tf#L111) | Enable and configure fleet features. Set to null to disable GKE Hub if fleet workload identity is not used. | object({…}) | | null |
-| [fleet_workload_identity](variables.tf#L124) | Use Fleet Workload Identity for clusters. Enables GKE Hub if set to true. | bool | | false |
-| [iam](variables.tf#L136) | Project-level authoritative IAM bindings for users and service accounts in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} |
-| [iam_by_principals](variables.tf#L143) | Authoritative IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid cycle errors. Merged internally with the `iam` variable. | map(list(string)) | | {} |
-| [labels](variables.tf#L150) | Project-level labels. | map(string) | | {} |
-| [nodepools](variables.tf#L156) | Nodepools configuration. Refer to the gke-nodepool module for type details. | map(map(object({…}))) | | {} |
-| [project_services](variables.tf#L203) | Additional project services to enable. | list(string) | | [] |
-
-## Outputs
-
-| name | description | sensitive |
-|---|---|:---:|
-| [cluster_ids](outputs.tf#L17) | Cluster ids. | |
-| [clusters](outputs.tf#L24) | Cluster resources. | |
-| [project_id](outputs.tf#L29) | GKE project id. | |
-
diff --git a/blueprints/gke/multitenant-fleet/gke-clusters.tf b/blueprints/gke/multitenant-fleet/gke-clusters.tf
deleted file mode 100644
index 8a6fa3211..000000000
--- a/blueprints/gke/multitenant-fleet/gke-clusters.tf
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * Copyright 2023 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 GKE clusters.
-
-module "gke-cluster" {
- source = "../../../modules/gke-cluster-standard"
- for_each = var.clusters
- name = each.key
- project_id = module.gke-project-0.project_id
- cluster_autoscaling = each.value.cluster_autoscaling
- description = each.value.description
- enable_features = each.value.enable_features
- enable_addons = each.value.enable_addons
- issue_client_certificate = each.value.issue_client_certificate
- labels = each.value.labels
- location = each.value.location
- logging_config = each.value.logging_config
- maintenance_config = each.value.maintenance_config
- max_pods_per_node = each.value.max_pods_per_node
- min_master_version = each.value.min_master_version
- monitoring_config = each.value.monitoring_config
- node_locations = each.value.node_locations
- private_cluster_config = each.value.private_cluster_config
- release_channel = each.value.release_channel
- vpc_config = merge(each.value.vpc_config, {
- network = coalesce(
- each.value.vpc_config.network, var.vpc_config.vpc_self_link
- )
- })
- deletion_protection = var.deletion_protection
-}
diff --git a/blueprints/gke/patterns/autopilot-cluster/versions.tf b/blueprints/gke/patterns/autopilot-cluster/versions.tf
index 08cda2815..d498075b0 100644
--- a/blueprints/gke/patterns/autopilot-cluster/versions.tf
+++ b/blueprints/gke/patterns/autopilot-cluster/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/blueprints/gke/patterns/batch/versions.tf b/blueprints/gke/patterns/batch/versions.tf
index 08cda2815..d498075b0 100644
--- a/blueprints/gke/patterns/batch/versions.tf
+++ b/blueprints/gke/patterns/batch/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/blueprints/gke/patterns/kafka/versions.tf b/blueprints/gke/patterns/kafka/versions.tf
index 08cda2815..d498075b0 100644
--- a/blueprints/gke/patterns/kafka/versions.tf
+++ b/blueprints/gke/patterns/kafka/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/blueprints/gke/patterns/kong-cloudrun/versions.tf b/blueprints/gke/patterns/kong-cloudrun/versions.tf
index 08cda2815..d498075b0 100644
--- a/blueprints/gke/patterns/kong-cloudrun/versions.tf
+++ b/blueprints/gke/patterns/kong-cloudrun/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/blueprints/gke/patterns/mysql/versions.tf b/blueprints/gke/patterns/mysql/versions.tf
index 08cda2815..d498075b0 100644
--- a/blueprints/gke/patterns/mysql/versions.tf
+++ b/blueprints/gke/patterns/mysql/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/blueprints/gke/patterns/redis-cluster/versions.tf b/blueprints/gke/patterns/redis-cluster/versions.tf
index 08cda2815..d498075b0 100644
--- a/blueprints/gke/patterns/redis-cluster/versions.tf
+++ b/blueprints/gke/patterns/redis-cluster/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/blueprints/secops/secops-gke-forwarder/versions.tf b/blueprints/secops/secops-gke-forwarder/versions.tf
index 08cda2815..d498075b0 100644
--- a/blueprints/secops/secops-gke-forwarder/versions.tf
+++ b/blueprints/secops/secops-gke-forwarder/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/default-versions.tf b/default-versions.tf
index 08cda2815..3018c9bf9 100644
--- a/default-versions.tf
+++ b/default-versions.tf
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# Fabric release: v35.1.0
+# Fabric release: v36.0.0
terraform {
required_version = ">= 1.7.4"
diff --git a/fast/stage-links.sh b/fast/stage-links.sh
index e66ace3f2..5ad46edd8 100755
--- a/fast/stage-links.sh
+++ b/fast/stage-links.sh
@@ -27,6 +27,9 @@ Usage with GCS output files bucket:
Usage with local output files folder:
stage-links.sh FOLDER_PATH
+
+Point path/GCS URI to the tenant folder in tenant mode:
+ stage-links.sh FOLDER_PATH/TENANT_SHORTNAME
END
exit 0
fi
@@ -52,25 +55,30 @@ case $STAGE_NAME in
"0-bootstrap")
unset GLOBALS
PROVIDER="providers/0-bootstrap-providers.tf"
+ SELF="$STAGE_NAME.auto.tfvars"
TFVARS=""
;;
"1-resman" | "1-tenant-factory")
PROVIDER="providers/${STAGE_NAME}-providers.tf"
+ SELF="$STAGE_NAME.auto.tfvars"
TFVARS="tfvars/0-bootstrap.auto.tfvars.json"
;;
"1-vpcsc")
PROVIDER="providers/1-vpcsc-providers.tf"
+ SELF="$STAGE_NAME.auto.tfvars"
TFVARS="tfvars/0-bootstrap.auto.tfvars.json"
;;
"2-networking"*)
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/2-networking-providers.tf"
+ SELF="2-networking.auto.tfvars"
TFVARS="tfvars/0-bootstrap.auto.tfvars.json
tfvars/1-resman.auto.tfvars.json"
else
unset GLOBALS
PROVIDER="tenants/$TENANT/providers/2-networking-providers.tf"
+ SELF="tenants/$TENANT/2-networking.auto.tfvars"
TFVARS="tenants/$TENANT/tfvars/0-bootstrap-tenant.auto.tfvars.json
tenants/$TENANT/tfvars/1-resman.auto.tfvars.json"
fi
@@ -79,12 +87,14 @@ case $STAGE_NAME in
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/2-project-factory-providers.tf"
+ SELF="$STAGE_NAME.auto.tfvars"
TFVARS="tfvars/0-bootstrap.auto.tfvars.json
tfvars/1-resman.auto.tfvars.json"
EXTRA_FILES="tfvars/2-networking.auto.tfvars.json"
else
unset GLOBALS
PROVIDER="tenants/$TENANT/providers/2-project-factory-providers.tf"
+ SELF="tenants/$TENANT/$STAGE_NAME.auto.tfvars"
TFVARS="tenants/$TENANT/tfvars/0-bootstrap-tenant.auto.tfvars.json
tenants/$TENANT/tfvars/1-resman.auto.tfvars.json"
EXTRA_FILES="tenants/$TENANT/tfvars/2-networking.auto.tfvars.json"
@@ -94,11 +104,13 @@ case $STAGE_NAME in
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/2-security-providers.tf"
+ SELF="$STAGE_NAME.auto.tfvars"
TFVARS="tfvars/0-bootstrap.auto.tfvars.json
tfvars/1-resman.auto.tfvars.json"
else
unset GLOBALS
PROVIDER="tenants/$TENANT/providers/2-security-providers.tf"
+ SELF="tenants/$TENANT/$STAGE_NAME.auto.tfvars"
TFVARS="tenants/$TENANT/tfvars/0-bootstrap-tenant.auto.tfvars.json
tenants/$TENANT/tfvars/1-resman.auto.tfvars.json"
fi
@@ -107,6 +119,7 @@ case $STAGE_NAME in
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-network-security-providers.tf"
+ SELF="$STAGE_NAME.auto.tfvars"
TFVARS="tfvars/0-bootstrap.auto.tfvars.json
tfvars/1-resman.auto.tfvars.json
tfvars/2-networking.auto.tfvars.json
@@ -114,6 +127,7 @@ case $STAGE_NAME in
else
unset GLOBALS
PROVIDER="tenants/$TENANT/providers/3-network-security-providers.tf"
+ SELF="tenants/$TENANT/$STAGE_NAME.auto.tfvars"
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
@@ -156,6 +170,11 @@ for f in $TFVARS; do
echo "$CMD/$f ./"
done
+if [[ ! -z ${SELF+x} ]]; then
+ echo "# conventional place for stage tfvars (manually created)"
+ echo "$CMD/$SELF ./"
+fi
+
if [[ ! -z ${EXTRA_FILES+x} ]]; then
echo "# optional files"
for f in $EXTRA_FILES; do
diff --git a/fast/stages/0-bootstrap/.fast-stage.env b/fast/stages/0-bootstrap/.fast-stage.env
new file mode 100644
index 000000000..a842174c3
--- /dev/null
+++ b/fast/stages/0-bootstrap/.fast-stage.env
@@ -0,0 +1,5 @@
+FAST_STAGE_DESCRIPTION="organization bootstrap"
+FAST_STAGE_LEVEL=0
+FAST_STAGE_NAME=bootstrap
+# FAST_STAGE_DEPS="0-globals 0-bootstrap"
+# FAST_STAGE_OPTIONAL=""
\ No newline at end of file
diff --git a/fast/stages/0-bootstrap/README.md b/fast/stages/0-bootstrap/README.md
index c1887e84a..14f61f818 100644
--- a/fast/stages/0-bootstrap/README.md
+++ b/fast/stages/0-bootstrap/README.md
@@ -399,22 +399,30 @@ Once the initial `apply` completes successfully, configure a remote backend usin
- the GCS bucket where output files are always stored
- Terraform outputs (not recommended as it's more complex)
-The following two snippets show how to leverage the `stage-links.sh` script in the root FAST folder to fetch the commands required for output files linking or copying, using either the local output folder configured via Terraform variables, or the GCS bucket which can be derived from the `automation` output.
+The following two snippets show how to leverage the `fast-links.sh` script in the FAST stages folder to fetch the commands required for output files linking or copying, using either the local output folder configured via Terraform variables, or the GCS bucket which can be derived from the `automation` output.
```bash
-../../stage-links.sh ~/fast-config
+../fast-links.sh ~/fast-config
-# copy and paste the following commands for '0-bootstrap'
+# File linking commands for organization bootstrap stage
-ln -s ~/fast-config/providers/0-bootstrap-providers.tf ./
+# provider file
+ln -s ~/fast-config/fast-test-00/providers/0-bootstrap-providers.tf ./
+
+# conventional place for stage tfvars (manually created)
+ln -s ~/fast-config/fast-test-00/0-bootstrap.auto.tfvars ./
```
```bash
-../../stage-links.sh gs://xxx-prod-iac-core-outputs-0
+../fast-links.sh gs://xxx-prod-iac-core-outputs-0
-# copy and paste the following commands for '0-bootstrap'
+# File linking commands for organization bootstrap stage
+# provider file
gcloud storage cp gs://xxx-prod-iac-core-outputs-0/providers/0-bootstrap-providers.tf ./
+
+# conventional place for stage tfvars (manually created)
+gcloud storage cp gs://xxx-prod-iac-core-outputs-0/0-bootstrap.auto.tfvars ./
```
Copy/paste the command returned by the script to link or copy the provider file, then migrate state with `terraform init` and run `terraform apply`. If your organization was created with "Secure by Default Org Policy", that is with some of the org policies enabled, add `-var 'org_policies_config={"import_defaults": true}'` to `terraform apply`:
@@ -628,7 +636,7 @@ The remaining configuration is manual, as it regards the repositories themselves
- for Gitlab, rename it to `.gitlab-ci.yml` and place it in the repository root
- for Source Repositories, place it in `.cloudbuild/workflow.yaml`
-
+
## Files
@@ -636,7 +644,6 @@ The remaining configuration is manual, as it regards the repositories themselves
|---|---|---|---|
| [automation.tf](./automation.tf) | Automation project and resources. | gcs · iam-service-account · project | |
| [billing.tf](./billing.tf) | Billing export project and dataset. | bigquery-dataset · project | google_billing_account_iam_member |
-| [checklist.tf](./checklist.tf) | None | gcs | google_storage_bucket_object |
| [cicd.tf](./cicd.tf) | Workload Identity Federation configurations for CI/CD. | iam-service-account | |
| [identity-providers-defs.tf](./identity-providers-defs.tf) | Identity provider definitions. | | |
| [identity-providers.tf](./identity-providers.tf) | Workload Identity Federation provider definitions. | | google_iam_workforce_pool · google_iam_workforce_pool_provider · google_iam_workload_identity_pool · google_iam_workload_identity_pool_provider |
@@ -654,41 +661,40 @@ The remaining configuration is manual, as it regards the repositories themselves
| name | description | type | required | default | producer |
|---|---|:---:|:---:|:---:|:---:|
| [billing_account](variables.tf#L17) | Billing account id. If billing account is not part of the same org set `is_org_level` to `false`. To disable handling of billing IAM roles set `no_iam` to `true`. | object({…}) | ✓ | | |
-| [organization](variables.tf#L302) | Organization details. | object({…}) | ✓ | | |
-| [prefix](variables.tf#L317) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | |
+| [organization](variables.tf#L275) | Organization details. | object({…}) | ✓ | | |
+| [prefix](variables.tf#L290) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | |
| [bootstrap_user](variables.tf#L27) | Email of the nominal user running this stage for the first time. | string | | null | |
-| [cicd_backends](variables.tf#L33) | CI/CD backend configuration. Leave null to use GCS buckets for state. | object({…}) | | null | |
-| [cicd_repositories](variables.tf#L69) | CI/CD repository configuration. Identity providers reference keys in the `federated_identity_providers` variable. Set to null to disable, or set individual repositories to null if not needed. | object({…}) | | null | |
-| [custom_roles](variables.tf#L123) | Map of role names => list of permissions to additionally create at the organization level. | map(list(string)) | | {} | |
-| [environments](variables.tf#L130) | Environment names. | map(object({…})) | | {…} | |
-| [essential_contacts](variables.tf#L154) | Email used for essential contacts, unset if null. | string | | null | |
-| [factories_config](variables.tf#L160) | Configuration for the resource factories or external data. | object({…}) | | {} | |
-| [groups](variables.tf#L172) | 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({…}) | | {} | |
-| [iam](variables.tf#L188) | Organization-level custom IAM settings in role => [principal] format. | map(list(string)) | | {} | |
-| [iam_bindings_additive](variables.tf#L195) | Organization-level custom additive IAM bindings. Keys are arbitrary. | map(object({…})) | | {} | |
-| [iam_by_principals](variables.tf#L210) | Authoritative IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid cycle errors. Merged internally with the `iam` variable. | map(list(string)) | | {} | |
-| [locations](variables.tf#L217) | Optional locations for GCS, BigQuery, and logging buckets created here. | object({…}) | | {} | |
-| [log_sinks](variables.tf#L231) | Org-level log sinks, in name => {type, filter} format. | map(object({…})) | | {…} | |
-| [org_policies_config](variables.tf#L284) | Organization policies customization. | object({…}) | | {} | |
-| [outputs_location](variables.tf#L311) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable. | string | | null | |
-| [project_parent_ids](variables.tf#L326) | Optional parents for projects created here in folders/nnnnnnn format. Null values will use the organization as parent. | object({…}) | | {} | |
-| [workforce_identity_providers](variables.tf#L337) | Workforce Identity Federation pools. | map(object({…})) | | {} | |
-| [workload_identity_providers](variables.tf#L353) | Workload Identity Federation pools. The `cicd_repositories` variable references keys here. | map(object({…})) | | {} | |
+| [cicd_repositories](variables.tf#L33) | CI/CD repository configuration. Identity providers reference keys in the `federated_identity_providers` variable. Set to null to disable, or set individual repositories to null if not needed. | object({…}) | | null | |
+| [custom_roles](variables.tf#L87) | Map of role names => list of permissions to additionally create at the organization level. | map(list(string)) | | {} | |
+| [environments](variables.tf#L94) | Environment names. | map(object({…})) | | {…} | |
+| [essential_contacts](variables.tf#L127) | Email used for essential contacts, unset if null. | string | | null | |
+| [factories_config](variables.tf#L133) | Configuration for the resource factories or external data. | object({…}) | | {} | |
+| [groups](variables.tf#L144) | 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({…}) | | {} | |
+| [iam](variables.tf#L160) | Organization-level custom IAM settings in role => [principal] format. | map(list(string)) | | {} | |
+| [iam_bindings_additive](variables.tf#L167) | Organization-level custom additive IAM bindings. Keys are arbitrary. | map(object({…})) | | {} | |
+| [iam_by_principals](variables.tf#L182) | Authoritative IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid cycle errors. Merged internally with the `iam` variable. | map(list(string)) | | {} | |
+| [locations](variables.tf#L189) | Optional locations for GCS, BigQuery, and logging buckets created here. | object({…}) | | {} | |
+| [log_sinks](variables.tf#L203) | Org-level log sinks, in name => {type, filter} format. | map(object({…})) | | {…} | |
+| [org_policies_config](variables.tf#L256) | Organization policies customization. | object({…}) | | {} | |
+| [outputs_location](variables.tf#L284) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable. | string | | null | |
+| [project_parent_ids](variables.tf#L299) | Optional parents for projects created here in folders/nnnnnnn format. Null values will use the organization as parent. | object({…}) | | {} | |
+| [workforce_identity_providers](variables.tf#L310) | Workforce Identity Federation pools. | map(object({…})) | | {} | |
+| [workload_identity_providers](variables.tf#L326) | Workload Identity Federation pools. The `cicd_repositories` variable references keys here. | map(object({…})) | | {} | |
## Outputs
| name | description | sensitive | consumers |
|---|---|:---:|---|
-| [automation](outputs.tf#L184) | Automation resources. | | |
-| [billing_dataset](outputs.tf#L189) | BigQuery dataset prepared for billing export. | | |
-| [cicd_repositories](outputs.tf#L194) | CI/CD repository configurations. | | |
-| [custom_roles](outputs.tf#L206) | Organization-level custom roles. | | |
-| [outputs_bucket](outputs.tf#L211) | GCS bucket where generated output files are stored. | | |
-| [project_ids](outputs.tf#L216) | Projects created by this stage. | | |
-| [providers](outputs.tf#L226) | Terraform provider files for this stage and dependent stages. | ✓ | stage-01 |
-| [service_accounts](outputs.tf#L233) | Automation service accounts created by this stage. | | |
-| [tfvars](outputs.tf#L251) | Terraform variable files for the following stages. | ✓ | |
-| [tfvars_globals](outputs.tf#L257) | Terraform Globals variable files for the following stages. | ✓ | |
-| [workforce_identity_pool](outputs.tf#L263) | Workforce Identity Federation pool. | | |
-| [workload_identity_pool](outputs.tf#L272) | Workload Identity Federation pool and providers. | | |
+| [automation](outputs.tf#L153) | Automation resources. | | |
+| [billing_dataset](outputs.tf#L158) | BigQuery dataset prepared for billing export. | | |
+| [cicd_repositories](outputs.tf#L163) | CI/CD repository configurations. | | |
+| [custom_roles](outputs.tf#L175) | Organization-level custom roles. | | |
+| [outputs_bucket](outputs.tf#L180) | GCS bucket where generated output files are stored. | | |
+| [project_ids](outputs.tf#L185) | Projects created by this stage. | | |
+| [providers](outputs.tf#L195) | Terraform provider files for this stage and dependent stages. | ✓ | stage-01 |
+| [service_accounts](outputs.tf#L202) | Automation service accounts created by this stage. | | |
+| [tfvars](outputs.tf#L211) | Terraform variable files for the following stages. | ✓ | |
+| [tfvars_globals](outputs.tf#L217) | Terraform Globals variable files for the following stages. | ✓ | |
+| [workforce_identity_pool](outputs.tf#L223) | Workforce Identity Federation pool. | | |
+| [workload_identity_pool](outputs.tf#L232) | Workload Identity Federation pool and providers. | | |
diff --git a/fast/stages/0-bootstrap/automation.tf b/fast/stages/0-bootstrap/automation.tf
index 117716a15..0b369aaca 100644
--- a/fast/stages/0-bootstrap/automation.tf
+++ b/fast/stages/0-bootstrap/automation.tf
@@ -38,6 +38,11 @@ module "automation-project" {
? {}
: { (var.essential_contacts) = ["ALL"] }
)
+ factories_config = {
+ org_policies = (
+ var.bootstrap_user != null ? null : var.factories_config.org_policies_iac
+ )
+ }
# human (groups) IAM bindings
iam_by_principals = {
(local.principals.gcp-devops) = [
@@ -117,17 +122,20 @@ module "automation-project" {
role = "roles/serviceusage.serviceUsageViewer"
}
}
- org_policies = var.bootstrap_user != null ? {} : {
- "compute.skipDefaultNetworkCreation" = {
- rules = [{ enforce = true }]
+ org_policies = (
+ var.bootstrap_user != null || var.org_policies_config.iac_policy_member_domains == null
+ ? {}
+ : {
+ "iam.allowedPolicyMemberDomains" = {
+ inherit_from_parent = true
+ rules = [{
+ allow = {
+ values = var.org_policies_config.iac_policy_member_domains
+ }
+ }]
+ }
}
- "iam.automaticIamGrantsForDefaultServiceAccounts" = {
- rules = [{ enforce = true }]
- }
- "iam.disableServiceAccountKeyCreation" = {
- rules = [{ enforce = true }]
- }
- }
+ )
services = concat(
[
"accesscontextmanager.googleapis.com",
diff --git a/fast/stages/0-bootstrap/checklist.tf b/fast/stages/0-bootstrap/checklist.tf
deleted file mode 100644
index 0c52f41ed..000000000
--- a/fast/stages/0-bootstrap/checklist.tf
+++ /dev/null
@@ -1,153 +0,0 @@
-/**
- * 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.
- */
-
-locals {
- # group mapping from checklist to ours
- _cl_groups = {
- BILLING_ADMINS = local.principals.gcp-billing-admins
- DEVOPS = local.principals.gcp-devops
- # LOGGING_ADMINS
- # MONITORING_ADMINS
- NETWORK_ADMINS = local.principals.gcp-network-admins
- ORG_ADMINS = local.principals.gcp-organization-admins
- SECURITY_ADMINS = local.principals.gcp-security-admins
- }
- # parse raw data from JSON files if they exist
- _cl_data_raw = (
- var.factories_config.checklist_data == null
- ? null
- : jsondecode(file(pathexpand(var.factories_config.checklist_data)))
- )
- _cl_org_raw = (
- var.factories_config.checklist_org_iam == null
- ? null
- : jsondecode(file(pathexpand(var.factories_config.checklist_org_iam)))
- )
- # check that files are for the correct organization and ignore them if not
- _cl_data = (
- try(local._cl_data_raw.cloud_setup_config.organization.id, null) != tostring(var.organization.id)
- ? null
- : local._cl_data_raw.cloud_setup_config
- )
- _cl_org = (
- try(local._cl_org_raw.cloud_setup_org_iam.organization.id, null) != tostring(var.organization.id)
- ? null
- : local._cl_org_raw.cloud_setup_org_iam
- )
- # do a first pass on IAM bindings to identify groups and normalize
- _cl_org_iam_bindings = {
- for b in try(local._cl_org.iam_bindings, []) :
- lookup(local._cl_groups, b.group_id, b.principal) => {
- additive = [
- for r in b.role : r if !contains(local.iam_roles_authoritative, r)
- ]
- authoritative = [
- for r in b.role : r if contains(local.iam_roles_authoritative, r)
- ]
- roles = b.role
- is_group = lookup(local._cl_groups, b.group_id, null) != null
- }
- }
- # compile the final data structure we will consume from various places
- checklist = {
- billing_account = try(local._cl_data.billing_account, null)
- iam_principals = {
- for k, v in local._cl_org_iam_bindings :
- k => v.authoritative if v.is_group && length(v.authoritative) > 0
- }
- iam = {
- for k, v in local._cl_org_iam_bindings :
- k => v.authoritative if !v.is_group && length(v.authoritative) > 0
- }
- iam_bindings = concat(flatten([
- for k, v in local._cl_org_iam_bindings : [
- for r in v.additive : [
- {
- key = "${r}-${k}"
- member = k
- role = r
- }
- ]
- ]
- ]))
- location = try(local._cl_data.logging.sinks[0].destination.location, null)
- }
- uses_checklist = (
- var.factories_config.checklist_data != null
- ||
- var.factories_config.checklist_org_iam != null
- )
-}
-check "checklist" {
- # checklist data files don't need to be both present so we check independently
- # version mismatch might be ok, we just alert users
- assert {
- condition = (
- var.factories_config.checklist_data == null ||
- try(local._cl_data_raw.cloud_setup_config.version, null) == "0.1.0"
- )
- error_message = "Checklist data version mismatch."
- }
- assert {
- condition = (
- var.factories_config.checklist_org_iam == null ||
- try(local._cl_org_raw.cloud_setup_org_iam.version, null) == "0.1.0"
- )
- error_message = "Checklist org IAM version mismatch."
- }
- # wrong org id forces us to ignore the files, but we also alert users
- assert {
- condition = (
- var.factories_config.checklist_data == null ||
- try(local._cl_data_raw.cloud_setup_config.organization.id, null) == tostring(var.organization.id)
- )
- error_message = "Checklist data organization id mismatch, file ignored."
- }
- assert {
- condition = (
- var.factories_config.checklist_org_iam == null ||
- try(local._cl_org_raw.cloud_setup_org_iam.organization.id, null) == tostring(var.organization.id)
- )
- error_message = "Checklist org IAM organization id mismatch, file ignored."
- }
-}
-
-# checklist files bucket
-
-module "automation-tf-checklist-gcs" {
- source = "../../../modules/gcs"
- count = local.uses_checklist ? 1 : 0
- project_id = module.automation-project.project_id
- name = "iac-core-checklist-0"
- prefix = local.prefix
- location = local.locations.gcs
- versioning = true
- depends_on = [module.organization]
-}
-
-resource "google_storage_bucket_object" "checklist_data" {
- count = var.factories_config.checklist_data != null ? 1 : 0
- bucket = module.automation-tf-checklist-gcs[0].name
- name = "checklist/data.tfvars.json"
- source = var.factories_config.checklist_data
-}
-
-resource "google_storage_bucket_object" "checklist_org_iam" {
- count = var.factories_config.checklist_org_iam != null ? 1 : 0
- bucket = module.automation-tf-checklist-gcs[0].name
- name = "checklist/org-iam.tfvars.json"
- source = var.factories_config.checklist_org_iam
-}
diff --git a/fast/stages/0-bootstrap/cicd.tf b/fast/stages/0-bootstrap/cicd.tf
index 1f3d621bc..6705d4cb1 100644
--- a/fast/stages/0-bootstrap/cicd.tf
+++ b/fast/stages/0-bootstrap/cicd.tf
@@ -39,9 +39,10 @@ locals {
contains(
keys(local.workload_identity_providers),
coalesce(try(v.identity_provider, null), ":")
- ) && (
- try(v.type, "") == "terraform" ||
- fileexists(format("${path.module}/templates/workflow-%s.yaml", try(v.type, "")))
+ )
+ &&
+ fileexists(
+ format("${path.module}/templates/workflow-%s.yaml", try(v.type, ""))
)
)
}
@@ -89,12 +90,6 @@ module "automation-tf-cicd-sa" {
google_iam_workload_identity_pool.default[0].name,
each.value.name
)
- : length(regexall("%s", local.workload_identity_providers_defs[each.value.type].principal_branch)) == 2
- ? format(
- local.workload_identity_providers_defs[each.value.type].principal_branch,
- google_iam_workload_identity_pool.default[0].name,
- each.value.branch
- )
: format(
local.workload_identity_providers_defs[each.value.type].principal_branch,
google_iam_workload_identity_pool.default[0].name,
diff --git a/fast/stages/0-bootstrap/data/custom-roles/billing_viewer.yaml b/fast/stages/0-bootstrap/data/custom-roles/billing_viewer.yaml
new file mode 100644
index 000000000..fbec35a73
--- /dev/null
+++ b/fast/stages/0-bootstrap/data/custom-roles/billing_viewer.yaml
@@ -0,0 +1,33 @@
+# Copyright 2023 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.
+
+# yaml-language-server: $schema=../../schemas/custom-role.schema.json
+
+name: billingViewer
+includedPermissions:
+- billing.accounts.get
+- billing.accounts.get
+- billing.accounts.getIamPolicy
+- billing.accounts.getIamPolicy
+- billing.accounts.getSpendingInformation
+- billing.accounts.getUsageExportSpec
+- billing.accounts.list
+- billing.accounts.list
+- billing.budgets.get
+- billing.budgets.list
+- billing.budgets.update
+- billing.credits.list
+- billing.resourceAssociations.list
+- recommender.costInsights.get
+- recommender.costInsights.list
diff --git a/fast/stages/0-bootstrap/data/custom-roles/gcve_network_viewer.yaml b/fast/stages/0-bootstrap/data/custom-roles/gcve_network_viewer.yaml
new file mode 100644
index 000000000..f2ee44789
--- /dev/null
+++ b/fast/stages/0-bootstrap/data/custom-roles/gcve_network_viewer.yaml
@@ -0,0 +1,21 @@
+# Copyright 2023 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.
+
+# yaml-language-server: $schema=../../schemas/custom-role.schema.json
+
+name: gcveNetworkViewer
+includedPermissions:
+ - vmwareengine.networkPeerings.get
+ - vmwareengine.networkPeerings.list
+ - vmwareengine.operations.get
diff --git a/fast/stages/0-bootstrap/data/custom-roles/project_iam_viewer.yaml b/fast/stages/0-bootstrap/data/custom-roles/project_iam_viewer.yaml
new file mode 100644
index 000000000..2f268aa11
--- /dev/null
+++ b/fast/stages/0-bootstrap/data/custom-roles/project_iam_viewer.yaml
@@ -0,0 +1,24 @@
+# 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.
+
+# yaml-language-server: $schema=../../schemas/custom-role.schema.json
+# this is used by the plan-only admin SA
+
+name: projectIamViewer
+includedPermissions:
+- iam.policybindings.get
+- iam.policybindings.list
+- resourcemanager.projects.get
+- resourcemanager.projects.getIamPolicy
+- resourcemanager.projects.searchPolicyBindings
diff --git a/fast/stages/0-bootstrap/data/org-policies-iac/compute.yaml b/fast/stages/0-bootstrap/data/org-policies-iac/compute.yaml
new file mode 100644
index 000000000..ffdcc7e9c
--- /dev/null
+++ b/fast/stages/0-bootstrap/data/org-policies-iac/compute.yaml
@@ -0,0 +1,19 @@
+# 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.
+
+# yaml-language-server: $schema=../../schemas/org-policies.schema.json
+
+compute.skipDefaultNetworkCreation:
+ rules:
+ - enforce: true
diff --git a/fast/stages/0-bootstrap/data/org-policies-iac/iam.yaml b/fast/stages/0-bootstrap/data/org-policies-iac/iam.yaml
new file mode 100644
index 000000000..c4b603c6a
--- /dev/null
+++ b/fast/stages/0-bootstrap/data/org-policies-iac/iam.yaml
@@ -0,0 +1,24 @@
+# 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.
+
+# yaml-language-server: $schema=../../schemas/org-policies.schema.json
+
+iam.automaticIamGrantsForDefaultServiceAccounts:
+ rules:
+ - enforce: true
+
+iam.disableServiceAccountKeyCreation:
+ rules:
+ - enforce: true
+
diff --git a/fast/stages/0-bootstrap/main.tf b/fast/stages/0-bootstrap/main.tf
index dfd6d34d7..7e3cde150 100644
--- a/fast/stages/0-bootstrap/main.tf
+++ b/fast/stages/0-bootstrap/main.tf
@@ -26,7 +26,7 @@ locals {
locations = {
bq = var.locations.bq
gcs = var.locations.gcs
- logging = coalesce(try(local.checklist.location, null), var.locations.logging)
+ logging = var.locations.logging
pubsub = var.locations.pubsub
}
# naming: environment used in most resource names
diff --git a/fast/stages/0-bootstrap/organization.tf b/fast/stages/0-bootstrap/organization.tf
index 18644f83f..c5928c848 100644
--- a/fast/stages/0-bootstrap/organization.tf
+++ b/fast/stages/0-bootstrap/organization.tf
@@ -54,12 +54,10 @@ locals {
[for d in var.org_policies_config.constraints.allowed_essential_contact_domains : "@${d}"]
)
org_policies_tag_name = "${var.organization.id}/${var.org_policies_config.tag_name}"
-
- # intermediate values before we merge in what comes from the checklist
- _iam_principals = {
+ iam_principals = {
for k, v in local.iam_principal_bindings : k => v.authoritative
}
- _iam = merge(
+ iam = merge(
{
for r in local.iam_delete_roles : r => []
},
@@ -67,37 +65,12 @@ locals {
for b in local._iam_bindings_auth : b.role => b.member...
}
)
- _iam_bindings_additive = {
+ iam_bindings_additive = {
for b in local._iam_bindings_add : "${b.role}-${b.member}" => {
member = b.member
role = b.role
}
}
- # final values combining all sources
- iam_principals = {
- for k, v in local._iam_principals : k => distinct(concat(
- v,
- try(local.checklist.iam_principals[k], [])
- ))
- }
- iam = {
- for k, v in local._iam : k => distinct(concat(
- v,
- try(local.checklist.iam[k].authoritative, [])
- ))
- }
- iam_bindings_additive = merge(
- local._iam_bindings_additive,
- {
- for k, v in try(local.checklist.iam_bindings, {}) :
- v.key => v if lookup(local._iam_bindings_additive, v.key, null) == null
- }
- )
- # compute authoritative and additive roles for use by add-ons (checklist, etc.)
- iam_roles_authoritative = distinct(concat(
- flatten(values(local._iam_principals)),
- keys(local._iam)
- ))
}
# TODO: add a check block to ensure our custom roles exist in the factory files
@@ -168,10 +141,6 @@ 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"]
@@ -229,7 +198,7 @@ module "organization" {
factories_config = {
custom_roles = var.factories_config.custom_roles
org_policies = (
- var.bootstrap_user != null ? null : var.factories_config.org_policy
+ var.bootstrap_user != null ? null : var.factories_config.org_policies
)
}
logging_sinks = {
diff --git a/fast/stages/0-bootstrap/outputs.tf b/fast/stages/0-bootstrap/outputs.tf
index 4b1bf5458..29bf4a89f 100644
--- a/fast/stages/0-bootstrap/outputs.tf
+++ b/fast/stages/0-bootstrap/outputs.tf
@@ -15,8 +15,7 @@
*/
locals {
- _tpl_providers_gcs = "${path.module}/templates/providers_gcs.tf.tpl"
- _tpl_providers_terraform = "${path.module}/templates/providers_terraform.tf.tpl"
+ _tpl_providers = "${path.module}/templates/providers.tf.tpl"
# render CI/CD workflow templates
cicd_workflows = {
for k, v in local.cicd_repositories : k => templatefile(
@@ -42,96 +41,59 @@ locals {
tf_var_files = local.cicd_workflow_var_files[k]
}
)
- if v.type != "terraform"
- }
- providers_config = {
- "0-bootstrap" = {
- name = "bootstrap",
- sa = module.automation-tf-bootstrap-sa.email,
- bucket = module.automation-tf-bootstrap-gcs.name,
- backend_extra = null
- },
- "0-bootstrap-r" = {
- name = "bootstrap",
- sa = module.automation-tf-bootstrap-r-sa.email,
- bucket = module.automation-tf-bootstrap-gcs.name,
- backend_extra = null
- },
- "1-resman" = {
- name = "resman",
- sa = module.automation-tf-resman-sa.email,
- bucket = module.automation-tf-resman-gcs.name,
- backend_extra = null
- },
- "1-resman-r" = {
- name = "resman",
- sa = module.automation-tf-resman-r-sa.email,
- bucket = module.automation-tf-resman-gcs.name,
- backend_extra = null
- },
- "1-tenant-factory" = {
- name = "tenant-factory",
- sa = module.automation-tf-resman-sa.email,
- bucket = module.automation-tf-resman-gcs.name,
- backend_extra = "prefix = \"tenant-factory\""
- },
- "1-tenant-factory-r" = {
- name = "tenant-factory",
- sa = module.automation-tf-resman-r-sa.email,
- bucket = module.automation-tf-resman-gcs.name,
- backend_extra = "prefix = \"tenant-factory\""
- },
- "1-vpcsc" = {
- name = "vpcsc",
- sa = module.automation-tf-vpcsc-sa.email,
- bucket = module.automation-tf-vpcsc-gcs.name,
- backend_extra = "prefix = \"vpcsc\""
- },
- "1-vpcsc-r" = {
- name = "vpcsc",
- sa = module.automation-tf-vpcsc-r-sa.email,
- bucket = module.automation-tf-vpcsc-gcs.name,
- backend_extra = "prefix = \"vpcsc\""
- },
}
providers = {
- for k, v in local.providers_config : k => (
- var.cicd_backends != null && try(var.cicd_backends.terraform, null) != null ?
- templatefile(
- local._tpl_providers_terraform,
- merge(
- {
- name = v.name,
- sa = v.sa
- },
- {
- workspaces = lookup(
- var.cicd_backends.terraform.workspaces,
- v.name,
- {
- tags = null,
- name = null,
- project = null
- }
- )
- },
- {
- organization = var.cicd_backends.terraform.organization,
- hostname = var.cicd_backends.terraform.hostname
- }
- )
- ) :
- templatefile(local._tpl_providers_gcs, {
- name = v.name,
- sa = v.sa,
- bucket = v.bucket,
- backend_extra = v.backend_extra
- })
- )
+ "0-bootstrap" = templatefile(local._tpl_providers, {
+ backend_extra = null
+ bucket = module.automation-tf-bootstrap-gcs.name
+ name = "bootstrap"
+ sa = module.automation-tf-bootstrap-sa.email
+ })
+ "0-bootstrap-r" = templatefile(local._tpl_providers, {
+ backend_extra = null
+ bucket = module.automation-tf-bootstrap-gcs.name
+ name = "bootstrap"
+ sa = module.automation-tf-bootstrap-r-sa.email
+ })
+ "1-resman" = templatefile(local._tpl_providers, {
+ backend_extra = null
+ bucket = module.automation-tf-resman-gcs.name
+ name = "resman"
+ sa = module.automation-tf-resman-sa.email
+ })
+ "1-resman-r" = templatefile(local._tpl_providers, {
+ backend_extra = null
+ bucket = module.automation-tf-resman-gcs.name
+ name = "resman"
+ sa = module.automation-tf-resman-r-sa.email
+ })
+ "1-tenant-factory" = templatefile(local._tpl_providers, {
+ backend_extra = "prefix = \"tenant-factory\""
+ bucket = module.automation-tf-resman-gcs.name
+ name = "tenant-factory"
+ sa = module.automation-tf-resman-sa.email
+ })
+ "1-tenant-factory-r" = templatefile(local._tpl_providers, {
+ backend_extra = "prefix = \"tenant-factory\""
+ bucket = module.automation-tf-resman-gcs.name
+ name = "tenant-factory"
+ sa = module.automation-tf-resman-r-sa.email
+ })
+ "1-vpcsc" = templatefile(local._tpl_providers, {
+ backend_extra = "prefix = \"vpcsc\""
+ bucket = module.automation-tf-vpcsc-gcs.name
+ name = "vpcsc"
+ sa = module.automation-tf-vpcsc-sa.email
+ })
+ "1-vpcsc-r" = templatefile(local._tpl_providers, {
+ backend_extra = "prefix = \"vpcsc\""
+ bucket = module.automation-tf-vpcsc-gcs.name
+ name = "vpcsc"
+ sa = module.automation-tf-vpcsc-r-sa.email
+ })
}
tfvars = {
automation = {
- cicd_backends = var.cicd_backends
federated_identity_pool = try(
google_iam_workload_identity_pool.default[0].name, null
)
@@ -174,10 +136,17 @@ locals {
tfvars_globals = {
billing_account = var.billing_account
groups = local.principals
- environments = var.environments
- locations = local.locations
- organization = var.organization
- prefix = var.prefix
+ environments = {
+ for k, v in var.environments :
+ k => merge(v, {
+ tag_name = (
+ v.tag_name != null ? v.tag_name : lower(replace(v.name, " ", "-"))
+ )
+ })
+ }
+ locations = local.locations
+ organization = var.organization
+ prefix = var.prefix
}
}
@@ -238,15 +207,6 @@ output "service_accounts" {
}
}
-# output "test" {
-# value = {
-# checklist = local.checklist
-# iam_roles_authoritative = local.iam_roles_authoritative
-# iam_roles_additive = local.iam_roles_additive
-# test = local.checklist
-# }
-# }
-
# ready to use variable values for subsequent stages
output "tfvars" {
description = "Terraform variable files for the following stages."
diff --git a/fast/stages/0-bootstrap/templates/providers_gcs.tf.tpl b/fast/stages/0-bootstrap/templates/providers.tf.tpl
similarity index 100%
rename from fast/stages/0-bootstrap/templates/providers_gcs.tf.tpl
rename to fast/stages/0-bootstrap/templates/providers.tf.tpl
diff --git a/fast/stages/0-bootstrap/variables.tf b/fast/stages/0-bootstrap/variables.tf
index b1807b850..b9b30587d 100644
--- a/fast/stages/0-bootstrap/variables.tf
+++ b/fast/stages/0-bootstrap/variables.tf
@@ -30,42 +30,6 @@ variable "bootstrap_user" {
default = null
}
-variable "cicd_backends" {
- description = "CI/CD backend configuration. Leave null to use GCS buckets for state."
- type = object({
- terraform = optional(object({
- organization = string
- workspaces = map(object({
- tags = optional(list(string), null)
- name = optional(string, null)
- project = optional(string, null)
- }))
- hostname = optional(string, null)
- }))
- })
- default = null
- validation {
- condition = (
- var.cicd_backends == null ||
- (
- length([for k, v in coalesce(var.cicd_backends, {}) : true if v != null]) == 1
- )
- )
- error_message = "cicd_backends must be either null or contain exactly one backend configuration."
- }
- validation {
- condition = (
- var.cicd_backends == null ||
- try(var.cicd_backends.terraform, null) == null ||
- alltrue([
- for k, v in try(var.cicd_backends.terraform.workspaces, {}) :
- v.tags != null || v.name != null || v.project != null
- ])
- )
- error_message = "At least one of 'tags', 'name', or 'project' must be defined for each workspace in the 'workspaces' map when 'terraform' is defined."
- }
-}
-
variable "cicd_repositories" {
description = "CI/CD repository configuration. Identity providers reference keys in the `federated_identity_providers` variable. Set to null to disable, or set individual repositories to null if not needed."
type = object({
@@ -132,6 +96,7 @@ variable "environments" {
type = map(object({
name = string
is_default = optional(bool, false)
+ tag_name = optional(string)
}))
nullable = false
default = {
@@ -149,6 +114,14 @@ variable "environments" {
])
error_message = "At least one environment should be marked as default."
}
+ validation {
+ condition = alltrue([
+ for k, v in var.environments : join(" ", regexall(
+ "[a-zA-Z][a-zA-Z0-9\\s-]+[a-zA-Z0-9]", v.name
+ )) == v.name
+ ])
+ error_message = "Environment names can only contain letters numbers dashes or spaces."
+ }
}
variable "essential_contacts" {
@@ -160,10 +133,9 @@ variable "essential_contacts" {
variable "factories_config" {
description = "Configuration for the resource factories or external data."
type = object({
- checklist_data = optional(string)
- checklist_org_iam = optional(string)
- custom_roles = optional(string, "data/custom-roles")
- org_policy = optional(string, "data/org-policies")
+ custom_roles = optional(string, "data/custom-roles")
+ org_policies = optional(string, "data/org-policies")
+ org_policies_iac = optional(string, "data/org-policies-iac")
})
nullable = false
default = {}
@@ -284,6 +256,7 @@ variable "log_sinks" {
variable "org_policies_config" {
description = "Organization policies customization."
type = object({
+ iac_policy_member_domains = optional(list(string))
constraints = optional(object({
allowed_essential_contact_domains = optional(list(string), [])
allowed_policy_member_domains = optional(list(string), [])
diff --git a/fast/stages/1-resman/.fast-stage.env b/fast/stages/1-resman/.fast-stage.env
new file mode 100644
index 000000000..cbfceb145
--- /dev/null
+++ b/fast/stages/1-resman/.fast-stage.env
@@ -0,0 +1,5 @@
+FAST_STAGE_DESCRIPTION="resource management"
+FAST_STAGE_LEVEL=1
+FAST_STAGE_NAME=resman
+FAST_STAGE_DEPS="0-globals 0-bootstrap"
+# FAST_STAGE_OPTIONAL=""
\ No newline at end of file
diff --git a/fast/stages/1-resman/README.md b/fast/stages/1-resman/README.md
index 5c6d6e665..f70125fa5 100644
--- a/fast/stages/1-resman/README.md
+++ b/fast/stages/1-resman/README.md
@@ -1,13 +1,12 @@
# Resource hierarchy
-This stage performs two important tasks:
+This stage manages the upper part of the resource management hierarchy, and decouples later stages (networking, etc.) from the organization via folders, IaC resources and IAM bindings.
-- create the top-level hierarchy of folders, and the associated resources used later on to automate each part of the hierarchy (eg. Networking)
-- configure resource management tags used in scoping specific IAM roles on the resource hierarchy
+The complete hierarchy is not managed here, as considerations on departments, teams, and applications are too granular and best managed via the [project factory](../2-project-factory/), which this stage enables.
-The code is intentionally simple, as it's intended to provide a generic initial setup (Networking, Security, etc.), and then allow easy customizations to complete the implementation of the intended hierarchy design.
+As many other parts of FAST, this stage implements several factories that allow simplified management and operations of recurring sets of resources.
-The following diagram is a high level reference of the resources created and managed here:
+The following diagram is a high level reference of the resources created and managed here, and gives an initial representation of its three main configuration elements: top-level folders, FAST stage 2s and stage 3s.
@@ -15,7 +14,13 @@ The following diagram is a high level reference of the resources created and man
- [Design overview and choices](#design-overview-and-choices)
- - [Department or team folders](#department-or-team-folders)
+- [Resource management primitives](#resource-management-primitives)
+ - [Top-level folders](#top-level-folders)
+ - [Stage 2](#stage-2)
+ - [Stage 3](#stage-3)
+ - [Project (and hierarchy) factory](#project-and-hierarchy-factory)
+- [Other design considerations](#other-design-considerations)
+ - [Secure tags](#secure-tags)
- [Multitenancy](#multitenancy)
- [Workload Identity Federation and CI/CD](#workload-identity-federation-and-cicd)
- [How to run this stage](#how-to-run-this-stage)
@@ -23,11 +28,6 @@ The following diagram is a high level reference of the resources created and man
- [Impersonating the automation service account](#impersonating-the-automation-service-account)
- [Variable configuration](#variable-configuration)
- [Running the stage](#running-the-stage)
-- [Customizations](#customizations)
- - [Toggling features](#toggling-features)
- - [Top-level folders](#top-level-folders)
- - [Secure tags](#secure-tags)
- - [IAM](#iam)
- [Files](#files)
- [Variables](#variables)
- [Outputs](#outputs)
@@ -35,160 +35,88 @@ The following diagram is a high level reference of the resources created and man
## Design overview and choices
-Despite its simplicity, this stage implements the basics of a design that we've seen working well for a variety of customers, where the hierarchy is laid out following two conceptually different approaches:
+This stage is designed to offer a good amount of flexibility in laying out the organizational hierarchy, while still providing a default approach that we've seen working across different types of users and organizations.
-- core or shared resources are grouped in hierarchy branches that map to their type or purpose (e.g. Networking)
-- team or application resources are grouped in lower level hierarchy branches that map to management or operational considerations (e.g. which team manages a set of applications, or owns a subset of company data, etc.)
+The default design provided here splits the hierarchy in two different logical areas:
-This split approach usually represents well functional and operational patterns, where core resources are centrally managed by individual teams (e.g. networking, security, fleets of similar VMS, etc.), while teams need more granularity to access managed services used by the applications they maintain.
+- core or shared resources (e.g. networking) which are grouped in dedicated top-level folders that implement centralized management by dedicated teams
+- team or application resources which are grouped under one or more top-level "teams" folders, and typically host managed services (storage, etc.) billed and controlled by their distributed teams
-The approach also adapts to different high level requirements:
+This split approach allows concise mapping of functional and operational patterns to IAM roles and GCP-specific constructs:
-- it can be used either for single organizations containing multiple environments, or with multiple organizations dedicated to specific environments (e.g. prod/nonprod), as the environment split is implemented at the project or lower folder level
-- it adapts to complex scenarios, with different countries or corporate entities using the same GCP organization, as core services are typically shared, and/or an extra layer on top can be used as a drop-in to implement the country/entity separation
+- core services are clearly separated, providing few touchpoints where IAM and security policies need to be applied (typically their top-level folder)
+- new sets of core services (fleets of VMs, shared GKE clusters, etc.) are added as a unit, minimizing operational complexity
+- team and application resources not subject to centralized management are grouped together, providing a unified view and easy budgeting/cost-allocation
+- automation for core resources is segregated via separate service accounts and buckets for each area (shared service, application) effectively minimizing blast radius
-Additionally, a few critical benefits are directly provided by this design:
+Resource names follow the FAST convention discussed in the [Bootstrap stage documentation](../0-bootstrap/README.md#naming).
-- core services are clearly separated, with very few touchpoints where IAM and security policies need to be applied (typically their top-level folder)
-- adding a new set of core services (e.g. shared GKE clusters) is a trivial operation that does not break the existing design
-- grouping application resources and services using teams or business logic is a flexible approach, which maps well to typical operational or budget requirements
-- automation stages (e.g. Networking) can be segregated in a simple and effective way, by creating the required service accounts and buckets for each stage here, and applying a handful of IAM roles to the relevant folder
+## Resource management primitives
-For a discussion on naming, please refer to the [Bootstrap stage documentation](../0-bootstrap/README.md#naming), as the same approach is shared by all stages.
-
-### Department or team folders
-
-Top-level folders for teams or departments can be easily created via the `top_level_folders` variable or the associated factory, which expose the full power of the underlying [folder module](../../../modules/folder/).
-
-The suggestion is to use this feature sparingly so as to keep the top level of the hierarchy simple, and minimize changes to this stage due to its security implications. One approach is to create a grouping folder (e.g. `Departments` or `Teams`) here, and delegate management of lower level folders to the [project factory](../2-project-factory/) stage.
-
-Top-level folders also support defining associated resources for automation, and auto-created provider files to bootstrap Infrastructure and Code. An example is provided below.
-
-### Multitenancy
-
-Multitenancy is supported via a [separate stage](../1-tenant-factory/), which is entirely optional and can be applied after resource management has been deployed. For simpler use cases that do not require complex organization-level multitenancy, [top-level folders](#top-level-folders) can be used in combination with the [project factory stage](../2-project-factory/) support for folder and project management.
-
-### Workload Identity Federation and CI/CD
-
-This stage also implements optional support for CI/CD, much in the same way as the bootstrap stage. The only difference is on Workload Identity Federation, which is only configured in bootstrap and made available here via stage interface variables (the automatically generated `.tfvars` files).
-
-For details on how to configure CI/CD please refer to the [relevant section in the bootstrap stage documentation](../0-bootstrap/README.md#cicd-repositories).
-
-## How to run this stage
-
-This stage is meant to be executed after the [bootstrap](../0-bootstrap) stage has run, as it leverages the automation service account and bucket created there. The relevant user groups must also exist, but that's one of the requirements for the previous stage too, so if you ran that successfully, you're good to go.
-
-It's of course possible 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 stage for the actual 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 '1-resman'
-
-ln -s ~/fast-config/providers/1-resman-providers.tf ./
-ln -s ~/fast-config/tfvars/0-globals.auto.tfvars.json ./
-ln -s ~/fast-config/tfvars/0-bootstrap.auto.tfvars.json ./
-```
-
-```bash
-../../stage-links.sh gs://xxx-prod-iac-core-outputs-0
-
-# copy and paste the following commands for '1-resman'
-
-gcloud storage cp gs://xxx-prod-iac-core-outputs-0/providers/1-resman-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 ./
-```
-
-### 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 stage, which are prepopulated here via the `0-bootstrap.auto.tfvars.json` file 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
-
-### Toggling features
-
-Some FAST features used here and by the following stages can be enabled or disabled using the `fast_features` variables.
-
-The `fast_features` variable consists of 5 toggles:
-
-- **`data_platform`** controls the creation of required resources (folders, service accounts, buckets, IAM bindings) to deploy the [3-data-platform](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/tree/master/fast/stages/3-data-platform) stage
-- **`gcve`** controls the creation of required resources (folders, service accounts, buckets, IAM bindings) to deploy the [3-gcve](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/tree/master/fast/stages/3-gcve) stage
-- **`gke`** controls the creation of required resources (folders, service accounts, buckets, IAM bindings) to deploy the [3-gke-multitenant](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/tree/master/fast/stages/3-gke-multitenant) stage
-- **`project_factory`** controls the creation of required resources (folders, service accounts, buckets, IAM bindings) to deploy the [2-project-factory](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/tree/master/fast/stages/2-project-factory) stage
-- **`sandbox`** controls the creation of a "Sandbox" top level folder with relaxed policies, intended for sandbox environments where users can experiment
-- **`teams`** controls the creation of the top level "Teams" folder used by the [teams feature in resman](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/tree/master/fast/stages/1-resman#team-folders).
+This stage allows a certain degree of free-form hierarchy design on top of instead of the default layout, by providing a set of high level primitives that implement specific FAST functionality: top-level folders, centralized stage 2, environment-level stage 3 for shared services, and the project factory.
### Top-level folders
-The `top_level_folders` variable and associated factory allow simple definition of additional top-level folders, and associated configurations.
+Top-level folders, as indicated by their name, are folders directly attached to the organization that can be freely defined via Terraform variables or factory YAML files. They represent a node in the organization, which can be used to partition the hierarchy via IAM or tag bindings, and to implement separate automation stages via their optional IaC resources.
-The following is an example that creates two folders via tfvars, and also configures the factory to define additional folders via YAML. Folders defined via the variable or factory files support the same interface of the [folder module](../../../modules/folder/).
+Top-level folders support the full interface of the [folder module](../../../modules/folder/), and can fit in the FAST design in different ways:
-```tfvars
-factories_config = {
- top_level_folders = "~/fast-config/data/1-resman/folders"
-}
-top_level_folders = {
- test-1 = {
- name = "Test 1"
- iam = {
- "roles/viewer" = [
- "group:test-1-viewers@example.org"
- ]
- }
- }
- test-2 = {
- # disable creation of the automation SA and bucket
- automation = {
- enable = false
- }
- name = "Test 2"
- }
-}
-```
+- as supporting folders for the project factory, by granting high level permissions to its service accounts via IAM and tag bindings (see the ["Teams" example in the data folder](./data/top-level-folders/teams.yaml))
+- as standalone folders to support custom usage, with or without associated IaC resources (see the ["Sandbox" exanple in the data folder](./data/top-level-folders/sandbox.yaml))
+- as grouping nodes for the environment-specific stage 3 folders (see the ["GCVE" example in the data folder](./data/top-level-folders/gcve.yaml))
+- as a grouping node for stage 2s, for example via a "Shared Services" top-level folder set as the `folder_config.parent_id` attribute for networking and security stages
-```yaml
-# ~/fast-config/data/1-resman/folders/test-4.yaml
-name: Test 4
-automation: null
-iam:
- roles/browser:
- - domain:example.org
-```
+Top-level folders support context-based expansion for service accounts and organization-level tags, which can be referenced by name (e.g. `project-factory` to refer to the project factory service accounts). This allows writing portable organization-independent YAML that can be shared across different FAST installations.
+
+### Stage 2
+
+FAST stage 2s implement core infrastructure services shared across the organization. In the FAST design networking, security, network security and the project factory are defined as stage 2.
+
+FAST stage 2s are typically managed by dedicated teams, they implement environment separation internally due to the complexity of their designs, and provide resources and specific IAM permissions to other shared services implemented as stage 3s (e.g. Shared VPC networks, IAM delegated grants on host projects/subnets or KMS keys).
+
+The default configuration enables all stage 2s except network security. Each stage can be customized via a set of variable-level attributes:
+
+- `short_name` defines the name used for the stage IaC buckets and service accounts
+- `cicd_config` turns on CI/CD configuration and generates the workflow file for the stage
+- `folder_config` controls whether environment-level folders are created under the stage main folder (e.g. `Networking/Development`), allows defining additional IAM bindings on the main folder, or changing its name and parent
+
+Folder configuration is only available for networking and security stages, as the project factory and network security stages are "folderless", using top-level folders or organization-level resources.
+
+Each stage creates its own tag value in the `context` key, which is used by FAST for conditional roles at the organization level (`context/networking`, `context/project-factory` etc.). The tag value is assigned to the stage's folder, and can be applied to other folders to enable specific functionality, as described further down for the project factory.
+
+Think of stage 2s as "named stages" which have specific ties and privileges on the organization. Due to their complexity and the potential need for custom changes, they are implemented in code via dedicated terraform resources each in a stage file (e.g. `stage2-networking.tf`).
+
+### Stage 3
+
+FAST stage 3s are designed to host shared infrastructure that leverages core services from stage 2 (networking, encryption keys, etc.), has limited access to the organization, and is partitioned (or "cloned") by environment.
+
+As shared services they are still managed by dedicated teams, but principals and permissions might differ between environments. Most stage 3s leverage folders (environment-level project factories are the exception), where the stage root folder is created via top-level folders configuration, and the lower level environment folders are part of the stage.
+
+Configuration can be done either via Terraform variables or factory YAML files. The second option is used by default, providing a set of factory files for top-level folders and stage 3s that mirror the legacy FAST hierarchy implemented via code.
+
+Stage 3 configuration is similar to the stage 2 one described above except for a few differences. Each stage defined in the `fast_stage_3` map:
+
+- can define an arbitrary name in the map key, which is used for the stage's output files and internal context-based substitutions
+- needs to define an environment which is present in the bootstrap `environment_names` definition
+- can define organization-level IAM bindings that are conditional to the stage tag value, or an arbitrary one defined in configuration
+- can define stage 2-level tag bindings that are effective only on the stage 2 resources matching the same environment
+
+> TODO: examples from data, make sure the add IAM for GCVE etc. there
+
+### Project (and hierarchy) factory
+
+Despite being itself a stage 2 (and potentially one or more environment-specific stage 3), the project factory is an important primitive to shape the lower level resource hierarchy which implements folder and project management.
+
+By default FAST offers a single organization-wide project factory with the following characteristics:
+
+- any top-level folder with the suitable set of roles can be managed as a sub-hierarchy tree by the project factory (see the ["Teams" definition](./data/top-level-folders/teams.yaml) in the data folder)
+- organization policy management on its folders and projects by the project factory only requires binding the `context/project-factory` tag value
+- networking-related project configuration is available by default, the project factory can grant a limited set of roles on network resources, and attach service projects to VPC host projects
+- security-related project configuration is available by default, the project factory can grant the KMS encrypt/decrypt role on centralized KMS key in the security stage
+
+If environment-specific project factories are desirable, they can be configured as stage 3 as the examples in the stage3 data folder show.
+
+## Other design considerations
### Secure tags
@@ -220,82 +148,147 @@ tags = {
}
```
-### IAM
+### Multitenancy
-The `folder_iam` variable can be used to manage authoritative bindings for all top-level folders. For additional control, IAM roles can be easily edited in the relevant `branch-xxx.tf` file, following the best practice outlined in the [bootstrap stage](../0-bootstrap#customizations) documentation of separating user-level and service-account level IAM policies through the IAM-related variables (`iam`, `iam_bindings`, `iam_bindings_additive`) of the relevant modules.
+Multitenancy is supported via a [separate stage](../1-tenant-factory/), which is entirely optional and can be applied after resource management has been deployed. For simpler use cases that do not require complex organization-level multitenancy, [top-level folders](#top-level-folders) can be used in combination with the [project factory stage](../2-project-factory/) support for folder and project management.
-A full reference of IAM roles managed by this stage [is available here](./IAM.md).
+### Workload Identity Federation and CI/CD
-
+This stage also implements optional support for CI/CD, much in the same way as the bootstrap stage. The only difference is on Workload Identity Federation, which is only configured in bootstrap and made available here via stage interface variables (the automatically generated `.tfvars` files).
+
+For details on how to configure CI/CD please refer to the [relevant section in the bootstrap stage documentation](../0-bootstrap/README.md#cicd-repositories).
+
+## How to run this stage
+
+This stage is meant to be executed after the [bootstrap](../0-bootstrap) stage has run, as it leverages the automation service account and bucket created there. The relevant user groups must also exist, but that's one of the requirements for the previous stage too, so if you ran that successfully, you're good to go.
+
+It's of course possible 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 stage for the actual 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 `fast-links.sh` script in the FAST stages 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.
+
+Using local output files.
+
+```bash
+../fast-links.sh ~/fast-config
+
+# File linking commands for resource management stage
+
+# provider file
+ln -s ~/fast-config/fast-test-00/providers/1-resman-providers.tf ./
+
+# input files from other stages
+ln -s ~/fast-config/fast-test-00/tfvars/0-globals.auto.tfvars.json ./
+ln -s ~/fast-config/fast-test-00/tfvars/0-bootstrap.auto.tfvars.json ./
+
+# conventional place for stage tfvars (manually created)
+ln -s ~/fast-config/fast-test-00/1-resman.auto.tfvars ./
+```
+
+Using the GCS outputs bucket.
+
+```bash
+../fast-links.sh gs://xxx-prod-iac-core-outputs-0
+
+# File linking commands for resource management stage
+
+# provider file
+gcloud storage cp gs://xxx-prod-iac-core-outputs-0/providers/1-resman-providers.tf ./
+
+# input files from other stages
+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 ./
+
+# conventional place for stage tfvars (manually created)
+gcloud storage cp gs://xxx-prod-iac-core-outputs-0/1-resman.auto.tfvars ./
+```
+
+### 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 stage, which are prepopulated here via the `0-bootstrap.auto.tfvars.json` file 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
+
+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
+```
+
+
## Files
| name | description | modules | resources |
|---|---|---|---|
| [billing.tf](./billing.tf) | Billing resources for external billing use cases. | | google_billing_account_iam_member |
-| [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-networking.tf](./branch-networking.tf) | Networking stage resources. | folder · gcs · iam-service-account | |
-| [branch-nsec.tf](./branch-nsec.tf) | Network security stage resources. | 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 | |
-| [branch-security.tf](./branch-security.tf) | Security stage resources. | folder · gcs · iam-service-account | |
-| [checklist.tf](./checklist.tf) | None | folder | |
-| [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 | |
| [iam.tf](./iam.tf) | Organization or root node-level IAM bindings. | | |
| [main.tf](./main.tf) | Module-level locals and resources. | | |
| [organization.tf](./organization.tf) | Organization policies. | organization | |
-| [outputs-files.tf](./outputs-files.tf) | Output files persistence to local filesystem. | | local_file |
-| [outputs-gcs.tf](./outputs-gcs.tf) | Output files persistence to automation GCS bucket. | | google_storage_bucket_object |
+| [outputs-files.tf](./outputs-files.tf) | Output files persistence to local filesystem. | | google_storage_bucket_object · local_file |
| [outputs.tf](./outputs.tf) | Module outputs. | | |
+| [stage-2-network-security.tf](./stage-2-network-security.tf) | None | gcs · iam-service-account | |
+| [stage-2-networking.tf](./stage-2-networking.tf) | None | folder · gcs · iam-service-account | |
+| [stage-2-project-factory.tf](./stage-2-project-factory.tf) | None | gcs · iam-service-account | |
+| [stage-2-security.tf](./stage-2-security.tf) | None | folder · gcs · iam-service-account | |
+| [stage-3.tf](./stage-3.tf) | None | folder · gcs · iam-service-account | |
+| [stage-cicd.tf](./stage-cicd.tf) | None | iam-service-account | |
| [tenant-logging.tf](./tenant-logging.tf) | Audit log project and sink for tenant root folder. | bigquery-dataset · gcs · logging-bucket · pubsub | |
| [tenant-root.tf](./tenant-root.tf) | None | folder · project | |
| [top-level-folders.tf](./top-level-folders.tf) | None | folder · gcs · iam-service-account | |
| [variables-fast.tf](./variables-fast.tf) | FAST stage interface. | | |
+| [variables-stages.tf](./variables-stages.tf) | None | | |
+| [variables-toplevel-folders.tf](./variables-toplevel-folders.tf) | None | | |
| [variables.tf](./variables.tf) | Module variables. | | |
## Variables
| name | description | type | required | default | producer |
|---|---|:---:|:---:|:---:|:---:|
-| [automation](variables-fast.tf#L19) | Automation resources created by the bootstrap stage. | object({…}) | ✓ | | 0-bootstrap |
-| [billing_account](variables-fast.tf#L53) | 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#L109) | Logging configuration for tenants. | object({…}) | ✓ | | 1-tenant-factory |
-| [organization](variables-fast.tf#L122) | Organization details. | object({…}) | ✓ | | 0-bootstrap |
-| [prefix](variables-fast.tf#L140) | 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#L64) | 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#L81) | 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#L96) | 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#L146) | 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({…})) | | {} | |
+| [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 |
+| [environments](variables-fast.tf#L71) | Environment names. | map(object({…})) | ✓ | | 0-globals |
+| [logging](variables-fast.tf#L116) | Logging configuration for tenants. | object({…}) | ✓ | | 1-tenant-factory |
+| [organization](variables-fast.tf#L129) | Organization details. | object({…}) | ✓ | | 0-bootstrap |
+| [prefix](variables-fast.tf#L147) | 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 |
+| [factories_config](variables.tf#L20) | Configuration for the resource factories or external data. | object({…}) | | {} | |
+| [fast_stage_2](variables-stages.tf#L17) | FAST stages 2 configurations. | object({…}) | | {} | |
+| [fast_stage_3](variables-stages.tf#L97) | FAST stages 3 configurations. | map(object({…})) | | {} | |
+| [groups](variables-fast.tf#L88) | 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#L103) | Optional locations for GCS, BigQuery, and logging buckets created here. | object({…}) | | {} | 0-bootstrap |
+| [outputs_location](variables.tf#L31) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable. | string | | null | |
+| [root_node](variables-fast.tf#L153) | Root node for the hierarchy, if running in tenant mode. | string | | null | 0-bootstrap |
+| [tag_names](variables.tf#L37) | Customized names for resource management tags. | object({…}) | | {} | |
+| [tags](variables.tf#L51) | Custom secure tags by key name. The `iam` attribute behaves like the similarly named one at module level. | map(object({…})) | | {} | |
+| [top_level_folders](variables-toplevel-folders.tf#L17) | 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#L413) | WIF configuration for CI/CD repositories. | | |
-| [dataplatform](outputs.tf#L427) | Data for the Data Platform stage. | | |
-| [folder_ids](outputs.tf#L443) | Folder ids. | | |
-| [gcve](outputs.tf#L448) | Data for the GCVE stage. | | 03-gcve |
-| [gke_multitenant](outputs.tf#L469) | Data for the GKE multitenant stage. | | 03-gke-multitenant |
-| [networking](outputs.tf#L490) | Data for the networking stage. | | |
-| [project_factories](outputs.tf#L499) | Data for the project factories stage. | | |
-| [providers](outputs.tf#L518) | Terraform provider files for this stage and dependent stages. | ✓ | 02-networking · 02-security · 03-dataplatform · 03-network-security |
-| [sandbox](outputs.tf#L525) | Data for the sandbox stage. | | xx-sandbox |
-| [security](outputs.tf#L539) | Data for the networking stage. | | 02-security |
-| [tfvars](outputs.tf#L550) | Terraform variable files for the following stages. | ✓ | |
+| [cicd_repositories](outputs.tf#L76) | WIF configuration for CI/CD repositories. | | |
+| [folder_ids](outputs.tf#L88) | Folder ids. | | |
+| [providers](outputs.tf#L94) | Terraform provider files for this stage and dependent stages. | ✓ | |
+| [tfvars](outputs.tf#L101) | Terraform variable files for the following stages. | ✓ | |
diff --git a/fast/stages/1-resman/billing.tf b/fast/stages/1-resman/billing.tf
index c289ddfec..9fb6734e4 100644
--- a/fast/stages/1-resman/billing.tf
+++ b/fast/stages/1-resman/billing.tf
@@ -17,20 +17,46 @@
# tfdoc:file:description Billing resources for external billing use cases.
locals {
- # used here for convenience, in organization.tf members are explicit
- billing_ext_users = compact([
- try(module.branch-network-sa.iam_email, null),
- try(module.branch-pf-dev-sa.iam_email, null),
- try(module.branch-pf-prod-sa.iam_email, null),
- try(module.branch-pf-sa.iam_email, null),
- try(module.branch-security-sa.iam_email, null),
- try(module.branch-dp-dev-sa[0].iam_email, null),
- try(module.branch-dp-prod-sa[0].iam_email, null),
- try(module.branch-gcve-dev-sa[0].iam_email, null),
- try(module.branch-gcve-prod-sa[0].iam_email, null),
- try(module.branch-gke-dev-sa[0].iam_email, null),
- try(module.branch-gke-prod-sa[0].iam_email, null)
- ])
+ billing_iam = merge(
+ # stage 2
+ var.fast_stage_2.networking.enabled != true ? {} : {
+ sa_net_billing = {
+ member = module.net-sa-rw[0].iam_email
+ role = "roles/billing.user"
+ }
+ },
+ var.fast_stage_2.security.enabled != true ? {} : {
+ sa_sec_billing = {
+ member = module.sec-sa-rw[0].iam_email
+ role = "roles/billing.user"
+ }
+ },
+ var.fast_stage_2.project_factory.enabled != true ? {} : merge(
+ {
+ sa_pf_billing = {
+ member = module.pf-sa-rw[0].iam_email
+ role = "roles/billing.user"
+ },
+ sa_pf_costs_manager = {
+ member = module.pf-sa-rw[0].iam_email
+ role = "roles/billing.costsManager"
+ }
+ },
+ var.billing_account.is_org_level != true ? {} : {
+ sa_pf_ro_viewer = {
+ member = module.pf-sa-ro[0].iam_email
+ role = var.custom_roles.billing_viewer
+ }
+ }
+ ),
+ # stage 3
+ {
+ for k, v in local.stage3 : k => {
+ member = module.stage3-sa-rw[k].iam_email
+ role = "roles/billing.user"
+ }
+ }
+ )
billing_mode = (
var.billing_account.no_iam
? null
@@ -42,20 +68,11 @@ locals {
# standalone billing account
-resource "google_billing_account_iam_member" "billing_ext_admin" {
- for_each = toset(
- local.billing_mode == "resource" ? local.billing_ext_users : []
+resource "google_billing_account_iam_member" "default" {
+ for_each = (
+ local.billing_mode != "resource" ? {} : local.billing_iam
)
billing_account_id = var.billing_account.id
- role = "roles/billing.user"
- member = each.key
-}
-
-resource "google_billing_account_iam_member" "billing_ext_costsmanager" {
- for_each = toset(
- local.billing_mode == "resource" ? local.billing_ext_users : []
- )
- billing_account_id = var.billing_account.id
- role = "roles/billing.costsManager"
- member = each.key
+ role = each.value.role
+ member = each.value.member
}
diff --git a/fast/stages/1-resman/branch-data-platform.tf b/fast/stages/1-resman/branch-data-platform.tf
deleted file mode 100644
index d168a02f4..000000000
--- a/fast/stages/1-resman/branch-data-platform.tf
+++ /dev/null
@@ -1,197 +0,0 @@
-/**
- * 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 Data Platform stages resources.
-
-module "branch-dp-folder" {
- source = "../../../modules/folder"
- count = var.fast_features.data_platform ? 1 : 0
- parent = local.root_node
- name = "Data Platform"
- iam = var.folder_iam.data_platform
- tag_bindings = {
- context = try(
- local.tag_values["${var.tag_names.context}/data"].id, null
- )
- }
-}
-
-module "branch-dp-dev-folder" {
- source = "../../../modules/folder"
- count = var.fast_features.data_platform ? 1 : 0
- parent = module.branch-dp-folder[0].id
- name = "Development"
- iam_by_principals = {}
- # owner and viewer roles are broad and might grant unwanted access
- # replace them with more selective custom roles for production deployments
- iam = {
- # read-write (apply) automation service account
- (local.custom_roles.service_project_network_admin) = [
- module.branch-dp-dev-sa[0].iam_email
- ]
- "roles/logging.admin" = [module.branch-dp-dev-sa[0].iam_email]
- "roles/owner" = [module.branch-dp-dev-sa[0].iam_email]
- "roles/resourcemanager.folderAdmin" = [module.branch-dp-dev-sa[0].iam_email]
- "roles/resourcemanager.projectCreator" = [module.branch-dp-dev-sa[0].iam_email]
- # read-only (plan) automation service account
- "roles/viewer" = [module.branch-dp-dev-r-sa[0].iam_email]
- "roles/resourcemanager.folderViewer" = [module.branch-dp-dev-r-sa[0].iam_email]
- }
- tag_bindings = {
- context = try(
- local.tag_values["${var.tag_names.environment}/development"].id,
- null
- )
- }
-}
-
-module "branch-dp-prod-folder" {
- source = "../../../modules/folder"
- count = var.fast_features.data_platform ? 1 : 0
- parent = module.branch-dp-folder[0].id
- name = "Production"
- iam_by_principals = {}
- # owner and viewer roles are broad and might grant unwanted access
- # replace them with more selective custom roles for production deployments
- iam = {
- # read-write (apply) automation service account
- (local.custom_roles.service_project_network_admin) = [module.branch-dp-prod-sa[0].iam_email]
- "roles/owner" = [module.branch-dp-prod-sa[0].iam_email]
- "roles/logging.admin" = [module.branch-dp-prod-sa[0].iam_email]
- "roles/resourcemanager.folderAdmin" = [module.branch-dp-prod-sa[0].iam_email]
- "roles/resourcemanager.projectCreator" = [module.branch-dp-prod-sa[0].iam_email]
- # read-only (plan) automation service account
- "roles/viewer" = [module.branch-dp-prod-r-sa[0].iam_email]
- "roles/resourcemanager.folderViewer" = [module.branch-dp-prod-r-sa[0].iam_email]
- }
- tag_bindings = {
- context = try(
- local.tag_values["${var.tag_names.environment}/production"].id,
- null
- )
- }
-}
-
-# automation service accounts
-
-module "branch-dp-dev-sa" {
- source = "../../../modules/iam-service-account"
- count = var.fast_features.data_platform ? 1 : 0
- project_id = var.automation.project_id
- name = "dev-resman-dp-0"
- display_name = "Terraform data platform development service account."
- prefix = var.prefix
- iam = {
- "roles/iam.serviceAccountTokenCreator" = compact([
- try(module.branch-dp-dev-sa-cicd[0].iam_email, null)
- ])
- }
- iam_project_roles = {
- (var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"]
- }
- iam_storage_roles = {
- (var.automation.outputs_bucket) = ["roles/storage.objectAdmin"]
- }
-}
-
-module "branch-dp-prod-sa" {
- source = "../../../modules/iam-service-account"
- count = var.fast_features.data_platform ? 1 : 0
- project_id = var.automation.project_id
- name = "prod-resman-dp-0"
- display_name = "Terraform data platform production service account."
- prefix = var.prefix
- iam = {
- "roles/iam.serviceAccountTokenCreator" = compact([
- try(module.branch-dp-prod-sa-cicd[0].iam_email, null)
- ])
- }
- iam_storage_roles = {
- (var.automation.outputs_bucket) = ["roles/storage.objectAdmin"]
- }
-}
-
-# automation read-only service accounts
-
-module "branch-dp-dev-r-sa" {
- source = "../../../modules/iam-service-account"
- count = var.fast_features.data_platform ? 1 : 0
- project_id = var.automation.project_id
- name = "dev-resman-dp-0r"
- display_name = "Terraform data platform development service account (read-only)."
- prefix = var.prefix
- iam = {
- "roles/iam.serviceAccountTokenCreator" = compact([
- try(module.branch-dp-dev-r-sa-cicd[0].iam_email, null)
- ])
- }
- iam_project_roles = {
- (var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"]
- }
- iam_storage_roles = {
- (var.automation.outputs_bucket) = [var.custom_roles["storage_viewer"]]
- }
-}
-
-module "branch-dp-prod-r-sa" {
- source = "../../../modules/iam-service-account"
- count = var.fast_features.data_platform ? 1 : 0
- project_id = var.automation.project_id
- name = "prod-resman-dp-0r"
- display_name = "Terraform data platform production service account (read-only)."
- prefix = var.prefix
- iam = {
- "roles/iam.serviceAccountTokenCreator" = compact([
- try(module.branch-dp-prod-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 buckets
-
-module "branch-dp-dev-gcs" {
- source = "../../../modules/gcs"
- count = var.fast_features.data_platform ? 1 : 0
- project_id = var.automation.project_id
- name = "dev-resman-dp-0"
- prefix = var.prefix
- location = var.locations.gcs
- versioning = true
- iam = {
- "roles/storage.objectAdmin" = [module.branch-dp-dev-sa[0].iam_email]
- "roles/storage.objectViewer" = [module.branch-dp-dev-r-sa[0].iam_email]
- }
-}
-
-module "branch-dp-prod-gcs" {
- source = "../../../modules/gcs"
- count = var.fast_features.data_platform ? 1 : 0
- project_id = var.automation.project_id
- name = "prod-resman-dp-0"
- prefix = var.prefix
- location = var.locations.gcs
- versioning = true
- iam = {
- "roles/storage.objectAdmin" = [module.branch-dp-prod-sa[0].iam_email]
- "roles/storage.objectViewer" = [module.branch-dp-prod-r-sa[0].iam_email]
- }
-}
diff --git a/fast/stages/1-resman/branch-gcve.tf b/fast/stages/1-resman/branch-gcve.tf
deleted file mode 100644
index 04627dadc..000000000
--- a/fast/stages/1-resman/branch-gcve.tf
+++ /dev/null
@@ -1,198 +0,0 @@
-/**
- * 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 GCVE stage resources.
-
-module "branch-gcve-folder" {
- source = "../../../modules/folder"
- count = var.fast_features.gcve ? 1 : 0
- parent = local.root_node
- name = "GCVE"
- iam = var.folder_iam.gcve
- tag_bindings = {
- context = try(
- local.tag_values["${var.tag_names.context}/gcve"].id, null
- )
- }
-}
-
-module "branch-gcve-dev-folder" {
- source = "../../../modules/folder"
- count = var.fast_features.gcve ? 1 : 0
- parent = module.branch-gcve-folder[0].id
- name = "Development"
- iam = {
- # read-write (apply) automation service account
- "roles/owner" = [module.branch-gcve-dev-sa[0].iam_email]
- "roles/logging.admin" = [module.branch-gcve-dev-sa[0].iam_email]
- "roles/resourcemanager.folderAdmin" = [module.branch-gcve-dev-sa[0].iam_email]
- "roles/resourcemanager.projectCreator" = [module.branch-gcve-dev-sa[0].iam_email]
- "roles/compute.xpnAdmin" = [module.branch-gcve-dev-sa[0].iam_email]
- # read-only (plan) automation service account
- "roles/viewer" = [module.branch-gcve-dev-r-sa[0].iam_email]
- "roles/resourcemanager.folderViewer" = [module.branch-gcve-dev-r-sa[0].iam_email]
- }
- tag_bindings = {
- context = try(
- local.tag_values["${var.tag_names.environment}/development"].id,
- null
- )
- }
-}
-
-module "branch-gcve-prod-folder" {
- source = "../../../modules/folder"
- count = var.fast_features.gcve ? 1 : 0
- parent = module.branch-gcve-folder[0].id
- name = "Production"
- iam = {
- # read-write (apply) automation service account
- "roles/owner" = [module.branch-gcve-prod-sa[0].iam_email]
- "roles/logging.admin" = [module.branch-gcve-prod-sa[0].iam_email]
- "roles/resourcemanager.folderAdmin" = [module.branch-gcve-prod-sa[0].iam_email]
- "roles/resourcemanager.projectCreator" = [module.branch-gcve-prod-sa[0].iam_email]
- "roles/compute.xpnAdmin" = [module.branch-gcve-prod-sa[0].iam_email]
- # read-only (plan) automation service account
- "roles/viewer" = [module.branch-gcve-prod-r-sa[0].iam_email]
- "roles/resourcemanager.folderViewer" = [module.branch-gcve-prod-r-sa[0].iam_email]
- }
- tag_bindings = {
- context = try(
- local.tag_values["${var.tag_names.environment}/production"].id,
- null
- )
- }
-}
-
-# automation service accounts
-
-module "branch-gcve-dev-sa" {
- source = "../../../modules/iam-service-account"
- count = var.fast_features.gcve ? 1 : 0
- project_id = var.automation.project_id
- name = "dev-resman-gcve-0"
- display_name = "Terraform GCVE development service account."
- prefix = var.prefix
- iam = {
- "roles/iam.serviceAccountTokenCreator" = concat(
- [local.principals.gcp-devops],
- compact([
- try(module.branch-gcve-dev-sa-cicd[0].iam_email, null)
- ])
- )
- }
- iam_project_roles = {
- (var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"]
- }
- iam_storage_roles = {
- (var.automation.outputs_bucket) = ["roles/storage.objectAdmin"]
- }
-}
-
-module "branch-gcve-prod-sa" {
- source = "../../../modules/iam-service-account"
- count = var.fast_features.gcve ? 1 : 0
- project_id = var.automation.project_id
- name = "prod-resman-gcve-0"
- display_name = "Terraform GCVE production service account."
- prefix = var.prefix
- iam = {
- "roles/iam.serviceAccountTokenCreator" = concat(
- [local.principals.gcp-devops],
- compact([
- try(module.branch-gcve-prod-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 accounts
-
-module "branch-gcve-dev-r-sa" {
- source = "../../../modules/iam-service-account"
- count = var.fast_features.gcve ? 1 : 0
- project_id = var.automation.project_id
- name = "dev-resman-gcve-0r"
- display_name = "Terraform GCVE development service account (read-only)."
- prefix = var.prefix
- iam = {
- "roles/iam.serviceAccountTokenCreator" = compact([
- try(module.branch-gcve-dev-r-sa-cicd[0].iam_email, null)
- ])
- }
- iam_project_roles = {
- (var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"]
- }
- iam_storage_roles = {
- (var.automation.outputs_bucket) = [var.custom_roles["storage_viewer"]]
- }
-}
-
-module "branch-gcve-prod-r-sa" {
- source = "../../../modules/iam-service-account"
- count = var.fast_features.gcve ? 1 : 0
- project_id = var.automation.project_id
- name = "prod-resman-gcve-0r"
- display_name = "Terraform GCVE production service account (read-only)."
- prefix = var.prefix
- iam = {
- "roles/iam.serviceAccountTokenCreator" = compact([
- try(module.branch-gcve-prod-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 buckets
-
-module "branch-gcve-dev-gcs" {
- source = "../../../modules/gcs"
- count = var.fast_features.gcve ? 1 : 0
- project_id = var.automation.project_id
- name = "dev-resman-gcve-0"
- prefix = var.prefix
- location = var.locations.gcs
- versioning = true
- iam = {
- "roles/storage.objectAdmin" = [module.branch-gcve-dev-sa[0].iam_email]
- "roles/storage.objectViewer" = [module.branch-gcve-dev-r-sa[0].iam_email]
- }
-}
-
-module "branch-gcve-prod-gcs" {
- source = "../../../modules/gcs"
- count = var.fast_features.gcve ? 1 : 0
- project_id = var.automation.project_id
- name = "prod-resman-gcve-0"
- prefix = var.prefix
- location = var.locations.gcs
- versioning = true
- iam = {
- "roles/storage.objectAdmin" = [module.branch-gcve-prod-sa[0].iam_email]
- "roles/storage.objectViewer" = [module.branch-gcve-prod-r-sa[0].iam_email]
- }
-}
diff --git a/fast/stages/1-resman/branch-gke.tf b/fast/stages/1-resman/branch-gke.tf
deleted file mode 100644
index d28e019ea..000000000
--- a/fast/stages/1-resman/branch-gke.tf
+++ /dev/null
@@ -1,198 +0,0 @@
-/**
- * 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 GKE multitenant stage resources.
-
-module "branch-gke-folder" {
- source = "../../../modules/folder"
- count = var.fast_features.gke ? 1 : 0
- parent = local.root_node
- name = "GKE"
- iam = var.folder_iam.gke
- tag_bindings = {
- context = try(
- local.tag_values["${var.tag_names.context}/gke"].id, null
- )
- }
-}
-
-module "branch-gke-dev-folder" {
- source = "../../../modules/folder"
- count = var.fast_features.gke ? 1 : 0
- parent = module.branch-gke-folder[0].id
- name = "Development"
- iam = {
- # read-write (apply) automation service account
- "roles/owner" = [module.branch-gke-dev-sa[0].iam_email]
- "roles/logging.admin" = [module.branch-gke-dev-sa[0].iam_email]
- "roles/resourcemanager.folderAdmin" = [module.branch-gke-dev-sa[0].iam_email]
- "roles/resourcemanager.projectCreator" = [module.branch-gke-dev-sa[0].iam_email]
- "roles/compute.xpnAdmin" = [module.branch-gke-dev-sa[0].iam_email]
- # read-only (plan) automation service account
- "roles/viewer" = [module.branch-gke-dev-r-sa[0].iam_email]
- "roles/resourcemanager.folderViewer" = [module.branch-gke-dev-r-sa[0].iam_email]
- }
- tag_bindings = {
- context = try(
- local.tag_values["${var.tag_names.environment}/development"].id,
- null
- )
- }
-}
-
-module "branch-gke-prod-folder" {
- source = "../../../modules/folder"
- count = var.fast_features.gke ? 1 : 0
- parent = module.branch-gke-folder[0].id
- name = "Production"
- iam = {
- # read-write (apply) automation service account
- "roles/owner" = [module.branch-gke-prod-sa[0].iam_email]
- "roles/logging.admin" = [module.branch-gke-prod-sa[0].iam_email]
- "roles/resourcemanager.folderAdmin" = [module.branch-gke-prod-sa[0].iam_email]
- "roles/resourcemanager.projectCreator" = [module.branch-gke-prod-sa[0].iam_email]
- "roles/compute.xpnAdmin" = [module.branch-gke-prod-sa[0].iam_email]
- # read-only (plan) automation service account
- "roles/viewer" = [module.branch-gke-prod-r-sa[0].iam_email]
- "roles/resourcemanager.folderViewer" = [module.branch-gke-prod-r-sa[0].iam_email]
- }
- tag_bindings = {
- context = try(
- local.tag_values["${var.tag_names.environment}/production"].id,
- null
- )
- }
-}
-
-# automation service accounts
-
-module "branch-gke-dev-sa" {
- source = "../../../modules/iam-service-account"
- count = var.fast_features.gke ? 1 : 0
- project_id = var.automation.project_id
- name = "dev-resman-gke-0"
- display_name = "Terraform gke multitenant dev service account."
- prefix = var.prefix
- iam = {
- "roles/iam.serviceAccountTokenCreator" = concat(
- [local.principals.gcp-devops],
- compact([
- try(module.branch-gke-dev-sa-cicd[0].iam_email, null)
- ])
- )
- }
- iam_project_roles = {
- (var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"]
- }
- iam_storage_roles = {
- (var.automation.outputs_bucket) = ["roles/storage.objectAdmin"]
- }
-}
-
-module "branch-gke-prod-sa" {
- source = "../../../modules/iam-service-account"
- count = var.fast_features.gke ? 1 : 0
- project_id = var.automation.project_id
- name = "prod-resman-gke-0"
- display_name = "Terraform gke multitenant prod service account."
- prefix = var.prefix
- iam = {
- "roles/iam.serviceAccountTokenCreator" = concat(
- [local.principals.gcp-devops],
- compact([
- try(module.branch-gke-prod-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 accounts
-
-module "branch-gke-dev-r-sa" {
- source = "../../../modules/iam-service-account"
- count = var.fast_features.gke ? 1 : 0
- project_id = var.automation.project_id
- name = "dev-resman-gke-0r"
- display_name = "Terraform gke multitenant development service account (read-only)."
- prefix = var.prefix
- iam = {
- "roles/iam.serviceAccountTokenCreator" = compact([
- try(module.branch-gke-dev-r-sa-cicd[0].iam_email, null)
- ])
- }
- iam_project_roles = {
- (var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"]
- }
- iam_storage_roles = {
- (var.automation.outputs_bucket) = [var.custom_roles["storage_viewer"]]
- }
-}
-
-module "branch-gke-prod-r-sa" {
- source = "../../../modules/iam-service-account"
- count = var.fast_features.gke ? 1 : 0
- project_id = var.automation.project_id
- name = "prod-resman-gke-0r"
- display_name = "Terraform gke multitenant production service account (read-only)."
- prefix = var.prefix
- iam = {
- "roles/iam.serviceAccountTokenCreator" = compact([
- try(module.branch-gke-prod-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 buckets
-
-module "branch-gke-dev-gcs" {
- source = "../../../modules/gcs"
- count = var.fast_features.gke ? 1 : 0
- project_id = var.automation.project_id
- name = "dev-resman-gke-0"
- prefix = var.prefix
- location = var.locations.gcs
- versioning = true
- iam = {
- "roles/storage.objectAdmin" = [module.branch-gke-dev-sa[0].iam_email]
- "roles/storage.objectViewer" = [module.branch-gke-dev-r-sa[0].iam_email]
- }
-}
-
-module "branch-gke-prod-gcs" {
- source = "../../../modules/gcs"
- count = var.fast_features.gke ? 1 : 0
- project_id = var.automation.project_id
- name = "prod-resman-gke-0"
- prefix = var.prefix
- location = var.locations.gcs
- versioning = true
- iam = {
- "roles/storage.objectAdmin" = [module.branch-gke-prod-sa[0].iam_email]
- "roles/storage.objectViewer" = [module.branch-gke-prod-r-sa[0].iam_email]
- }
-}
diff --git a/fast/stages/1-resman/branch-networking.tf b/fast/stages/1-resman/branch-networking.tf
deleted file mode 100644
index 0a03a381d..000000000
--- a/fast/stages/1-resman/branch-networking.tf
+++ /dev/null
@@ -1,200 +0,0 @@
-/**
- * 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 Networking stage resources.
-
-locals {
- # FAST-specific IAM
- _network_folder_fast_iam = merge(
- {
- # read-write (apply) automation service account
- "roles/logging.admin" = [module.branch-network-sa.iam_email]
- "roles/owner" = [module.branch-network-sa.iam_email]
- "roles/resourcemanager.folderAdmin" = [module.branch-network-sa.iam_email]
- "roles/resourcemanager.projectCreator" = [module.branch-network-sa.iam_email]
- "roles/compute.xpnAdmin" = [module.branch-network-sa.iam_email]
- # read-only (plan) automation service account
- "roles/viewer" = [module.branch-network-r-sa.iam_email]
- "roles/resourcemanager.folderViewer" = [module.branch-network-r-sa.iam_email]
- },
- var.fast_features.nsec != true ? {} : {
- # nsec service accounts
- "roles/serviceusage.serviceUsageAdmin" = [
- try(module.branch-nsec-sa[0].iam_email, null)
- ]
- "roles/serviceusage.serviceUsageConsumer" = [
- try(module.branch-nsec-r-sa[0].iam_email, null)
- ]
- (var.custom_roles["network_firewall_policies_admin"]) = [
- try(module.branch-nsec-sa[0].iam_email, null)
- ]
- "roles/compute.orgFirewallPolicyUser" = [
- try(module.branch-nsec-r-sa[0].iam_email, null)
- ]
- }
- )
- # deep-merge FAST-specific IAM with user-provided bindings in var.folder_iam
- _network_folder_iam = merge(
- var.folder_iam.network,
- {
- for role, principals in local._network_folder_fast_iam :
- role => distinct(concat(principals, lookup(var.folder_iam.network, role, [])))
- }
- )
-}
-
-module "branch-network-folder" {
- source = "../../../modules/folder"
- parent = local.root_node
- name = "Networking"
- iam_by_principals = {
- (local.principals.gcp-network-admins) = [
- # owner and viewer roles are broad and might grant unwanted access
- # replace them with more selective custom roles for production deployments
- "roles/editor",
- ]
- }
- iam = local._network_folder_iam
- tag_bindings = {
- context = try(
- local.tag_values["${var.tag_names.context}/networking"].id, null
- )
- }
-}
-
-module "branch-network-prod-folder" {
- source = "../../../modules/folder"
- parent = module.branch-network-folder.id
- name = "Production"
- iam = {
- # read-write (apply) automation service accounts
- (local.custom_roles.service_project_network_admin) = compact([
- try(module.branch-dp-prod-sa[0].iam_email, null),
- try(module.branch-gcve-prod-sa[0].iam_email, null),
- try(module.branch-gke-prod-sa[0].iam_email, null),
- try(module.branch-pf-sa.iam_email, null),
- try(module.branch-pf-prod-sa.iam_email, null)
- ])
- # read-only (plan) automation service accounts
- "roles/compute.networkViewer" = compact([
- try(module.branch-dp-prod-r-sa[0].iam_email, null),
- try(module.branch-gcve-prod-r-sa[0].iam_email, null),
- try(module.branch-gke-prod-r-sa[0].iam_email, null),
- try(module.branch-pf-r-sa.iam_email, null),
- try(module.branch-pf-prod-r-sa.iam_email, null)
- ])
- (local.custom_roles.gcve_network_admin) = compact([
- try(module.branch-gcve-prod-sa[0].iam_email, null)
- ])
- }
- tag_bindings = {
- environment = try(
- local.tag_values["${var.tag_names.environment}/production"].id,
- null
- )
- }
-}
-
-module "branch-network-dev-folder" {
- source = "../../../modules/folder"
- parent = module.branch-network-folder.id
- name = "Development"
- iam = {
- # read-write (apply) automation service accounts
- (local.custom_roles.service_project_network_admin) = compact([
- try(module.branch-dp-dev-sa[0].iam_email, null),
- try(module.branch-gcve-dev-sa[0].iam_email, null),
- try(module.branch-gke-dev-sa[0].iam_email, null),
- try(module.branch-pf-sa.iam_email, null),
- try(module.branch-pf-dev-sa.iam_email, null)
- ])
- # read-only (plan) automation service accounts
- "roles/compute.networkViewer" = compact([
- try(module.branch-dp-dev-r-sa[0].iam_email, null),
- try(module.branch-gcve-dev-r-sa[0].iam_email, null),
- try(module.branch-gke-dev-r-sa[0].iam_email, null),
- try(module.branch-pf-r-sa.iam_email, null),
- try(module.branch-pf-dev-r-sa.iam_email, null)
- ])
- (local.custom_roles.gcve_network_admin) = compact([
- try(module.branch-gcve-dev-sa[0].iam_email, null)
- ])
- }
- tag_bindings = {
- environment = try(
- local.tag_values["${var.tag_names.environment}/development"].id,
- null
- )
- }
-}
-
-# automation service account
-
-module "branch-network-sa" {
- source = "../../../modules/iam-service-account"
- project_id = var.automation.project_id
- name = "prod-resman-net-0"
- display_name = "Terraform resman networking service account."
- prefix = var.prefix
- service_account_create = var.root_node == null
- iam = {
- "roles/iam.serviceAccountTokenCreator" = compact([
- try(module.branch-network-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-network-r-sa" {
- source = "../../../modules/iam-service-account"
- project_id = var.automation.project_id
- name = "prod-resman-net-0r"
- display_name = "Terraform resman networking service account (read-only)."
- prefix = var.prefix
- iam = {
- "roles/iam.serviceAccountTokenCreator" = compact([
- try(module.branch-network-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-network-gcs" {
- source = "../../../modules/gcs"
- project_id = var.automation.project_id
- name = "prod-resman-net-0"
- prefix = var.prefix
- location = var.locations.gcs
- versioning = true
- iam = {
- "roles/storage.objectAdmin" = [module.branch-network-sa.iam_email]
- "roles/storage.objectViewer" = [module.branch-network-r-sa.iam_email]
- }
-}
diff --git a/fast/stages/1-resman/branch-project-factory.tf b/fast/stages/1-resman/branch-project-factory.tf
deleted file mode 100644
index bb458e3f2..000000000
--- a/fast/stages/1-resman/branch-project-factory.tf
+++ /dev/null
@@ -1,176 +0,0 @@
-/**
- * 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 Project factory stage resources.
-
-# automation service accounts
-
-module "branch-pf-sa" {
- source = "../../../modules/iam-service-account"
- project_id = var.automation.project_id
- name = "resman-pf-0"
- display_name = "Terraform project factory main service account."
- prefix = var.prefix
- iam = {
- "roles/iam.serviceAccountTokenCreator" = compact([
- try(module.branch-pf-sa-cicd[0].iam_email, null)
- ])
- }
- iam_project_roles = {
- (var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"]
- }
- iam_storage_roles = {
- (var.automation.outputs_bucket) = ["roles/storage.objectAdmin"]
- }
-}
-
-module "branch-pf-dev-sa" {
- source = "../../../modules/iam-service-account"
- project_id = var.automation.project_id
- name = "dev-resman-pf-0"
- display_name = "Terraform project factory development service account."
- prefix = var.prefix
- iam = {
- "roles/iam.serviceAccountTokenCreator" = compact([
- try(module.branch-pf-dev-sa-cicd[0].iam_email, null)
- ])
- }
- iam_project_roles = {
- (var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"]
- }
- iam_storage_roles = {
- (var.automation.outputs_bucket) = ["roles/storage.objectAdmin"]
- }
-}
-
-module "branch-pf-prod-sa" {
- source = "../../../modules/iam-service-account"
- project_id = var.automation.project_id
- name = "prod-resman-pf-0"
- display_name = "Terraform project factory production service account."
- prefix = var.prefix
- iam = {
- "roles/iam.serviceAccountTokenCreator" = compact([
- try(module.branch-pf-prod-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 accounts
-
-module "branch-pf-r-sa" {
- source = "../../../modules/iam-service-account"
- project_id = var.automation.project_id
- name = "resman-pf-0r"
- display_name = "Terraform project factory main service account (read-only)."
- prefix = var.prefix
- iam = {
- "roles/iam.serviceAccountTokenCreator" = compact([
- try(module.branch-pf-r-sa-cicd[0].iam_email, null)
- ])
- }
- iam_project_roles = {
- (var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"]
- }
- iam_storage_roles = {
- (var.automation.outputs_bucket) = [var.custom_roles["storage_viewer"]]
- }
-}
-
-module "branch-pf-dev-r-sa" {
- source = "../../../modules/iam-service-account"
- project_id = var.automation.project_id
- name = "dev-resman-pf-0r"
- display_name = "Terraform project factory development service account (read-only)."
- prefix = var.prefix
- iam = {
- "roles/iam.serviceAccountTokenCreator" = compact([
- try(module.branch-pf-dev-r-sa-cicd[0].iam_email, null)
- ])
- }
- iam_project_roles = {
- (var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"]
- }
- iam_storage_roles = {
- (var.automation.outputs_bucket) = [var.custom_roles["storage_viewer"]]
- }
-}
-
-module "branch-pf-prod-r-sa" {
- source = "../../../modules/iam-service-account"
- project_id = var.automation.project_id
- name = "prod-resman-pf-0r"
- display_name = "Terraform project factory production service account (read-only)."
- prefix = var.prefix
- iam = {
- "roles/iam.serviceAccountTokenCreator" = compact([
- try(module.branch-pf-prod-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 buckets
-
-module "branch-pf-gcs" {
- source = "../../../modules/gcs"
- project_id = var.automation.project_id
- name = "resman-pf-0"
- prefix = var.prefix
- location = var.locations.gcs
- versioning = true
- iam = {
- "roles/storage.objectAdmin" = [module.branch-pf-sa.iam_email]
- "roles/storage.objectViewer" = [module.branch-pf-r-sa.iam_email]
- }
-}
-
-module "branch-pf-dev-gcs" {
- source = "../../../modules/gcs"
- project_id = var.automation.project_id
- name = "dev-resman-pf-0"
- prefix = var.prefix
- location = var.locations.gcs
- versioning = true
- iam = {
- "roles/storage.objectAdmin" = [module.branch-pf-dev-sa.iam_email]
- "roles/storage.objectViewer" = [module.branch-pf-dev-r-sa.iam_email]
- }
-}
-
-module "branch-pf-prod-gcs" {
- source = "../../../modules/gcs"
- project_id = var.automation.project_id
- name = "prod-resman-pf-0"
- prefix = var.prefix
- location = var.locations.gcs
- versioning = true
- iam = {
- "roles/storage.objectAdmin" = [module.branch-pf-prod-sa.iam_email]
- "roles/storage.objectViewer" = [module.branch-pf-prod-r-sa.iam_email]
- }
-}
diff --git a/fast/stages/1-resman/branch-sandbox.tf b/fast/stages/1-resman/branch-sandbox.tf
deleted file mode 100644
index 6c38c5efa..000000000
--- a/fast/stages/1-resman/branch-sandbox.tf
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * 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 Sandbox stage resources.
-
-locals {
- # FAST-specific IAM
- _sandbox_folder_fast_iam = !var.fast_features.sandbox ? {} : {
- "roles/logging.admin" = [module.branch-sandbox-sa[0].iam_email]
- "roles/owner" = [module.branch-sandbox-sa[0].iam_email]
- "roles/resourcemanager.folderAdmin" = [module.branch-sandbox-sa[0].iam_email]
- "roles/resourcemanager.projectCreator" = [module.branch-sandbox-sa[0].iam_email]
- }
- # deep-merge FAST-specific IAM with user-provided bindings in var.folder_iam
- _sandbox_folder_iam = merge(
- var.folder_iam.sandbox,
- {
- for role, principals in local._sandbox_folder_fast_iam :
- role => distinct(concat(principals, lookup(var.folder_iam.sandbox, role, [])))
- }
- )
-}
-
-module "branch-sandbox-folder" {
- source = "../../../modules/folder"
- count = var.fast_features.sandbox ? 1 : 0
- parent = local.root_node
- name = "Sandbox"
- iam = local._sandbox_folder_iam
- factories_config = {
- org_policies = (
- var.root_node != null || var.factories_config.org_policies == null
- ? null
- : "${var.factories_config.org_policies}/sandbox"
- )
- }
- tag_bindings = {
- context = try(
- local.tag_values["${var.tag_names.context}/sandbox"].id, null
- )
- }
-}
-
-module "branch-sandbox-gcs" {
- source = "../../../modules/gcs"
- count = var.fast_features.sandbox ? 1 : 0
- project_id = var.automation.project_id
- name = "dev-resman-sbox-0"
- prefix = var.prefix
- location = var.locations.gcs
- versioning = true
- iam = {
- "roles/storage.objectAdmin" = [module.branch-sandbox-sa[0].iam_email]
- }
-}
-
-module "branch-sandbox-sa" {
- source = "../../../modules/iam-service-account"
- count = var.fast_features.sandbox ? 1 : 0
- project_id = var.automation.project_id
- name = "dev-resman-sbox-0"
- display_name = "Terraform resman sandbox service account."
- prefix = var.prefix
- iam_project_roles = {
- (var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"]
- }
-}
diff --git a/fast/stages/1-resman/branch-security.tf b/fast/stages/1-resman/branch-security.tf
deleted file mode 100644
index 97cba1d7b..000000000
--- a/fast/stages/1-resman/branch-security.tf
+++ /dev/null
@@ -1,135 +0,0 @@
-/**
- * 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 stage resources.
-
-locals {
- # FAST-specific IAM
- _security_folder_fast_iam = {
- "roles/logging.admin" = [module.branch-security-sa.iam_email]
- "roles/owner" = [module.branch-security-sa.iam_email]
- "roles/resourcemanager.folderAdmin" = [module.branch-security-sa.iam_email]
- "roles/resourcemanager.projectCreator" = [module.branch-security-sa.iam_email]
- # read-only (plan) automation service account
- "roles/viewer" = [module.branch-security-r-sa.iam_email]
- "roles/resourcemanager.folderViewer" = [module.branch-security-r-sa.iam_email]
- }
-
- # deep-merge FAST-specific IAM with user-provided bindings in var.folder_iam
- _security_folder_iam = merge(
- var.folder_iam.security,
- {
- for role, principals in local._security_folder_fast_iam :
- role => distinct(concat(principals, lookup(var.folder_iam.security, role, [])))
- }
- )
-}
-
-module "branch-security-folder" {
- source = "../../../modules/folder"
- parent = local.root_node
- name = "Security"
- iam_by_principals = {
- (local.principals.gcp-security-admins) = [
- # owner and viewer roles are broad and might grant unwanted access
- # replace them with more selective custom roles for production deployments
- "roles/editor"
- ]
- }
- iam = local._security_folder_iam
- iam_bindings = {
- tenant_iam_admin_conditional = {
- members = [
- module.branch-security-sa.iam_email,
- ]
- role = "roles/resourcemanager.folderIamAdmin"
- condition = {
- expression = format(
- "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])",
- join(",", formatlist("'%s'", [
- "roles/privateca.certificateManager"
- ]))
- )
- title = "security_sa_delegated_grants"
- description = "Certificate Authority Service delegated grants."
- }
- }
- }
- tag_bindings = {
- context = try(
- local.tag_values["${var.tag_names.context}/security"].id, null
- )
- }
-}
-
-# automation service account
-
-module "branch-security-sa" {
- source = "../../../modules/iam-service-account"
- project_id = var.automation.project_id
- name = "prod-resman-sec-0"
- display_name = "Terraform resman security service account."
- prefix = var.prefix
- service_account_create = var.root_node == null
- iam = {
- "roles/iam.serviceAccountTokenCreator" = compact([
- try(module.branch-security-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-security-r-sa" {
- source = "../../../modules/iam-service-account"
- project_id = var.automation.project_id
- name = "prod-resman-sec-0r"
- display_name = "Terraform resman security service account (read-only)."
- prefix = var.prefix
- service_account_create = var.root_node == null
- iam = {
- "roles/iam.serviceAccountTokenCreator" = compact([
- try(module.branch-security-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-security-gcs" {
- source = "../../../modules/gcs"
- project_id = var.automation.project_id
- name = "prod-resman-sec-0"
- prefix = var.prefix
- location = var.locations.gcs
- versioning = true
- iam = {
- "roles/storage.objectAdmin" = [module.branch-security-sa.iam_email]
- "roles/storage.objectViewer" = [module.branch-security-r-sa.iam_email]
- }
-}
diff --git a/fast/stages/1-resman/checklist.tf b/fast/stages/1-resman/checklist.tf
deleted file mode 100644
index 55b57bc8c..000000000
--- a/fast/stages/1-resman/checklist.tf
+++ /dev/null
@@ -1,111 +0,0 @@
-/**
- * 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.
- */
-
-locals {
- # parse raw data from JSON files if they exist
- _cl_data_raw = (
- var.factories_config.checklist_data == null
- ? null
- : jsondecode(file(pathexpand(var.factories_config.checklist_data)))
- )
- # check that files are for the correct organization and ignore them if not
- _cl_data = (
- try(local._cl_data_raw.cloud_setup_config.organization.id, null) != tostring(var.organization.id)
- ? null
- : local._cl_data_raw.cloud_setup_config
- )
- # normalized IAM bindings one element per binding
- _cl_iam = local._cl_data == null ? [] : flatten([
- for v in try(local._cl_data.access_control, []) : [
- for r in v.role : {
- principal = v.principal
- resource_id = v.resource.id
- role = r
- } if v.resource.type == "FOLDER"
- ]
- ])
- # compile the final data structure we will consume from various places
- checklist = {
- hierarchy = local._cl_data == null ? {} : {
- for v in try(local._cl_data.folders, []) : v.reference_id => {
- level = length(split("/", v.reference_id))
- name = v.display_name
- parent_id = v.parent
- }
- }
- iam = {
- for v in local._cl_iam : v.resource_id => v...
- }
- }
-}
-
-check "checklist" {
- # version mismatch might be ok, we just alert users
- assert {
- condition = (
- var.factories_config.checklist_data == null ||
- try(local._cl_data_raw.cloud_setup_config.version, null) == "0.1.0"
- )
- error_message = "Checklist data version mismatch."
- }
- # wrong org id forces us to ignore the files, but we also alert users
- assert {
- condition = (
- var.factories_config.checklist_data == null ||
- try(local._cl_data_raw.cloud_setup_config.organization.id, null) == tostring(var.organization.id)
- )
- error_message = "Checklist data organization id mismatch, file ignored."
- }
-}
-
-module "checklist-folder-1" {
- source = "../../../modules/folder"
- for_each = {
- for k, v in local.checklist.hierarchy : k => v if v.level == 1
- }
- parent = "organizations/${var.organization.id}"
- name = each.value.name
- iam = {
- for v in try(local.checklist.iam[each.key], []) :
- v.role => v.principal...
- }
-}
-
-module "checklist-folder-2" {
- source = "../../../modules/folder"
- for_each = {
- for k, v in local.checklist.hierarchy : k => v if v.level == 2
- }
- parent = module.checklist-folder-1[each.value.parent_id].id
- name = each.value.name
- iam = {
- for v in try(local.checklist.iam[each.key], []) :
- v.role => v.principal...
- }
-}
-
-module "checklist-folder-3" {
- source = "../../../modules/folder"
- for_each = {
- for k, v in local.checklist.hierarchy : k => v if v.level == 3
- }
- parent = module.checklist-folder-2[each.value.parent_id].id
- name = each.value.name
- iam = {
- for v in try(local.checklist.iam[each.key], []) :
- v.role => v.principal...
- }
-}
diff --git a/fast/stages/1-resman/cicd-data-platform.tf b/fast/stages/1-resman/cicd-data-platform.tf
deleted file mode 100644
index f16fd0a1b..000000000
--- a/fast/stages/1-resman/cicd-data-platform.tf
+++ /dev/null
@@ -1,159 +0,0 @@
-/**
- * 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 data platform branch.
-
-# read-write (apply) SAs used by CI/CD workflows to impersonate automation SAs
-
-module "branch-dp-dev-sa-cicd" {
- source = "../../../modules/iam-service-account"
- for_each = (
- try(local.cicd_repositories.data_platform_dev.name, null) != null
- ? { 0 = local.cicd_repositories.data_platform_dev }
- : {}
- )
- project_id = var.automation.project_id
- name = "dev-resman-dp-1"
- display_name = "Terraform CI/CD data platform development 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
- )
- : length(regexall("%s", local.identity_providers[each.value.identity_provider].principal_branch)) == 2
- ? format(
- local.identity_providers[each.value.identity_provider].principal_branch,
- var.automation.federated_identity_pool,
- each.value.branch
- )
- : format(
- local.identity_providers[each.value.identity_provider].principal_branch,
- var.automation.federated_identity_pool,
- each.value.name,
- each.value.branch
- )
- ]
- }
- iam_project_roles = {
- (var.automation.project_id) = ["roles/logging.logWriter"]
- }
- iam_storage_roles = {
- (var.automation.outputs_bucket) = ["roles/storage.objectViewer"]
- }
-}
-
-module "branch-dp-prod-sa-cicd" {
- source = "../../../modules/iam-service-account"
- for_each = (
- try(local.cicd_repositories.data_platform_prod.name, null) != null
- ? { 0 = local.cicd_repositories.data_platform_prod }
- : {}
- )
- project_id = var.automation.project_id
- name = "prod-resman-dp-1"
- display_name = "Terraform CI/CD data platform production 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
- )
- : length(regexall("%s", local.identity_providers[each.value.identity_provider].principal_branch)) == 2
- ? format(
- local.identity_providers[each.value.identity_provider].principal_branch,
- var.automation.federated_identity_pool,
- each.value.branch
- )
- : 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) SAs used by CI/CD workflows to impersonate automation SAs
-
-module "branch-dp-dev-r-sa-cicd" {
- source = "../../../modules/iam-service-account"
- for_each = (
- try(local.cicd_repositories.data_platform_dev.name, null) != null
- ? { 0 = local.cicd_repositories.data_platform_dev }
- : {}
- )
- project_id = var.automation.project_id
- name = "dev-resman-dp-1r"
- display_name = "Terraform CI/CD data platform development service account (read-only)."
- prefix = var.prefix
- iam = {
- "roles/iam.workloadIdentityUser" = [
- format(
- local.identity_providers[each.value.identity_provider].principal_repo,
- var.automation.federated_identity_pool,
- each.value.name
- )
- ]
- }
- iam_project_roles = {
- (var.automation.project_id) = ["roles/logging.logWriter"]
- }
- iam_storage_roles = {
- (var.automation.outputs_bucket) = ["roles/storage.objectViewer"]
- }
-}
-
-module "branch-dp-prod-r-sa-cicd" {
- source = "../../../modules/iam-service-account"
- for_each = (
- try(local.cicd_repositories.data_platform_prod.name, null) != null
- ? { 0 = local.cicd_repositories.data_platform_prod }
- : {}
- )
- project_id = var.automation.project_id
- name = "prod-resman-dp-1r"
- display_name = "Terraform CI/CD data platform production 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/cicd-gcve.tf b/fast/stages/1-resman/cicd-gcve.tf
deleted file mode 100644
index ded709dbf..000000000
--- a/fast/stages/1-resman/cicd-gcve.tf
+++ /dev/null
@@ -1,159 +0,0 @@
-/**
- * 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 GCVE branch.
-
-# read-write (apply) SAs used by CI/CD workflows to impersonate automation SAs
-
-module "branch-gcve-dev-sa-cicd" {
- source = "../../../modules/iam-service-account"
- for_each = (
- try(local.cicd_repositories.gcve_dev.name, null) != null
- ? { 0 = local.cicd_repositories.gcve_dev }
- : {}
- )
- project_id = var.automation.project_id
- name = "dev-resman-gcve-1"
- display_name = "Terraform CI/CD GCVE development 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
- )
- : length(regexall("%s", local.identity_providers[each.value.identity_provider].principal_branch)) == 2
- ? format(
- local.identity_providers[each.value.identity_provider].principal_branch,
- var.automation.federated_identity_pool,
- each.value.branch
- )
- : format(
- local.identity_providers[each.value.identity_provider].principal_branch,
- var.automation.federated_identity_pool,
- each.value.name,
- each.value.branch
- )
- ]
- }
- iam_project_roles = {
- (var.automation.project_id) = ["roles/logging.logWriter"]
- }
- iam_storage_roles = {
- (var.automation.outputs_bucket) = ["roles/storage.objectViewer"]
- }
-}
-
-module "branch-gcve-prod-sa-cicd" {
- source = "../../../modules/iam-service-account"
- for_each = (
- try(local.cicd_repositories.gcve_prod.name, null) != null
- ? { 0 = local.cicd_repositories.gcve_prod }
- : {}
- )
- project_id = var.automation.project_id
- name = "prod-resman-gcve-1"
- display_name = "Terraform CI/CD GCVE production 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
- )
- : length(regexall("%s", local.identity_providers[each.value.identity_provider].principal_branch)) == 2
- ? format(
- local.identity_providers[each.value.identity_provider].principal_branch,
- var.automation.federated_identity_pool,
- each.value.branch
- )
- : 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) SAs used by CI/CD workflows to impersonate automation SAs
-
-module "branch-gcve-dev-r-sa-cicd" {
- source = "../../../modules/iam-service-account"
- for_each = (
- try(local.cicd_repositories.gcve_dev.name, null) != null
- ? { 0 = local.cicd_repositories.gcve_dev }
- : {}
- )
- project_id = var.automation.project_id
- name = "dev-resman-gcve-1r"
- display_name = "Terraform CI/CD GCVE development service account (read-only)."
- prefix = var.prefix
- iam = {
- "roles/iam.workloadIdentityUser" = [
- format(
- local.identity_providers[each.value.identity_provider].principal_repo,
- var.automation.federated_identity_pool,
- each.value.name
- )
- ]
- }
- iam_project_roles = {
- (var.automation.project_id) = ["roles/logging.logWriter"]
- }
- iam_storage_roles = {
- (var.automation.outputs_bucket) = ["roles/storage.objectViewer"]
- }
-}
-
-module "branch-gcve-prod-r-sa-cicd" {
- source = "../../../modules/iam-service-account"
- for_each = (
- try(local.cicd_repositories.gcve_prod.name, null) != null
- ? { 0 = local.cicd_repositories.gcve_prod }
- : {}
- )
- project_id = var.automation.project_id
- name = "prod-resman-gcve-1r"
- display_name = "Terraform CI/CD GCVE production 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/cicd-gke.tf b/fast/stages/1-resman/cicd-gke.tf
deleted file mode 100644
index d934a763e..000000000
--- a/fast/stages/1-resman/cicd-gke.tf
+++ /dev/null
@@ -1,159 +0,0 @@
-/**
- * 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 GKE multitenant branch.
-
-# read-write (apply) SAs used by CI/CD workflows to impersonate automation SAs
-
-module "branch-gke-dev-sa-cicd" {
- source = "../../../modules/iam-service-account"
- for_each = (
- try(local.cicd_repositories.gke_dev.name, null) != null
- ? { 0 = local.cicd_repositories.gke_dev }
- : {}
- )
- project_id = var.automation.project_id
- name = "dev-resman-gke-1"
- display_name = "Terraform CI/CD GKE development 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
- )
- : length(regexall("%s", local.identity_providers[each.value.identity_provider].principal_branch)) == 2
- ? format(
- local.identity_providers[each.value.identity_provider].principal_branch,
- var.automation.federated_identity_pool,
- each.value.branch
- )
- : format(
- local.identity_providers[each.value.identity_provider].principal_branch,
- var.automation.federated_identity_pool,
- each.value.name,
- each.value.branch
- )
- ]
- }
- iam_project_roles = {
- (var.automation.project_id) = ["roles/logging.logWriter"]
- }
- iam_storage_roles = {
- (var.automation.outputs_bucket) = ["roles/storage.objectViewer"]
- }
-}
-
-module "branch-gke-prod-sa-cicd" {
- source = "../../../modules/iam-service-account"
- for_each = (
- try(local.cicd_repositories.gke_prod.name, null) != null
- ? { 0 = local.cicd_repositories.gke_prod }
- : {}
- )
- project_id = var.automation.project_id
- name = "prod-resman-gke-1"
- display_name = "Terraform CI/CD GKE production 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
- )
- : length(regexall("%s", local.identity_providers[each.value.identity_provider].principal_branch)) == 2
- ? format(
- local.identity_providers[each.value.identity_provider].principal_branch,
- var.automation.federated_identity_pool,
- each.value.branch
- )
- : 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) SAs used by CI/CD workflows to impersonate automation SAs
-
-module "branch-gke-dev-r-sa-cicd" {
- source = "../../../modules/iam-service-account"
- for_each = (
- try(local.cicd_repositories.gke_dev.name, null) != null
- ? { 0 = local.cicd_repositories.gke_dev }
- : {}
- )
- project_id = var.automation.project_id
- name = "dev-resman-gke-1r"
- display_name = "Terraform CI/CD gke multitenant development service account (read-only)."
- prefix = var.prefix
- iam = {
- "roles/iam.workloadIdentityUser" = [
- format(
- local.identity_providers[each.value.identity_provider].principal_repo,
- var.automation.federated_identity_pool,
- each.value.name
- )
- ]
- }
- iam_project_roles = {
- (var.automation.project_id) = ["roles/logging.logWriter"]
- }
- iam_storage_roles = {
- (var.automation.outputs_bucket) = ["roles/storage.objectViewer"]
- }
-}
-
-module "branch-gke-prod-r-sa-cicd" {
- source = "../../../modules/iam-service-account"
- for_each = (
- try(local.cicd_repositories.gke_prod.name, null) != null
- ? { 0 = local.cicd_repositories.gke_prod }
- : {}
- )
- project_id = var.automation.project_id
- name = "prod-resman-gke-1r"
- display_name = "Terraform CI/CD gke multitenant production 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/cicd-netsec.tf b/fast/stages/1-resman/cicd-netsec.tf
deleted file mode 100644
index f66327f68..000000000
--- a/fast/stages/1-resman/cicd-netsec.tf
+++ /dev/null
@@ -1,91 +0,0 @@
-/**
- * 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 nsec automation SA
-
-module "branch-nsec-sa-cicd" {
- source = "../../../modules/iam-service-account"
- for_each = (
- try(local.cicd_repositories.nsec.name, null) != null
- ? { 0 = local.cicd_repositories.nsec }
- : {}
- )
- project_id = var.automation.project_id
- name = "prod-resman-nsec-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
- )
- : length(regexall("%s", local.identity_providers[each.value.identity_provider].principal_branch)) == 2
- ? format(
- local.identity_providers[each.value.identity_provider].principal_branch,
- var.automation.federated_identity_pool,
- each.value.branch
- )
- : 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 nsec automation SA
-
-module "branch-nsec-r-sa-cicd" {
- source = "../../../modules/iam-service-account"
- for_each = (
- try(local.cicd_repositories.nsec.name, null) != null
- ? { 0 = local.cicd_repositories.nsec }
- : {}
- )
- project_id = var.automation.project_id
- name = "prod-resman-nsec-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/cicd-networking.tf b/fast/stages/1-resman/cicd-networking.tf
deleted file mode 100644
index 6262db4a7..000000000
--- a/fast/stages/1-resman/cicd-networking.tf
+++ /dev/null
@@ -1,90 +0,0 @@
-/**
- * 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 automation SA
-
-module "branch-network-sa-cicd" {
- source = "../../../modules/iam-service-account"
- for_each = (
- try(local.cicd_repositories.networking.name, null) != null
- ? { 0 = local.cicd_repositories.networking }
- : {}
- )
- project_id = var.automation.project_id
- name = "prod-resman-net-1"
- display_name = "Terraform CI/CD stage 2 networking 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
- )
- : length(regexall("%s", local.identity_providers[each.value.identity_provider].principal_branch)) == 2
- ? format(
- local.identity_providers[each.value.identity_provider].principal_branch,
- var.automation.federated_identity_pool,
- each.value.branch
- )
- : 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 automation SA
-
-module "branch-network-r-sa-cicd" {
- source = "../../../modules/iam-service-account"
- for_each = (
- try(local.cicd_repositories.networking.name, null) != null
- ? { 0 = local.cicd_repositories.networking }
- : {}
- )
- project_id = var.automation.project_id
- name = "prod-resman-net-1r"
- display_name = "Terraform CI/CD stage 2 networking 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/cicd-project-factory.tf b/fast/stages/1-resman/cicd-project-factory.tf
deleted file mode 100644
index 0e145dc62..000000000
--- a/fast/stages/1-resman/cicd-project-factory.tf
+++ /dev/null
@@ -1,228 +0,0 @@
-/**
- * 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 project factories.
-
-# read-write (apply) SAs used by CI/CD workflows to impersonate automation SAs
-
-module "branch-pf-sa-cicd" {
- source = "../../../modules/iam-service-account"
- for_each = (
- try(local.cicd_repositories.project_factory.name, null) != null
- ? { 0 = local.cicd_repositories.project_factory }
- : {}
- )
- project_id = var.automation.project_id
- name = "pf-resman-pf-1"
- display_name = "Terraform CI/CD project factory main service account."
- prefix = var.prefix
- iam = {
- "roles/iam.workloadIdentityUser" = [
- each.value.branch == null
- ? format(
- local.identity_providers[each.value.identity_provider].principal_repo,
- var.automation.federated_identity_pool,
- each.value.name
- )
- : length(regexall("%s", local.identity_providers[each.value.identity_provider].principal_branch)) == 2
- ? format(
- local.identity_providers[each.value.identity_provider].principal_branch,
- var.automation.federated_identity_pool,
- each.value.branch
- )
- : format(
- local.identity_providers[each.value.identity_provider].principal_branch,
- var.automation.federated_identity_pool,
- each.value.name,
- each.value.branch
- )
- ]
- }
- iam_project_roles = {
- (var.automation.project_id) = ["roles/logging.logWriter"]
- }
- iam_storage_roles = {
- (var.automation.outputs_bucket) = ["roles/storage.objectViewer"]
- }
-}
-
-module "branch-pf-dev-sa-cicd" {
- source = "../../../modules/iam-service-account"
- for_each = (
- try(local.cicd_repositories.project_factory_dev.name, null) != null
- ? { 0 = local.cicd_repositories.project_factory_dev }
- : {}
- )
- project_id = var.automation.project_id
- name = "dev-pf-resman-pf-1"
- display_name = "Terraform CI/CD project factory development 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
- )
- : length(regexall("%s", local.identity_providers[each.value.identity_provider].principal_branch)) == 2
- ? format(
- local.identity_providers[each.value.identity_provider].principal_branch,
- var.automation.federated_identity_pool,
- each.value.branch
- )
- : format(
- local.identity_providers[each.value.identity_provider].principal_branch,
- var.automation.federated_identity_pool,
- each.value.name,
- each.value.branch
- )
- ]
- }
- iam_project_roles = {
- (var.automation.project_id) = ["roles/logging.logWriter"]
- }
- iam_storage_roles = {
- (var.automation.outputs_bucket) = ["roles/storage.objectViewer"]
- }
-}
-
-module "branch-pf-prod-sa-cicd" {
- source = "../../../modules/iam-service-account"
- for_each = (
- try(local.cicd_repositories.project_factory_prod.name, null) != null
- ? { 0 = local.cicd_repositories.project_factory_prod }
- : {}
- )
- project_id = var.automation.project_id
- name = "prod-pf-resman-pf-1"
- display_name = "Terraform CI/CD project factory production 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
- )
- : length(regexall("%s", local.identity_providers[each.value.identity_provider].principal_branch)) == 2
- ? format(
- local.identity_providers[each.value.identity_provider].principal_branch,
- var.automation.federated_identity_pool,
- each.value.branch
- )
- : 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) SAs used by CI/CD workflows to impersonate automation SAs
-
-module "branch-pf-r-sa-cicd" {
- source = "../../../modules/iam-service-account"
- for_each = (
- try(local.cicd_repositories.project_factory.name, null) != null
- ? { 0 = local.cicd_repositories.project_factory }
- : {}
- )
- project_id = var.automation.project_id
- name = "resman-pf-1r"
- display_name = "Terraform CI/CD project factory main service account (read-only)."
- prefix = var.prefix
- iam = {
- "roles/iam.workloadIdentityUser" = [
- format(
- local.identity_providers[each.value.identity_provider].principal_repo,
- var.automation.federated_identity_pool,
- each.value.name
- )
- ]
- }
- iam_project_roles = {
- (var.automation.project_id) = ["roles/logging.logWriter"]
- }
- iam_storage_roles = {
- (var.automation.outputs_bucket) = ["roles/storage.objectViewer"]
- }
-}
-
-module "branch-pf-dev-r-sa-cicd" {
- source = "../../../modules/iam-service-account"
- for_each = (
- try(local.cicd_repositories.project_factory_dev.name, null) != null
- ? { 0 = local.cicd_repositories.project_factory_dev }
- : {}
- )
- project_id = var.automation.project_id
- name = "dev-resman-pf-1r"
- display_name = "Terraform CI/CD project factory development service account (read-only)."
- prefix = var.prefix
- iam = {
- "roles/iam.workloadIdentityUser" = [
- format(
- local.identity_providers[each.value.identity_provider].principal_repo,
- var.automation.federated_identity_pool,
- each.value.name
- )
- ]
- }
- iam_project_roles = {
- (var.automation.project_id) = ["roles/logging.logWriter"]
- }
- iam_storage_roles = {
- (var.automation.outputs_bucket) = ["roles/storage.objectViewer"]
- }
-}
-
-module "branch-pf-prod-r-sa-cicd" {
- source = "../../../modules/iam-service-account"
- for_each = (
- try(local.cicd_repositories.project_factory_prod.name, null) != null
- ? { 0 = local.cicd_repositories.project_factory_prod }
- : {}
- )
- project_id = var.automation.project_id
- name = "prod-resman-pf-1r"
- display_name = "Terraform CI/CD project factory production 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/cicd-security.tf b/fast/stages/1-resman/cicd-security.tf
deleted file mode 100644
index 086f8d929..000000000
--- a/fast/stages/1-resman/cicd-security.tf
+++ /dev/null
@@ -1,90 +0,0 @@
-/**
- * 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 security branch.
-
-# read-write (apply) SA used by CI/CD workflows to impersonate automation SA
-
-module "branch-security-sa-cicd" {
- source = "../../../modules/iam-service-account"
- for_each = (
- try(local.cicd_repositories.security.name, null) != null
- ? { 0 = local.cicd_repositories.security }
- : {}
- )
- project_id = var.automation.project_id
- name = "prod-resman-sec-1"
- display_name = "Terraform CI/CD stage 2 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
- )
- : length(regexall("%s", local.identity_providers[each.value.identity_provider].principal_branch)) == 2
- ? format(
- local.identity_providers[each.value.identity_provider].principal_branch,
- var.automation.federated_identity_pool,
- each.value.branch
- )
- : 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 automation SA
-
-module "branch-security-r-sa-cicd" {
- source = "../../../modules/iam-service-account"
- for_each = (
- try(local.cicd_repositories.security.name, null) != null
- ? { 0 = local.cicd_repositories.security }
- : {}
- )
- project_id = var.automation.project_id
- name = "prod-resman-sec-1r"
- display_name = "Terraform CI/CD stage 2 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/data/stage-3/gcve-dev.yaml b/fast/stages/1-resman/data/stage-3/gcve-dev.yaml
new file mode 100644
index 000000000..e36796dee
--- /dev/null
+++ b/fast/stages/1-resman/data/stage-3/gcve-dev.yaml
@@ -0,0 +1,29 @@
+# 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.
+
+# yaml-language-server: $schema=../../schemas/fast-stage3.schema.json
+
+short_name: gcve
+environment: dev
+folder_config:
+ name: Development
+ parent_id: gcve
+stage2_iam:
+ networking:
+ iam_admin_delegated: true
+ sa_roles:
+ ro:
+ - gcve_network_viewer
+ rw:
+ - gcve_network_admin
\ No newline at end of file
diff --git a/fast/stages/1-resman/data/stage-3/gcve-prod.yaml b/fast/stages/1-resman/data/stage-3/gcve-prod.yaml
new file mode 100644
index 000000000..789064090
--- /dev/null
+++ b/fast/stages/1-resman/data/stage-3/gcve-prod.yaml
@@ -0,0 +1,29 @@
+# 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.
+
+# yaml-language-server: $schema=../../schemas/fast-stage3.schema.json
+
+short_name: gcve
+environment: prod
+folder_config:
+ name: Production
+ parent_id: gcve
+stage2_iam:
+ networking:
+ iam_admin_delegated: true
+ sa_roles:
+ ro:
+ - gcve_network_viewer
+ rw:
+ - gcve_network_admin
\ No newline at end of file
diff --git a/fast/stages/1-resman/data/stage-3/gke-dev.yaml b/fast/stages/1-resman/data/stage-3/gke-dev.yaml
new file mode 100644
index 000000000..c15fdb417
--- /dev/null
+++ b/fast/stages/1-resman/data/stage-3/gke-dev.yaml
@@ -0,0 +1,29 @@
+# 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.
+
+# yaml-language-server: $schema=../../schemas/fast-stage3.schema.json
+
+short_name: gke
+environment: dev
+folder_config:
+ name: Development
+ parent_id: gke
+stage2_iam:
+ networking:
+ iam_admin_delegated: true
+ sa_roles:
+ ro:
+ - roles/dns.reader
+ rw:
+ - roles/dns.admin
diff --git a/fast/stages/1-resman/data/stage-3/gke-prod.yaml b/fast/stages/1-resman/data/stage-3/gke-prod.yaml
new file mode 100644
index 000000000..97b5396a9
--- /dev/null
+++ b/fast/stages/1-resman/data/stage-3/gke-prod.yaml
@@ -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.
+
+# yaml-language-server: $schema=../../schemas/fast-stage3.schema.json
+
+short_name: gke
+environment: prod
+folder_config:
+ name: Production
+ parent_id: gke
+stage2_iam:
+ networking:
+ sa_roles:
+ ro:
+ - roles/dns.reader
+ rw:
+ - roles/dns.admin
diff --git a/fast/stages/1-resman/data/stage-3/project-factory-dev.yaml b/fast/stages/1-resman/data/stage-3/project-factory-dev.yaml
new file mode 100644
index 000000000..e99aa60d1
--- /dev/null
+++ b/fast/stages/1-resman/data/stage-3/project-factory-dev.yaml
@@ -0,0 +1,23 @@
+# 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.
+
+# yaml-language-server: $schema=../../schemas/fast-stage3.schema.json
+
+short_name: pf
+environment: dev
+stage2_iam:
+ networking:
+ iam_admin_delegated: true
+ security:
+ iam_admin_delegated: true
diff --git a/fast/stages/1-resman/data/stage-3/project-factory-prod.yaml b/fast/stages/1-resman/data/stage-3/project-factory-prod.yaml
new file mode 100644
index 000000000..bc6b3eb7e
--- /dev/null
+++ b/fast/stages/1-resman/data/stage-3/project-factory-prod.yaml
@@ -0,0 +1,23 @@
+# 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.
+
+# yaml-language-server: $schema=../../schemas/fast-stage3.schema.json
+
+short_name: pf
+environment: prod
+stage2_iam:
+ networking:
+ iam_admin_delegated: true
+ security:
+ iam_admin_delegated: true
diff --git a/fast/stages/1-resman/data/top-level-folders/gcve.yaml b/fast/stages/1-resman/data/top-level-folders/gcve.yaml
new file mode 100644
index 000000000..13af215e2
--- /dev/null
+++ b/fast/stages/1-resman/data/top-level-folders/gcve.yaml
@@ -0,0 +1,17 @@
+# 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.
+
+# yaml-language-server: $schema=../../schemas/top-level-folder.schema.json
+
+name: GCVE
diff --git a/tests/fast/stages/s3_gke_multitenant/tftest.yaml b/fast/stages/1-resman/data/top-level-folders/gke.yaml
similarity index 82%
rename from tests/fast/stages/s3_gke_multitenant/tftest.yaml
rename to fast/stages/1-resman/data/top-level-folders/gke.yaml
index 39bf42c4c..789a792b2 100644
--- a/tests/fast/stages/s3_gke_multitenant/tftest.yaml
+++ b/fast/stages/1-resman/data/top-level-folders/gke.yaml
@@ -1,4 +1,4 @@
-# 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.
@@ -12,7 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-module: fast/stages/3-gke-multitenant/dev/
+# yaml-language-server: $schema=../../schemas/top-level-folder.schema.json
-tests:
- simple:
+name: GKE
diff --git a/fast/stages/1-resman/data/top-level-folders/sandbox.yaml b/fast/stages/1-resman/data/top-level-folders/sandbox.yaml
new file mode 100644
index 000000000..e82b31c35
--- /dev/null
+++ b/fast/stages/1-resman/data/top-level-folders/sandbox.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.
+
+# yaml-language-server: $schema=../../schemas/top-level-folder.schema.json
+
+name: Sandbox
+automation:
+ environment_name: dev
+ short_name: sbox
+factories_config:
+ org_policies: data/org-policies/sandbox
diff --git a/fast/stages/1-resman/data/top-level-folders/teams.yaml b/fast/stages/1-resman/data/top-level-folders/teams.yaml
index 3695ce69d..caa1112c4 100644
--- a/fast/stages/1-resman/data/top-level-folders/teams.yaml
+++ b/fast/stages/1-resman/data/top-level-folders/teams.yaml
@@ -15,8 +15,6 @@
# yaml-language-server: $schema=../../schemas/top-level-folder.schema.json
name: Teams
-automation:
- enable: false
iam:
"roles/owner":
- project-factory
@@ -28,5 +26,13 @@ iam:
- project-factory
"service_project_network_admin":
- project-factory
+ "roles/viewer":
+ - project-factory-r
+ "roles/resourcemanager.folderViewer":
+ - project-factory-r
+ "roles/resourcemanager.tagViewer":
+ - project-factory-r
+# don't create a context tag since this uses the pf tag
+is_fast_context: false
tag_bindings:
context: context/project-factory
diff --git a/fast/stages/1-resman/diagram.png b/fast/stages/1-resman/diagram.png
index 02c12d495..8d3d9665e 100644
Binary files a/fast/stages/1-resman/diagram.png and b/fast/stages/1-resman/diagram.png differ
diff --git a/fast/stages/1-resman/iam.tf b/fast/stages/1-resman/iam.tf
index 4e8e0663f..68a9dcb28 100644
--- a/fast/stages/1-resman/iam.tf
+++ b/fast/stages/1-resman/iam.tf
@@ -17,146 +17,85 @@
# tfdoc:file:description Organization or root node-level IAM bindings.
locals {
+ # aggregated map of organization IAM additive bindings for stages
iam_bindings_additive = merge(
- # network and security
- {
+ # stage 2 networking
+ !var.fast_stage_2.networking.enabled ? {} : {
sa_net_fw_policy_admin = {
- member = module.branch-network-sa.iam_email
+ member = module.net-sa-rw[0].iam_email
role = "roles/compute.orgFirewallPolicyAdmin"
}
sa_net_xpn_admin = {
- member = module.branch-network-sa.iam_email
+ member = module.net-sa-rw[0].iam_email
role = "roles/compute.xpnAdmin"
}
- sa_sec_asset_viewer = {
- member = module.branch-security-sa.iam_email
- role = "roles/cloudasset.viewer"
- }
- # re-enable if VPC-SC management is needed in the 2-security stage
- # sa_sec_vpcsc_admin = {
- # member = module.branch-security-sa.iam_email
- # role = "roles/accesscontextmanager.policyAdmin"
- # }
},
- # optional network security
- var.fast_features.nsec != true ? {} : {
- sa_net_nsec_fw_policy_admin = {
- member = module.branch-nsec-sa[0].iam_email
+ # stage 2 network security
+ !var.fast_stage_2.network_security.enabled ? {} : {
+ sa_nsec_fw_policy_admin = {
+ member = module.nsec-sa-rw[0].iam_email
role = "roles/compute.orgFirewallPolicyAdmin"
}
sa_net_nsec_ngfw_enterprise_admin = {
- member = module.branch-nsec-sa[0].iam_email
- role = local.custom_roles["ngfw_enterprise_admin"],
+ member = module.nsec-sa-rw[0].iam_email
+ role = var.custom_roles["ngfw_enterprise_admin"],
}
- sa_net_nsec_r_fw_policy_user = {
- member = module.branch-nsec-sa[0].iam_email
+ sa_net_nsec_fw_policy_user = {
+ member = module.nsec-sa-rw[0].iam_email
role = "roles/compute.orgFirewallPolicyUser"
}
- sa_net_nsec_r_ngfw_enterprise_viewer = {
- member = module.branch-nsec-r-sa[0].iam_email
- role = local.custom_roles["ngfw_enterprise_viewer"],
+ sa_net_nsec_ro_ngfw_enterprise_viewer = {
+ member = module.nsec-sa-ro[0].iam_email
+ role = var.custom_roles["ngfw_enterprise_viewer"],
}
},
- # optional billing roles for network and security
- local.billing_mode != "org" ? {} : {
- sa_net_billing = {
- member = module.branch-network-sa.iam_email
- role = "roles/billing.user"
- }
- sa_sec_billing = {
- member = module.branch-security-sa.iam_email
- role = "roles/billing.user"
+ # stage 2 security
+ !var.fast_stage_2.security.enabled ? {} : {
+ sa_sec_asset_viewer = {
+ member = module.sec-sa-rw[0].iam_email
+ role = "roles/cloudasset.viewer"
}
},
- # optional billing roles for data platform
- local.billing_mode != "org" || !var.fast_features.data_platform ? {} : {
- sa_dp_dev_billing = {
- member = module.branch-dp-dev-sa[0].iam_email
- role = "roles/billing.user"
- }
- sa_dp_prod_billing = {
- member = module.branch-dp-prod-sa[0].iam_email
- role = "roles/billing.user"
- }
- },
- # optional billing roles for GKE
- local.billing_mode != "org" || !var.fast_features.gke ? {} : {
- sa_gke_dev_billing = {
- member = module.branch-gke-dev-sa[0].iam_email
- role = "roles/billing.user"
- }
- sa_gke_prod_billing = {
- member = module.branch-gke-prod-sa[0].iam_email
- role = "roles/billing.user"
- }
- },
- # optional billing roles for project factory
- local.billing_mode != "org" ? {} : {
- sa_pf_billing = {
- member = module.branch-pf-sa.iam_email
- role = "roles/billing.user"
- }
- sa_pf_costs_manager = {
- member = module.branch-pf-sa.iam_email
- role = "roles/billing.costsManager"
- }
- sa_pf_dev_billing = {
- member = module.branch-pf-dev-sa.iam_email
- role = "roles/billing.user"
- }
- sa_pf_dev_costs_manager = {
- member = module.branch-pf-dev-sa.iam_email
- role = "roles/billing.costsManager"
- }
- sa_pf_prod_billing = {
- member = module.branch-pf-prod-sa.iam_email
- role = "roles/billing.user"
- }
- sa_pf_prod_costs_manager = {
- member = module.branch-pf-prod-sa.iam_email
- role = "roles/billing.costsManager"
- }
- },
- # scoped org policy admin grants for project factory
- # TODO: change to use context and environment tags, and tag bindings in stage 2s
- var.root_node != null ? {} : {
+ # stage 2 project factory
+ var.root_node != null || var.fast_stage_2.project_factory.enabled != true ? {} : {
sa_pf_conditional_org_policy = {
- member = module.branch-pf-sa.iam_email
+ member = module.pf-sa-rw[0].iam_email
role = "roles/orgpolicy.policyAdmin"
condition = {
title = "org_policy_tag_pf_scoped"
- description = "Org policy tag scoped grant for project factory main."
+ description = "Org policy tag scoped grant for project factory."
expression = <<-END
resource.matchTag('${local.tag_root}/${var.tag_names.context}', 'project-factory')
END
}
}
- sa_pf_dev_conditional_org_policy = {
- member = module.branch-pf-dev-sa.iam_email
- role = "roles/orgpolicy.policyAdmin"
- condition = {
- title = "org_policy_tag_pf_scoped_dev"
- description = "Org policy tag scoped grant for project factory dev."
- expression = <<-END
- resource.matchTag('${local.tag_root}/${var.tag_names.context}', 'project-factory')
- &&
- resource.matchTag('${local.tag_root}/${var.tag_names.environment}', 'development')
- END
- }
- }
- sa_pf_prod_conditional_org_policy = {
- member = module.branch-pf-prod-sa.iam_email
- role = "roles/orgpolicy.policyAdmin"
- condition = {
- title = "org_policy_tag_pf_scoped_prod"
- description = "Org policy tag scoped grant for project factory prod."
- expression = <<-END
- resource.matchTag('${local.tag_root}/${var.tag_names.context}', 'project-factory')
- &&
- resource.matchTag('${local.tag_root}/${var.tag_names.environment}', 'production')
- END
- }
- }
},
+ # stage 3
+ {
+ for v in local.stage3_sa_roles_in_org : join("/", values(v)) => {
+ role = lookup(var.custom_roles, v.role, v.role)
+ member = (
+ v.sa == "rw"
+ ? module.stage3-sa-rw[v.s3].iam_email
+ : module.stage3-sa-ro[v.s3].iam_email
+ )
+ condition = {
+ title = "stage3 ${v.s3} ${v.env}"
+ expression = <<-END
+ resource.matchTag(
+ '${local.tag_root}/${var.tag_names.environment}',
+ '${v.env}'
+ )
+ &&
+ resource.matchTag(
+ '${local.tag_root}/${var.tag_names.context}',
+ '${v.context}'
+ )
+ END
+ }
+ }
+ },
+ # billing for all stages
+ local.billing_mode != "org" ? {} : local.billing_iam
)
}
diff --git a/fast/stages/1-resman/main.tf b/fast/stages/1-resman/main.tf
index 9baa822d4..fbff1284e 100644
--- a/fast/stages/1-resman/main.tf
+++ b/fast/stages/1-resman/main.tf
@@ -19,63 +19,7 @@ locals {
# automation_resman_sa = try(
# data.google_client_openid_userinfo.provider_identity[0].email, null
# )
- # stage service accounts, used in top folders and outputs
- branch_service_accounts = {
- data-platform-dev = try(module.branch-dp-dev-sa[0].email, null)
- data-platform-dev-r = try(module.branch-dp-dev-r-sa[0].email, null)
- data-platform-prod = try(module.branch-dp-prod-sa[0].email, null)
- data-platform-prod-r = try(module.branch-dp-prod-r-sa[0].email, null)
- gcve-dev = try(module.branch-gcve-dev-sa[0].email, null)
- gcve-dev-r = try(module.branch-gcve-dev-r-sa[0].email, null)
- gcve-prod = try(module.branch-gcve-prod-sa[0].email, null)
- gcve-prod-r = try(module.branch-gcve-prod-r-sa[0].email, null)
- gke-dev = try(module.branch-gke-dev-sa[0].email, null)
- gke-dev-r = try(module.branch-gke-dev-r-sa[0].email, null)
- gke-prod = try(module.branch-gke-prod-sa[0].email, null)
- gke-prod-r = try(module.branch-gke-prod-r-sa[0].email, null)
- nsec = try(module.branch-nsec-sa[0].email, null)
- nsec-r = try(module.branch-nsec-r-sa[0].email, null)
- networking = module.branch-network-sa.email
- networking-r = module.branch-network-r-sa.email
- project-factory = module.branch-pf-sa.email
- project-factory-r = module.branch-pf-r-sa.email
- project-factory-dev = module.branch-pf-dev-sa.email
- project-factory-dev-r = module.branch-pf-dev-r-sa.email
- project-factory-prod = module.branch-pf-prod-sa.email
- project-factory-prod-r = module.branch-pf-prod-r-sa.email
- sandbox = try(module.branch-sandbox-sa[0].email, null)
- security = module.branch-security-sa.email
- security-r = module.branch-security-r-sa.email
- }
- # normalize CI/CD repositories
- cicd_repositories = {
- for k, v in coalesce(var.cicd_repositories, {}) : k => v
- if(
- v != null &&
- contains(
- keys(local.identity_providers),
- coalesce(try(v.identity_provider, null), ":")
- ) && (
- try(v.type, "") == "terraform" ||
- fileexists("${path.module}/templates/workflow-${try(v.type, "")}.yaml")
- )
- )
- }
- cicd_workflow_var_files = {
- stage_2 = [
- "0-bootstrap.auto.tfvars.json",
- "1-resman.auto.tfvars.json",
- "0-globals.auto.tfvars.json"
- ]
- stage_3 = [
- "0-bootstrap.auto.tfvars.json",
- "1-resman.auto.tfvars.json",
- "0-globals.auto.tfvars.json",
- "2-networking.auto.tfvars.json",
- "2-security.auto.tfvars.json"
- ]
- }
- custom_roles = coalesce(var.custom_roles, {})
+ # tag values use descriptive names
identity_providers = coalesce(
try(var.automation.federated_identity_providers, null), {}
)
@@ -91,6 +35,22 @@ locals {
? "organizations/${var.organization.id}"
: var.root_node
)
+ stage_service_accounts = merge(
+ !var.fast_stage_2.networking.enabled ? {} : {
+ networking = module.net-sa-rw[0].email
+ networking-r = module.net-sa-ro[0].email
+ },
+ !var.fast_stage_2.security.enabled ? {} : {
+ security = module.sec-sa-rw[0].email
+ security-r = module.sec-sa-ro[0].email
+ },
+ !var.fast_stage_2.project_factory.enabled ? {} : {
+ project-factory = module.pf-sa-rw[0].email
+ project-factory-r = module.pf-sa-ro[0].email
+ },
+ { for k, v in local.stage3 : k => module.stage3-sa-rw[k].email },
+ { for k, v in local.stage3 : "${k}-r" => module.stage3-sa-ro[k].email },
+ )
tag_keys = (
var.root_node == null
? module.organization[0].tag_keys
@@ -106,6 +66,12 @@ locals {
? module.organization[0].tag_values
: module.automation-project[0].tag_values
)
+ top_level_folder_ids = {
+ for k, v in module.top-level-folder : k => v.id
+ }
+ top_level_service_accounts = {
+ for k, v in module.top-level-sa : k => try(v.email)
+ }
}
# data "google_client_openid_userinfo" "provider_identity" {
diff --git a/fast/stages/1-resman/moved/v33.0.0-v34.0.0.tf b/fast/stages/1-resman/moved/v33.0.0-v34.0.0.tf
index b20783030..9b13d9e59 100644
--- a/fast/stages/1-resman/moved/v33.0.0-v34.0.0.tf
+++ b/fast/stages/1-resman/moved/v33.0.0-v34.0.0.tf
@@ -18,42 +18,34 @@ moved {
from = module.branch-pf-sa[0]
to = module.branch-pf-sa
}
-
moved {
from = module.branch-pf-dev-sa[0]
to = module.branch-pf-dev-sa
}
-
moved {
from = module.branch-pf-prod-sa[0]
to = module.branch-pf-prod-sa
}
-
moved {
from = module.branch-pf-r-sa[0]
to = module.branch-pf-r-sa
}
-
moved {
from = module.branch-pf-dev-r-sa[0]
to = module.branch-pf-dev-r-sa
}
-
moved {
from = module.branch-pf-prod-r-sa[0]
to = module.branch-pf-prod-r-sa
}
-
moved {
from = module.branch-pf-gcs[0]
to = module.branch-pf-gcs
}
-
moved {
from = module.branch-pf-dev-gcs[0]
to = module.branch-pf-dev-gcs
}
-
moved {
from = module.branch-pf-prod-gcs[0]
to = module.branch-pf-prod-gcs
diff --git a/fast/stages/1-resman/moved/v35.1.0-v36.0.0.tf b/fast/stages/1-resman/moved/v35.1.0-v36.0.0.tf
new file mode 100644
index 000000000..f9934257d
--- /dev/null
+++ b/fast/stages/1-resman/moved/v35.1.0-v36.0.0.tf
@@ -0,0 +1,238 @@
+/**
+ * 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.
+ */
+
+# stage 2 networking
+
+moved {
+ from = module.branch-network-folder
+ to = module.net-folder[0]
+}
+moved {
+ from = module.branch-network-dev-folder
+ to = module.net-folder-dev[0]
+}
+moved {
+ from = module.branch-network-prod-folder
+ to = module.net-folder-prod[0]
+}
+moved {
+ from = module.branch-network-gcs
+ to = module.net-bucket[0]
+}
+moved {
+ from = module.branch-network-sa
+ to = module.net-sa-ro[0]
+}
+moved {
+ from = module.branch-network-r-sa
+ to = module.net-sa-rw[0]
+}
+
+# stage 2 network security
+
+moved {
+ from = module.branch-nsec-gcs[0]
+ to = module.nsec-bucket[0]
+}
+moved {
+ from = module.branch-nsec-sa[0]
+ to = module.nsec-sa-rw[0]
+}
+moved {
+ from = module.branch-nsec-r-sa[0]
+ to = module.nsec-sa-ro[0]
+}
+moved {
+ from = module.branch-networking-sa-cicd["0"]
+ to = module.cicd-sa-rw["networking"]
+}
+moved {
+ from = module.branch-networking-r-sa-cicd["0"]
+ to = module.cicd-sa-ro["networking"]
+}
+
+# stage 2 project factory
+
+moved {
+ from = module.branch-pf-gcs
+ to = module.pf-bucket[0]
+}
+moved {
+ from = module.branch-pf-sa
+ to = module.pf-sa-rw[0]
+}
+moved {
+ from = module.branch-pf-r-sa
+ to = module.pf-sa-ro[0]
+}
+moved {
+ from = module.branch-pf-sa-cicd
+ to = module.cicd-sa-rw["project-factory"]
+}
+moved {
+ from = module.branch-pf-r-sa-cicd
+ to = module.cicd-sa-ro["project-factory"]
+}
+
+# stage 2 security
+
+moved {
+ from = module.branch-security-folder
+ to = module.sec-folder[0]
+}
+moved {
+ from = module.branch-security-gcs
+ to = module.sec-bucket[0]
+}
+moved {
+ from = module.branch-security-sa
+ to = module.sec-sa-rw[0]
+}
+moved {
+ from = module.branch-security-r-sa
+ to = module.sec-sa-ro[0]
+}
+moved {
+ from = module.branch-security-sa-cicd["0"]
+ to = module.cicd-sa-rw["security"]
+}
+moved {
+ from = module.branch-security-r-sa-cicd["0"]
+ to = module.cicd-sa-ro["security"]
+}
+
+# project factory dev
+
+moved {
+ from = module.branch-pf-dev-gcs
+ to = module.stage3-bucket["project-factory-dev"]
+}
+moved {
+ from = module.branch-pf-dev-sa
+ to = module.stage3-sa-rw["project-factory-dev"]
+}
+moved {
+ from = module.branch-pf-dev-r-sa
+ to = module.stage3-sa-ro["project-factory-dev"]
+}
+
+# project factory prod
+
+moved {
+ from = module.branch-pf-prod-gcs
+ to = module.stage3-bucket["project-factory-prod"]
+}
+moved {
+ from = module.branch-pf-prod-sa
+ to = module.stage3-sa-rw["project-factory-prod"]
+}
+moved {
+ from = module.branch-pf-prod-r-sa
+ to = module.stage3-sa-ro["project-factory-prod"]
+}
+
+# sandbox
+
+moved {
+ from = module.branch-sandbox-folder[0]
+ to = module.top-level-folder["sandbox"]
+}
+moved {
+ from = module.branch-sandbox-gcs[0]
+ to = module.top-level-bucket["sandbox"]
+}
+moved {
+ from = module.branch-sandbox-sa[0]
+ to = module.top-level-sa["sandbox"]
+}
+
+# stage 3 gke
+
+moved {
+ from = module.branch-gke-folder[0]
+ to = module.top-level-folder["gke"]
+}
+moved {
+ from = module.branch-gke-dev-folder[0]
+ to = module.stage3-folder["gke-dev"]
+}
+moved {
+ from = module.branch-gke-prod-folder[0]
+ to = module.stage3-folder["gke-prod"]
+}
+moved {
+ from = module.branch-gke-dev-gcs[0]
+ to = module.stage3-bucket["gke-dev"]
+}
+moved {
+ from = module.branch-gke-prod-gcs[0]
+ to = module.stage3-bucket["gke-prod"]
+}
+moved {
+ from = module.branch-gke-dev-sa[0]
+ to = module.stage3-sa-rw["gke-dev"]
+}
+moved {
+ from = module.branch-gke-prod-sa[0]
+ to = module.stage3-sa-rw["gke-prod"]
+}
+moved {
+ from = module.branch-gke-dev-r-sa[0]
+ to = module.stage3-sa-ro["gke-dev"]
+}
+moved {
+ from = module.branch-gke-prod-r-sa[0]
+ to = module.stage3-sa-ro["gke-prod"]
+}
+
+# stage 3 gcve
+
+moved {
+ from = module.branch-gcve-folder[0]
+ to = module.top-level-folder["gcve"]
+}
+moved {
+ from = module.branch-gcve-dev-folder[0]
+ to = module.stage3-folder["gcve-dev"]
+}
+moved {
+ from = module.branch-gcve-prod-folder[0]
+ to = module.stage3-folder["gcve-prod"]
+}
+moved {
+ from = module.branch-gcve-dev-gcs[0]
+ to = module.stage3-bucket["gcve-dev"]
+}
+moved {
+ from = module.branch-gcve-prod-gcs[0]
+ to = module.stage3-bucket["gcve-prod"]
+}
+moved {
+ from = module.branch-gcve-dev-sa[0]
+ to = module.stage3-sa-rw["gcve-dev"]
+}
+moved {
+ from = module.branch-gcve-prod-sa[0]
+ to = module.stage3-sa-rw["gcve-prod"]
+}
+moved {
+ from = module.branch-gcve-dev-r-sa[0]
+ to = module.stage3-sa-ro["gcve-dev"]
+}
+moved {
+ from = module.branch-gcve-prod-r-sa[0]
+ to = module.stage3-sa-ro["gcve-prod"]
+}
diff --git a/fast/stages/1-resman/organization.tf b/fast/stages/1-resman/organization.tf
index d6d04d370..b59b2659d 100644
--- a/fast/stages/1-resman/organization.tf
+++ b/fast/stages/1-resman/organization.tf
@@ -17,6 +17,59 @@
# tfdoc:file:description Organization policies.
locals {
+ # context tag values for enabled stage 2s (merged in the final map below)
+ _context_tag_values_stage2 = {
+ for k, v in var.fast_stage_2 :
+ k => replace(k, "_", "-") if v.enabled
+ }
+ # merge all context tag values into a single map
+ context_tag_values = merge(
+ # user-defined
+ try(local.tags["context"]["values"], {}),
+ # top-level folders
+ {
+ for k, v in local.top_level_folders : k => {
+ iam = try(local.tags.context.values.iam[k], {})
+ description = try(local.tags.context.values.description[k], null)
+ } if v.is_fast_context == true
+ },
+ # stage 2s
+ {
+ for k, v in local._context_tag_values_stage2 : v => {
+ iam = try(local.tags.context.values.iam[v], {})
+ description = try(local.tags.context.values.description[v], null)
+ }
+ },
+ # stage 3 define no context as they attach to a top-level folder
+ )
+ # environment tag values and their IAM bindings for stage 2 service accounts
+ environment_tag_values = {
+ for k, v in var.environments : v.tag_name => {
+ iam = merge(
+ # user-defined configuration
+ try(local.tags.environment.values[v.tag_name].iam, {}),
+ # stage 2 service accounts
+ {
+ "roles/resourcemanager.tagUser" = distinct(concat(
+ try(local.tags.environment.values[v.tag_name].iam["roles/resourcemanager.tagUser"], []),
+ !var.fast_stage_2.project_factory.enabled ? [] : [module.pf-sa-rw[0].iam_email],
+ !var.fast_stage_2.networking.enabled ? [] : [module.net-sa-rw[0].iam_email],
+ !var.fast_stage_2.security.enabled ? [] : [module.sec-sa-rw[0].iam_email],
+ ))
+ "roles/resourcemanager.tagViewer" = distinct(concat(
+ try(local.tags.environment.values[v.tag_name].iam["roles/resourcemanager.tagViewer"], []),
+ !var.fast_stage_2.project_factory.enabled ? [] : [module.pf-sa-ro[0].iam_email],
+ !var.fast_stage_2.networking.enabled ? [] : [module.net-sa-ro[0].iam_email],
+ !var.fast_stage_2.security.enabled ? [] : [module.sec-sa-ro[0].iam_email],
+ ))
+ }
+ )
+ description = try(
+ local.tags.environment.values[v].description, null
+ )
+ }
+ }
+ # service account expansion for user-specified tag values
tags = {
for k, v in var.tags : k => merge(v, {
values = {
@@ -40,7 +93,7 @@ module "organization" {
source = "../../../modules/organization"
count = var.root_node == null ? 1 : 0
organization_id = "organizations/${var.organization.id}"
- # additive bindings via delegated IAM grant set in stage 0
+ # additive bindings leveraging the delegated IAM grant set in stage 0
iam_bindings_additive = local.iam_bindings_additive
# do not assign tagViewer or tagUser roles here on tag keys and values as
# they are managed authoritatively and will break multitenant stages
@@ -48,62 +101,12 @@ module "organization" {
(var.tag_names.context) = {
description = "Resource management context."
iam = try(local.tags.context.iam, {})
- values = {
- data = {
- iam = try(local.tags.context.values.data.iam, {})
- description = try(local.tags.context.values.data.description, null)
- }
- gke = {
- iam = try(local.tags.context.values.gke.iam, {})
- description = try(local.tags.context.values.gke.description, null)
- }
- gcve = {
- iam = try(local.tags.context.values.gcve.iam, {})
- description = try(local.tags.context.values.gcve.description, null)
- }
- networking = {
- iam = try(local.tags.context.values.networking.iam, {})
- description = try(local.tags.context.values.networking.description, null)
- }
- project-factory = {
- iam = try(local.tags.context.values.project-factory.iam, {})
- description = try(local.tags.context.values.project-factory.description, null)
- }
- sandbox = {
- iam = try(local.tags.context.values.sandbox.iam, {})
- description = try(local.tags.context.values.sandbox.description, null)
- }
- security = {
- iam = try(local.tags.context.values.security.iam, {})
- description = try(local.tags.context.values.security.description, null)
- }
- }
- }
+ values = local.context_tag_values
+ },
(var.tag_names.environment) = {
description = "Environment definition."
iam = try(local.tags.environment.iam, {})
- values = {
- development = {
- iam = try(local.tags.environment.values.development.iam, {})
- iam_bindings = {
- pf = {
- members = [module.branch-pf-sa.iam_email]
- role = "roles/resourcemanager.tagUser"
- }
- }
- description = try(local.tags.environment.values.development.description, null)
- }
- production = {
- iam = try(local.tags.environment.values.production.iam, {})
- iam_bindings = {
- pf = {
- members = [module.branch-pf-sa.iam_email]
- role = "roles/resourcemanager.tagUser"
- }
- }
- description = try(local.tags.environment.values.production.description, null)
- }
- }
+ values = local.environment_tag_values
}
})
}
diff --git a/fast/stages/1-resman/outputs-files.tf b/fast/stages/1-resman/outputs-files.tf
index f7f080dd9..166b8558a 100644
--- a/fast/stages/1-resman/outputs-files.tf
+++ b/fast/stages/1-resman/outputs-files.tf
@@ -17,7 +17,152 @@
# tfdoc:file:description Output files persistence to local filesystem.
locals {
+ # output file definitions for enabled stage 2s
+ _stage2_outputs_attrs = merge(
+ var.fast_stage_2["networking"].enabled != true ? {} : {
+ networking = {
+ bucket = module.net-bucket[0].name
+ sa = {
+ apply = module.net-sa-rw[0].email
+ plan = module.net-sa-ro[0].email
+ }
+ }
+ },
+ var.fast_stage_2["network_security"].enabled != true ? {} : {
+ network_security = {
+ bucket = module.nsec-bucket[0].name
+ sa = {
+ apply = module.nsec-sa-rw[0].email
+ plan = module.nsec-sa-ro[0].email
+ }
+ }
+ },
+ var.fast_stage_2["project_factory"].enabled != true ? {} : {
+ project_factory = {
+ bucket = module.pf-bucket[0].name
+ sa = {
+ apply = module.pf-sa-rw[0].email
+ plan = module.pf-sa-ro[0].email
+ }
+ }
+ },
+ var.fast_stage_2["security"].enabled != true ? {} : {
+ security = {
+ bucket = module.sec-bucket[0].name
+ sa = {
+ apply = module.sec-sa-rw[0].email
+ plan = module.sec-sa-ro[0].email
+ }
+ }
+ }
+ )
+ # CI/CD workflow definitions for enabled stages
+ _cicd_workflow_attrs = merge(
+ # stage 2s
+ {
+ for k, v in local._stage2_outputs_attrs : k => {
+ audiences = try(
+ local.identity_providers[local.cicd_repositories[k].identity_provider].audiences, null
+ )
+ identity_provider = try(
+ local.identity_providers[local.cicd_repositories[k].identity_provider].name, null
+ )
+ outputs_bucket = var.automation.outputs_bucket
+ service_accounts = {
+ apply = try(module.cicd-sa-rw[k].email, "")
+ plan = try(module.cicd-sa-ro[k].email, "")
+ }
+ repository = local.cicd_repositories[k].repository
+ stage_name = k
+ tf_providers_files = {
+ apply = "2-${replace(k, "_", "-")}-providers.tf"
+ plan = "2-${replace(k, "_", "-")}-r-providers.tf"
+ }
+ tf_var_files = local.cicd_workflow_files.stage_2
+ } if lookup(local.cicd_repositories, k, null) != null
+ },
+ # stage 3
+ {
+ for k, v in local.cicd_repositories : "${v.lvl}-${k}" => {
+ audiences = try(
+ local.identity_providers[v.identity_provider].audiences, null
+ )
+ identity_provider = try(
+ local.identity_providers[v.identity_provider].name, null
+ )
+ outputs_bucket = var.automation.outputs_bucket
+ repository = v.repository
+ service_accounts = {
+ apply = module.cicd-sa-rw[0].email
+ plan = module.cicd-sa-ro[0].email
+ }
+ stage_name = v.short_name
+ tf_providers_files = {
+ apply = "${v.lvl}-${k}-providers.tf"
+ plan = "${v.lvl}-${k}-r-providers.tf"
+ }
+ tf_var_files = local.cicd_workflow_files.stage_3
+ } if v.lvl == 3
+ }
+ )
+ _tpl_providers = "${path.module}/templates/providers.tf.tpl"
+ cicd_workflows = {
+ for k, v in local._cicd_workflow_attrs : k => templatefile(
+ "${path.module}/templates/workflow-${v.repository.type}.yaml", v
+ )
+ }
outputs_location = try(pathexpand(var.outputs_location), "")
+ # render provider files from template
+ providers = merge(
+ # stage 2
+ {
+ for k, v in local._stage2_outputs_attrs :
+ "2-${replace(k, "_", "-")}" => templatefile(local._tpl_providers, {
+ backend_extra = null
+ bucket = v.bucket
+ name = "networking"
+ sa = v.sa.apply
+ })
+ },
+ {
+ for k, v in local._stage2_outputs_attrs :
+ "2-${replace(k, "_", "-")}-r" => templatefile(local._tpl_providers, {
+ backend_extra = null
+ bucket = v.bucket
+ name = "networking"
+ sa = v.sa.plan
+ })
+ },
+ # stage 3
+ {
+ for k, v in local.stage3 :
+ "3-${k}" => templatefile(local._tpl_providers, {
+ backend_extra = null
+ bucket = module.stage3-bucket[k].name
+ name = k
+ sa = module.stage3-sa-rw[k].email
+ })
+ },
+ {
+ for k, v in local.stage3 :
+ "3-${k}-r" => templatefile(local._tpl_providers, {
+ backend_extra = null
+ bucket = module.stage3-bucket[k].name
+ name = k
+ sa = module.stage3-sa-ro[k].email
+ })
+ },
+ # top-level folders
+ {
+ for k, v in module.top-level-sa :
+ "1-resman-folder-${k}" => templatefile(local._tpl_providers, {
+ backend_extra = null
+ bucket = module.top-level-bucket[k].name
+ name = k
+ sa = v.email
+ })
+ },
+ )
}
resource "local_file" "providers" {
@@ -40,3 +185,23 @@ resource "local_file" "workflows" {
filename = "${local.outputs_location}/workflows/${replace(each.key, "_", "-")}-workflow.yaml"
content = try(each.value, null)
}
+
+resource "google_storage_bucket_object" "providers" {
+ for_each = local.providers
+ bucket = var.automation.outputs_bucket
+ name = "providers/${each.key}-providers.tf"
+ content = each.value
+}
+
+resource "google_storage_bucket_object" "tfvars" {
+ bucket = var.automation.outputs_bucket
+ name = "tfvars/1-resman.auto.tfvars.json"
+ content = jsonencode(local.tfvars)
+}
+
+resource "google_storage_bucket_object" "workflows" {
+ for_each = local.cicd_workflows
+ bucket = var.automation.outputs_bucket
+ name = "workflows/${replace(each.key, "_", "-")}-workflow.yaml"
+ content = each.value
+}
diff --git a/fast/stages/1-resman/outputs-gcs.tf b/fast/stages/1-resman/outputs-gcs.tf
deleted file mode 100644
index 5b9f5d851..000000000
--- a/fast/stages/1-resman/outputs-gcs.tf
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * Copyright 2022 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 Output files persistence to automation GCS bucket.
-
-resource "google_storage_bucket_object" "providers" {
- for_each = local.providers
- bucket = var.automation.outputs_bucket
- name = "providers/${each.key}-providers.tf"
- content = each.value
-}
-
-resource "google_storage_bucket_object" "tfvars" {
- bucket = var.automation.outputs_bucket
- name = "tfvars/1-resman.auto.tfvars.json"
- content = jsonencode(local.tfvars)
-}
-
-resource "google_storage_bucket_object" "workflows" {
- for_each = local.cicd_workflows
- bucket = var.automation.outputs_bucket
- name = "workflows/${replace(each.key, "_", "-")}-workflow.yaml"
- content = each.value
-}
diff --git a/fast/stages/1-resman/outputs.tf b/fast/stages/1-resman/outputs.tf
index 863951de7..0c8152371 100644
--- a/fast/stages/1-resman/outputs.tf
+++ b/fast/stages/1-resman/outputs.tf
@@ -15,398 +15,61 @@
*/
locals {
- _tpl_providers_gcs = "${path.module}/templates/providers_gcs.tf.tpl"
- _tpl_providers_terraform = "${path.module}/templates/providers_terraform.tf.tpl"
- cicd_workflow_attrs = {
- data_platform_dev = {
- service_accounts = {
- apply = try(module.branch-dp-dev-sa-cicd[0].email, null)
- plan = try(module.branch-dp-dev-r-sa-cicd[0].email, null)
- }
- tf_providers_files = {
- apply = "3-data-platform-dev-providers.tf"
- plan = "3-data-platform-dev-r-providers.tf"
- }
- tf_var_files = local.cicd_workflow_var_files.stage_3
- }
- data_platform_prod = {
- service_accounts = {
- apply = try(module.branch-dp-prod-sa-cicd[0].email, null)
- plan = try(module.branch-dp-prod-r-sa-cicd[0].email, null)
- }
- tf_providers_files = {
- apply = "3-data-platform-prod-providers.tf"
- plan = "3-data-platform-prod-r-providers.tf"
- }
- tf_var_files = local.cicd_workflow_var_files.stage_3
- }
- gcve_dev = {
- service_accounts = {
- apply = try(module.branch-gcve-dev-sa-cicd[0].email, null)
- plan = try(module.branch-gcve-dev-r-sa-cicd[0].email, null)
- }
- tf_providers_files = {
- apply = "3-gcve-dev-providers.tf"
- plan = "3-gcve-dev-r-providers.tf"
- }
- tf_var_files = local.cicd_workflow_var_files.stage_3
- }
- gcve_prod = {
- service_accounts = {
- apply = try(module.branch-gcve-prod-sa-cicd[0].email, null)
- plan = try(module.branch-gcve-prod-r-sa-cicd[0].email, null)
- }
- tf_providers_files = {
- apply = "3-gcve-prod-providers.tf"
- plan = "3-gcve-prod-r-providers.tf"
- }
- tf_var_files = local.cicd_workflow_var_files.stage_3
- }
- gke_dev = {
- service_accounts = {
- apply = try(module.branch-gke-dev-sa-cicd[0].email, null)
- plan = try(module.branch-gke-dev-r-sa-cicd[0].email, null)
- }
- tf_providers_files = {
- apply = "3-gke-dev-providers.tf"
- plan = "3-gke-dev-r-providers.tf"
- }
- tf_var_files = local.cicd_workflow_var_files.stage_3
- }
- gke_prod = {
- service_accounts = {
- apply = try(module.branch-gke-prod-sa-cicd[0].email, null)
- plan = try(module.branch-gke-prod-r-sa-cicd[0].email, null)
- }
- tf_providers_files = {
- apply = "3-gke-prod-providers.tf"
- plan = "3-gke-prod-r-providers.tf"
- }
- tf_var_files = local.cicd_workflow_var_files.stage_3
- }
- nsec = {
- service_accounts = {
- apply = try(module.branch-nsec-sa-cicd[0].email, null)
- plan = try(module.branch-nsec-r-sa-cicd[0].email, null)
- }
- tf_providers_files = {
- apply = "3-network-security-providers.tf"
- plan = "3-network-security-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)
- plan = try(module.branch-network-r-sa-cicd[0].email, null)
- }
- tf_providers_files = {
- apply = "2-networking-providers.tf"
- plan = "2-networking-r-providers.tf"
- }
- tf_var_files = local.cicd_workflow_var_files.stage_2
- }
- project_factory = {
- service_accounts = {
- apply = try(module.branch-pf-sa-cicd[0].email, null)
- plan = try(module.branch-pf-r-sa-cicd[0].email, null)
- }
- tf_providers_files = {
- apply = "2-project-factory-providers.tf"
- plan = "2-project-factory-r-providers.tf"
- }
- tf_var_files = local.cicd_workflow_var_files.stage_3
- }
- project_factory_dev = {
- service_accounts = {
- apply = try(module.branch-pf-dev-sa-cicd[0].email, null)
- plan = try(module.branch-pf-dev-r-sa-cicd[0].email, null)
- }
- tf_providers_files = {
- apply = "2-project-factory-dev-providers.tf"
- plan = "2-project-factory-dev-r-providers.tf"
- }
- tf_var_files = local.cicd_workflow_var_files.stage_3
- }
- project_factory_prod = {
- service_accounts = {
- apply = try(module.branch-pf-prod-sa-cicd[0].email, null)
- plan = try(module.branch-pf-prod-r-sa-cicd[0].email, null)
- }
- tf_providers_files = {
- apply = "2-project-factory-prod-providers.tf"
- plan = "2-project-factory-prod-r-providers.tf"
- }
- tf_var_files = local.cicd_workflow_var_files.stage_3
- }
- security = {
- service_accounts = {
- apply = try(module.branch-security-sa-cicd[0].email, null)
- plan = try(module.branch-security-r-sa-cicd[0].email, null)
- }
- tf_providers_files = {
- apply = "2-security-providers.tf"
- plan = "2-security-r-providers.tf"
- }
- tf_var_files = local.cicd_workflow_var_files.stage_2
- }
- }
- cicd_workflows = {
- for k, v in local.cicd_repositories : k => templatefile(
- "${path.module}/templates/workflow-${v.type}.yaml",
- merge(local.cicd_workflow_attrs[k], {
- audiences = try(
- local.identity_providers[v.identity_provider].audiences, null
- )
- identity_provider = try(
- local.identity_providers[v.identity_provider].name, null
- )
- outputs_bucket = var.automation.outputs_bucket
- stage_name = k
- })
- )
- if v.type != "terraform"
- }
folder_ids = merge(
- {
- data-platform-dev = try(module.branch-dp-dev-folder[0].id, null)
- data-platform-prod = try(module.branch-dp-prod-folder[0].id, null)
- gcve-dev = try(module.branch-gcve-dev-folder[0].id, null)
- gcve-prod = try(module.branch-gcve-prod-folder[0].id, null)
- gke-dev = try(module.branch-gke-dev-folder[0].id, null)
- gke-prod = try(module.branch-gke-prod-folder[0].id, null)
- networking = try(module.branch-network-folder.id, null)
- networking-dev = try(module.branch-network-dev-folder.id, null)
- networking-prod = try(module.branch-network-prod-folder.id, null)
- sandbox = try(module.branch-sandbox-folder[0].id, null)
- security = try(module.branch-security-folder.id, null)
+ # stage 2
+ !var.fast_stage_2.networking.enabled ? {} : {
+ networking = module.net-folder[0].id
+ networking-dev = try(module.net-folder-dev[0].id, null)
+ networking-prod = try(module.net-folder-prod[0].id, null)
},
- {
- for k, v in module.top-level-folder : k => try(v.id, null)
- }
+ !var.fast_stage_2.security.enabled ? {} : {
+ security = module.sec-folder[0].id
+ security-dev = try(module.sec-folder-dev[0].id, null)
+ security-prod = try(module.sec-folder-prod[0].id, null)
+ },
+ # stage 3
+ { for k, v in module.stage3-folder : k => v.id },
+ # top-level folders
+ local.top_level_folder_ids
)
- _providers = merge(
- {
- "2-networking" = {
- backend_extra = null
- bucket = module.branch-network-gcs.name
- name = "networking"
- sa = module.branch-network-sa.email
- }
- "2-networking-r" = {
- backend_extra = null
- bucket = module.branch-network-gcs.name
- name = "networking"
- sa = module.branch-network-r-sa.email
- }
- "2-project-factory" = {
- backend_extra = null
- bucket = module.branch-pf-gcs.name
- name = "project-factory"
- sa = module.branch-pf-sa.email
- }
- "2-project-factory-r" = {
- backend_extra = null
- bucket = module.branch-pf-gcs.name
- name = "project-factory"
- sa = module.branch-pf-r-sa.email
- }
- "2-project-factory-dev" = {
- backend_extra = null
- bucket = module.branch-pf-dev-gcs.name
- name = "project-factory-dev"
- sa = module.branch-pf-dev-sa.email
- }
- "2-project-factory-dev-r" = {
- backend_extra = null
- bucket = module.branch-pf-dev-gcs.name
- name = "project-factory-dev"
- sa = module.branch-pf-dev-r-sa.email
- }
- "2-project-factory-prod" = {
- backend_extra = null
- bucket = module.branch-pf-prod-gcs.name
- name = "project-factory-prod"
- sa = module.branch-pf-prod-sa.email
- }
- "2-project-factory-prod-r" = {
- backend_extra = null
- bucket = module.branch-pf-prod-gcs.name
- name = "project-factory-prod"
- sa = module.branch-pf-prod-r-sa.email
- }
- "2-security" = {
- backend_extra = null
- bucket = module.branch-security-gcs.name
- name = "security"
- sa = module.branch-security-sa.email
- }
- "2-security-r" = {
- backend_extra = null
- bucket = module.branch-security-gcs.name
- name = "security"
- sa = module.branch-security-r-sa.email
- }
- },
- {
- for k, v in module.top-level-sa :
- "1-resman-folder-${k}" => {
- backend_extra = null
- bucket = module.top-level-bucket[k].name
- name = k
- sa = v.email
- }
- },
- !var.fast_features.data_platform ? {} : {
- "3-data-platform-dev" = {
- backend_extra = null
- bucket = module.branch-dp-dev-gcs[0].name
- name = "dp-dev"
- sa = module.branch-dp-dev-sa[0].email
- }
- "3-data-platform-dev-r" = {
- backend_extra = null
- bucket = module.branch-dp-dev-gcs[0].name
- name = "dp-dev"
- sa = module.branch-dp-dev-r-sa[0].email
- }
- "3-data-platform-prod" = {
- backend_extra = null
- bucket = module.branch-dp-prod-gcs[0].name
- name = "dp-prod"
- sa = module.branch-dp-prod-sa[0].email
- }
- "3-data-platform-prod-r" = {
- backend_extra = null
- bucket = module.branch-dp-prod-gcs[0].name
- name = "dp-prod"
- sa = module.branch-dp-prod-r-sa[0].email
- }
- },
- !var.fast_features.gke ? {} : {
- "3-gke-dev" = {
- backend_extra = null
- bucket = module.branch-gke-dev-gcs[0].name
- name = "gke-dev"
- sa = module.branch-gke-dev-sa[0].email
- }
- "3-gke-dev-r" = {
- backend_extra = null
- bucket = module.branch-gke-dev-gcs[0].name
- name = "gke-dev"
- sa = module.branch-gke-dev-r-sa[0].email
- }
- "3-gke-prod" = {
- backend_extra = null
- bucket = module.branch-gke-prod-gcs[0].name
- name = "gke-prod"
- sa = module.branch-gke-prod-sa[0].email
- }
- "3-gke-prod-r" = {
- backend_extra = null
- bucket = module.branch-gke-prod-gcs[0].name
- name = "gke-prod"
- sa = module.branch-gke-prod-r-sa[0].email
- }
- },
- !var.fast_features.gcve ? {} : {
- "3-gcve-dev" = {
- backend_extra = null
- bucket = module.branch-gcve-dev-gcs[0].name
- name = "gcve-dev"
- sa = module.branch-gcve-dev-sa[0].email
- }
- "3-gcve-dev-r" = {
- backend_extra = null
- bucket = module.branch-gcve-dev-gcs[0].name
- name = "gcve-dev"
- sa = module.branch-gcve-dev-r-sa[0].email
- }
- "3-gcve-prod" = {
- backend_extra = null
- bucket = module.branch-gcve-prod-gcs[0].name
- name = "gcve-prod"
- sa = module.branch-gcve-prod-sa[0].email
- }
- "3-gcve-prod-r" = {
- backend_extra = null
- bucket = module.branch-gcve-prod-gcs[0].name
- name = "gcve-prod"
- sa = module.branch-gcve-prod-r-sa[0].email
- }
- },
- !var.fast_features.nsec ? {} : {
- "3-network-security" = {
- backend_extra = null
- bucket = module.branch-nsec-gcs[0].name
- name = "network-security"
- sa = module.branch-nsec-sa[0].email
- }
- "3-network-security-r" = {
- backend_extra = null
- bucket = module.branch-nsec-gcs[0].name
- name = "network-security"
- sa = module.branch-nsec-r-sa[0].email
- }
- },
- !var.fast_features.sandbox ? {} : {
- "9-sandbox" = {
- backend_extra = null
- bucket = module.branch-sandbox-gcs[0].name
- name = "sandbox"
- sa = module.branch-sandbox-sa[0].email
- }
- },
- )
- providers = {
- for k, v in local._providers : k => (
- var.automation.cicd_backends != null && try(var.automation.cicd_backends.terraform, null) != null ?
- templatefile(
- local._tpl_providers_terraform,
- merge(
- {
- name = v.name,
- sa = v.sa
- },
- {
- workspaces = lookup(
- var.automation.cicd_backends.terraform.workspaces,
- v.name,
- {
- tags = null,
- name = null,
- project = null
- }
- )
- },
- {
- organization = var.automation.cicd_backends.terraform.organization,
- hostname = var.automation.cicd_backends.terraform.hostname
- }
- )
- ) :
- templatefile(local._tpl_providers_gcs, {
- name = v.name,
- sa = v.sa,
- bucket = v.bucket,
- backend_extra = v.backend_extra
- })
- )
- }
service_accounts = merge(
- local.branch_service_accounts,
- {
- for k, v in module.top-level-sa : k => try(v.email)
- }
+ local.stage_service_accounts,
+ local.top_level_service_accounts
)
tfvars = {
- checklist_hierarchy = local.checklist.hierarchy
- fast_features = var.fast_features
- folder_ids = local.folder_ids
- service_accounts = local.service_accounts
- tag_keys = { for k, v in try(local.tag_keys, {}) : k => v.id }
- tag_names = var.tag_names
- tag_values = { for k, v in try(local.tag_values, {}) : k => v.id }
+ stage_config = merge(
+ {
+ for k, v in local.stage3 : k => {
+ environment = v.environment
+ short_name = v.short_name
+ }
+ },
+ {
+ for k, v in var.fast_stage_2 : k => {
+ short_name = v.short_name
+ # rw service accounts for stage 3s that need delegated IAM on stage 2s
+ iam_delegated_principals = {
+ for ek, _ in var.environments : ek => [
+ for sk, sv in local.stage3 :
+ "serviceAccount:${local.stage_service_accounts[sk]}"
+ if sv.environment == ek && try(sv.stage2_iam[k].iam_admin_delegated, false)
+ ]
+ }
+ iam_viewer_principals = {
+ for ek, _ in var.environments : ek => [
+ for sk, sv in local.stage3 :
+ "serviceAccount:${local.stage_service_accounts["${sk}-r"]}"
+ if sv.environment == ek && try(sv.stage2_iam[k].iam_admin_delegated, false)
+ ]
+ }
+ } if v.enabled == true
+ }
+ )
+ folder_ids = local.folder_ids
+ service_accounts = local.service_accounts
+ tag_keys = { for k, v in try(local.tag_keys, {}) : k => v.id }
+ tag_names = var.tag_names
+ tag_values = { for k, v in try(local.tag_values, {}) : k => v.id }
}
}
@@ -414,28 +77,10 @@ output "cicd_repositories" {
description = "WIF configuration for CI/CD repositories."
value = {
for k, v in local.cicd_repositories : k => {
- branch = v.branch
- name = v.name
+ repository = v.repository
provider = try(
local.identity_providers[v.identity_provider].name, null
)
- service_account = local.cicd_workflow_attrs[k].service_accounts
- } if v != null
- }
-}
-
-output "dataplatform" {
- description = "Data for the Data Platform stage."
- value = !var.fast_features.data_platform ? {} : {
- dev = {
- folder = module.branch-dp-dev-folder[0].id
- gcs_bucket = module.branch-dp-dev-gcs[0].name
- service_account = module.branch-dp-dev-sa[0].email
- }
- prod = {
- folder = module.branch-dp-prod-folder[0].id
- gcs_bucket = module.branch-dp-prod-gcs[0].name
- service_account = module.branch-dp-prod-sa[0].email
}
}
}
@@ -445,107 +90,13 @@ output "folder_ids" {
value = local.folder_ids
}
-output "gcve" {
- # tfdoc:output:consumers 03-gcve
- description = "Data for the GCVE stage."
- value = (
- var.fast_features.gcve
- ? {
- "dev" = {
- folder = module.branch-gcve-dev-folder[0].id
- gcs_bucket = module.branch-gcve-dev-gcs[0].name
- service_account = module.branch-gcve-dev-sa[0].email
- }
- "prod" = {
- folder = module.branch-gcve-prod-folder[0].id
- gcs_bucket = module.branch-gcve-prod-gcs[0].name
- service_account = module.branch-gcve-prod-sa[0].email
- }
- }
- : {}
- )
-}
-
-output "gke_multitenant" {
- # tfdoc:output:consumers 03-gke-multitenant
- description = "Data for the GKE multitenant stage."
- value = (
- var.fast_features.gke
- ? {
- "dev" = {
- folder = module.branch-gke-dev-folder[0].id
- gcs_bucket = module.branch-gke-dev-gcs[0].name
- service_account = module.branch-gke-dev-sa[0].email
- }
- "prod" = {
- folder = module.branch-gke-prod-folder[0].id
- gcs_bucket = module.branch-gke-prod-gcs[0].name
- service_account = module.branch-gke-prod-sa[0].email
- }
- }
- : {}
- )
-}
-
-output "networking" {
- description = "Data for the networking stage."
- value = {
- folder = module.branch-network-folder.id
- gcs_bucket = module.branch-network-gcs.name
- service_account = module.branch-network-sa.iam_email
- }
-}
-
-output "project_factories" {
- description = "Data for the project factories stage."
- value = {
- dev = {
- bucket = module.branch-pf-dev-gcs.name
- sa = module.branch-pf-dev-sa.email
- }
- main = {
- bucket = module.branch-pf-gcs.name
- sa = module.branch-pf-sa.email
- }
- prod = {
- bucket = module.branch-pf-prod-gcs.name
- sa = module.branch-pf-prod-sa.email
- }
- }
-}
-
# ready to use provider configurations for subsequent stages
output "providers" {
- # tfdoc:output:consumers 02-networking 02-security 03-dataplatform 03-network-security
description = "Terraform provider files for this stage and dependent stages."
sensitive = true
value = local.providers
}
-output "sandbox" {
- # tfdoc:output:consumers xx-sandbox
- description = "Data for the sandbox stage."
- value = (
- var.fast_features.sandbox
- ? {
- folder = module.branch-sandbox-folder[0].id
- gcs_bucket = module.branch-sandbox-gcs[0].name
- service_account = module.branch-sandbox-sa[0].email
- }
- : null
- )
-}
-
-output "security" {
- # tfdoc:output:consumers 02-security
- description = "Data for the networking stage."
- value = {
- folder = module.branch-security-folder.id
- gcs_bucket = module.branch-security-gcs.name
- service_account = module.branch-security-sa.iam_email
- }
-}
-
# ready to use variable values for subsequent stages
output "tfvars" {
description = "Terraform variable files for the following stages."
diff --git a/fast/stages/1-resman/schemas/fast-stage3.schema.json b/fast/stages/1-resman/schemas/fast-stage3.schema.json
new file mode 100644
index 000000000..80bbad749
--- /dev/null
+++ b/fast/stages/1-resman/schemas/fast-stage3.schema.json
@@ -0,0 +1,152 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "FAST stage 3",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "short_name",
+ "environment"
+ ],
+ "properties": {
+ "short_name": {
+ "type": "string"
+ },
+ "environment": {
+ "enum": [
+ "dev",
+ "prod"
+ ]
+ },
+ "cicd_config": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "identity_provider",
+ "repository"
+ ],
+ "properties": {
+ "identity_provider": {
+ "type": "string"
+ },
+ "repository": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "branch": {
+ "type": "string"
+ },
+ "type": {
+ "enum": [
+ "github",
+ "gitlab"
+ ],
+ "default": "github"
+ }
+ }
+ }
+ }
+ },
+ "folder_config": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "iam_by_principals": {
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^(?:domain:|group:|serviceAccount:|user:|principal:|principalSet:)": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "pattern": "^(?:roles/|[a-z_]+)"
+ }
+ }
+ }
+ },
+ "parent_id": {
+ "type": "string"
+ },
+ "tag_bindings": {
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^[a-z0-9_-]+$": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "organization_iam": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "context_tag_value"
+ ],
+ "properties": {
+ "context_tag_value": {
+ "type": "string"
+ },
+ "sa_roles": {
+ "$ref": "#/$defs/sa_roles"
+ }
+ }
+ },
+ "stage2_iam": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "networking": {
+ "$ref": "#/$defs/stage2_iam"
+ },
+ "security": {
+ "$ref": "#/$defs/stage2_iam"
+ }
+ }
+ }
+ },
+ "$defs": {
+ "sa_roles": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "ro": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "rw": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "stage2_iam": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "iam_admin_delegated": {
+ "type": "boolean"
+ },
+ "sa_roles": {
+ "$ref": "#/$defs/sa_roles"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/fast/stages/1-resman/schemas/top-level-folder.schema.json b/fast/stages/1-resman/schemas/top-level-folder.schema.json
index 60e22c8ae..de27fa8dc 100644
--- a/fast/stages/1-resman/schemas/top-level-folder.schema.json
+++ b/fast/stages/1-resman/schemas/top-level-folder.schema.json
@@ -8,14 +8,55 @@
"type": "object",
"additionalProperties": false,
"properties": {
- "enable": {
- "type": "boolean"
+ "environment_name": {
+ "type": "string"
},
"sa_impersonation_principals": {
"type": "array",
"items": {
"type": "string"
}
+ },
+ "short_name": {
+ "type": "string"
+ }
+ }
+ },
+ "contacts": {
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "@": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "pattern": "^(?:ALL|SUSPENSION|SECURITY|TECHNICAL|BILLING|LEGAL|PRODUCT_UPDATES)$"
+ }
+ }
+ }
+ },
+ "factories_config": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "org_policies": {
+ "type": "string"
+ }
+ }
+ },
+ "firewall_policy": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "name",
+ "policy"
+ ],
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "policy": {
+ "type": "string"
}
}
},
@@ -31,6 +72,90 @@
"iam_by_principals": {
"$ref": "#/$defs/iam_by_principals"
},
+ "is_fast_context": {
+ "type": "boolean",
+ "default": true
+ },
+ "logging_data_access": {
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^(?:[a-z_-]+)\\.googleapis\\.com$": {
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^(?:DATA_READ|DATA_WRITE|ADMIN_READ)$": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "pattern": "@"
+ }
+ }
+ }
+ }
+ }
+ },
+ "logging_exclusions": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "logging_settings": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "disable_default_sink": {
+ "type": "boolean"
+ },
+ "storage_location": {
+ "type": "string"
+ }
+ }
+ },
+ "logging_sinks": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "destination",
+ "type"
+ ],
+ "properties": {
+ "bq_partitioned_table": {
+ "type": "boolean"
+ },
+ "description": {
+ "type": "string"
+ },
+ "destination": {
+ "type": "string"
+ },
+ "disabled": {
+ "type": "boolean"
+ },
+ "exclusions": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "filter": {
+ "type": "string"
+ },
+ "iam": {
+ "type": "boolean"
+ },
+ "include_children": {
+ "type": "boolean"
+ },
+ "type": {
+ "type": "string"
+ }
+ }
+ }
+ },
"name": {
"type": "string"
},
@@ -108,7 +233,7 @@
}
}
},
- "parent": {
+ "parent_id": {
"type": "string"
},
"tag_bindings": {
@@ -230,4 +355,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/fast/stages/1-resman/branch-nsec.tf b/fast/stages/1-resman/stage-2-network-security.tf
similarity index 52%
rename from fast/stages/1-resman/branch-nsec.tf
rename to fast/stages/1-resman/stage-2-network-security.tf
index 08dd2a7c8..e0679a545 100644
--- a/fast/stages/1-resman/branch-nsec.tf
+++ b/fast/stages/1-resman/stage-2-network-security.tf
@@ -14,38 +14,18 @@
* limitations under the License.
*/
-# tfdoc:file:description Network security stage resources.
+# automation service accounts
-# TODO: remove in v35.0.0
-
-moved {
- from = module.branch-nsec-sa
- to = module.branch-nsec-sa[0]
-}
-
-moved {
- from = module.branch-nsec-r-sa
- to = module.branch-nsec-r-sa[0]
-}
-
-moved {
- from = module.branch-nsec-gcs
- to = module.branch-nsec-gcs[0]
-}
-
-# automation service account
-
-module "branch-nsec-sa" {
- source = "../../../modules/iam-service-account"
- count = var.fast_features.nsec ? 1 : 0
- project_id = var.automation.project_id
- name = "prod-resman-nsec-0"
- display_name = "Terraform resman network security service account."
- prefix = var.prefix
- service_account_create = var.root_node == null
+module "nsec-sa-rw" {
+ source = "../../../modules/iam-service-account"
+ count = var.fast_stage_2.network_security.enabled ? 1 : 0
+ project_id = var.automation.project_id
+ name = "resman-${var.fast_stage_2.network_security.short_name}-0"
+ display_name = "Terraform resman network security main service account."
+ prefix = var.prefix
iam = {
"roles/iam.serviceAccountTokenCreator" = compact([
- try(module.branch-nsec-sa-cicd[0].iam_email, null)
+ try(module.cicd-sa-rw["network_security"].iam_email, null)
])
}
iam_project_roles = {
@@ -56,18 +36,16 @@ module "branch-nsec-sa" {
}
}
-# automation read-only service account
-
-module "branch-nsec-r-sa" {
+module "nsec-sa-ro" {
source = "../../../modules/iam-service-account"
- count = var.fast_features.nsec ? 1 : 0
+ count = var.fast_stage_2.network_security.enabled ? 1 : 0
project_id = var.automation.project_id
- name = "prod-resman-nsec-0r"
- display_name = "Terraform resman network security service account (read-only)."
+ name = "resman-${var.fast_stage_2.network_security.short_name}-0r"
+ display_name = "Terraform resman network security main service account (read-only)."
prefix = var.prefix
iam = {
"roles/iam.serviceAccountTokenCreator" = compact([
- try(module.branch-nsec-r-sa-cicd[0].iam_email, null)
+ try(module.cicd-sa-ro["network_security"].iam_email, null)
])
}
iam_project_roles = {
@@ -80,16 +58,16 @@ module "branch-nsec-r-sa" {
# automation bucket
-module "branch-nsec-gcs" {
+module "nsec-bucket" {
source = "../../../modules/gcs"
- count = var.fast_features.nsec ? 1 : 0
+ count = var.fast_stage_2.network_security.enabled ? 1 : 0
project_id = var.automation.project_id
- name = "prod-resman-nsec-0"
+ name = "resman-${var.fast_stage_2.network_security.short_name}-0"
prefix = var.prefix
location = var.locations.gcs
versioning = true
iam = {
- "roles/storage.objectAdmin" = [module.branch-nsec-sa[0].iam_email]
- "roles/storage.objectViewer" = [module.branch-nsec-r-sa[0].iam_email]
+ "roles/storage.objectAdmin" = [module.nsec-sa-rw[0].iam_email]
+ "roles/storage.objectViewer" = [module.nsec-sa-ro[0].iam_email]
}
}
diff --git a/fast/stages/1-resman/stage-2-networking.tf b/fast/stages/1-resman/stage-2-networking.tf
new file mode 100644
index 000000000..0abcf0e35
--- /dev/null
+++ b/fast/stages/1-resman/stage-2-networking.tf
@@ -0,0 +1,229 @@
+/**
+ * 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.
+ */
+
+locals {
+ # normalize IAM bindings for stage 3 service accounts
+ net_s3_iam = !var.fast_stage_2.networking.enabled ? {} : {
+ for v in local.stage3_iam_in_stage2 : "${v.role}:${v.env}" => (
+ v.sa == "rw"
+ ? module.stage3-sa-rw[v.s3].iam_email
+ : module.stage3-sa-ro[v.s3].iam_email
+ )...
+ if v.s2 == "networking"
+ }
+ net_use_env_folders = (
+ var.fast_stage_2.networking.enabled &&
+ var.fast_stage_2.networking.folder_config.create_env_folders
+ )
+}
+
+# top-level folder
+
+module "net-folder" {
+ source = "../../../modules/folder"
+ count = var.fast_stage_2.networking.enabled ? 1 : 0
+ parent = (
+ var.fast_stage_2.networking.folder_config.parent_id == null
+ ? local.root_node
+ : try(
+ local.top_level_folder_ids[var.fast_stage_2.networking.folder_config],
+ var.fast_stage_2.networking.folder_config.parent_id
+ )
+ )
+ name = var.fast_stage_2.networking.folder_config.name
+ iam = merge(
+ # stage own service accounts
+ {
+ "roles/logging.admin" = [module.net-sa-rw[0].iam_email]
+ "roles/owner" = [module.net-sa-rw[0].iam_email]
+ "roles/resourcemanager.folderAdmin" = [module.net-sa-rw[0].iam_email]
+ "roles/resourcemanager.projectCreator" = [module.net-sa-rw[0].iam_email]
+ "roles/compute.xpnAdmin" = [module.net-sa-rw[0].iam_email]
+ "roles/resourcemanager.tagUser" = [module.net-sa-rw[0].iam_email]
+ "roles/viewer" = [module.net-sa-ro[0].iam_email]
+ "roles/resourcemanager.folderViewer" = [module.net-sa-ro[0].iam_email]
+ "roles/resourcemanager.tagViewer" = [module.net-sa-ro[0].iam_email]
+ },
+ # network security stage 2 service accounts
+ var.fast_stage_2.network_security.enabled != true ? {} : {
+ "roles/serviceusage.serviceUsageAdmin" = [
+ module.nsec-sa-rw[0].iam_email
+ ]
+ (var.custom_roles["network_firewall_policies_admin"]) = [
+ module.nsec-sa-rw[0].iam_email
+ ]
+ "roles/compute.orgFirewallPolicyUser" = [
+ module.nsec-sa-ro[0].iam_email
+ ]
+ "roles/serviceusage.serviceUsageConsumer" = [
+ module.nsec-sa-ro[0].iam_email
+ ]
+ },
+ # security stage 2 service accounts
+ var.fast_stage_2.security.enabled != true ? {} : {
+ "roles/serviceusage.serviceUsageAdmin" = [
+ module.sec-sa-rw[0].iam_email
+ ]
+ "roles/serviceusage.serviceUsageConsumer" = [
+ module.sec-sa-ro[0].iam_email
+ ]
+ },
+ # project factory service accounts
+ (var.fast_stage_2.project_factory.enabled) != true ? {} : {
+ (var.custom_roles.service_project_network_admin) = [
+ module.pf-sa-rw[0].iam_email
+ ]
+ (var.custom_roles.project_iam_viewer) = [
+ module.pf-sa-ro[0].iam_email
+ ]
+ "roles/compute.networkViewer" = [
+ module.pf-sa-ro[0].iam_email
+ ]
+ }
+ )
+ iam_bindings = merge(
+ # project factory delegated grant
+ var.fast_stage_2.project_factory.enabled != true ? {} : {
+ pf_delegated_grant = {
+ role = "roles/resourcemanager.projectIamAdmin"
+ members = [module.pf-sa-rw[0].iam_email]
+ condition = {
+ expression = format(
+ "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])",
+ "'roles/compute.networkUser', 'roles/composer.sharedVpcAgent', 'roles/container.hostServiceAgentUser', 'roles/vpcaccess.user'"
+ )
+ title = "project factory project delegated admin"
+ description = "Project factory delegated grant."
+ }
+ }
+ },
+ # stage 3 roles
+ {
+ for k, v in local.net_s3_iam : k => {
+ role = lookup(var.custom_roles, split(":", k)[0], split(":", k)[0])
+ members = v
+ condition = {
+ title = "stage 3 ${split(":", k)[1]}"
+ expression = <<-END
+ resource.matchTag(
+ '${local.tag_root}/${var.tag_names.environment}',
+ '${split(":", k)[1]}'
+ )
+ END
+ }
+ }
+ }
+ )
+ iam_by_principals = merge(
+ {
+ # replace with more selective custom roles for production deployments
+ (local.principals.gcp-network-admins) = ["roles/editor"]
+ },
+ var.fast_stage_2.networking.folder_config.iam_by_principals
+ )
+ tag_bindings = {
+ context = try(
+ local.tag_values["${var.tag_names.context}/networking"].id, null
+ )
+ }
+}
+
+# optional per-environment folders
+
+module "net-folder-prod" {
+ source = "../../../modules/folder"
+ count = local.net_use_env_folders ? 1 : 0
+ parent = module.net-folder[0].id
+ name = var.environments["prod"].name
+ tag_bindings = {
+ environment = try(
+ local.tag_values["${var.tag_names.environment}/${var.environments["prod"].tag_name}"].id,
+ null
+ )
+ }
+}
+
+module "net-folder-dev" {
+ source = "../../../modules/folder"
+ count = local.net_use_env_folders ? 1 : 0
+ parent = module.net-folder[0].id
+ name = var.environments["dev"].name
+ tag_bindings = {
+ environment = try(
+ local.tag_values["${var.tag_names.environment}/${var.environments["dev"].tag_name}"].id,
+ null
+ )
+ }
+}
+
+# automation service accounts
+
+module "net-sa-rw" {
+ source = "../../../modules/iam-service-account"
+ count = var.fast_stage_2.networking.enabled ? 1 : 0
+ project_id = var.automation.project_id
+ name = "prod-resman-${var.fast_stage_2.networking.short_name}-0"
+ display_name = "Terraform resman networking service account."
+ prefix = var.prefix
+ service_account_create = var.root_node == null
+ iam = {
+ "roles/iam.serviceAccountTokenCreator" = compact([
+ try(module.cicd-sa-rw["networking"].iam_email, null)
+ ])
+ }
+ iam_project_roles = {
+ (var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"]
+ }
+ iam_storage_roles = {
+ (var.automation.outputs_bucket) = ["roles/storage.objectAdmin"]
+ }
+}
+
+module "net-sa-ro" {
+ source = "../../../modules/iam-service-account"
+ count = var.fast_stage_2.networking.enabled ? 1 : 0
+ project_id = var.automation.project_id
+ name = "prod-resman-${var.fast_stage_2.networking.short_name}-0r"
+ display_name = "Terraform resman networking service account (read-only)."
+ prefix = var.prefix
+ iam = {
+ "roles/iam.serviceAccountTokenCreator" = compact([
+ try(module.cicd-sa-ro["networking"].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 "net-bucket" {
+ source = "../../../modules/gcs"
+ count = var.fast_stage_2.networking.enabled ? 1 : 0
+ project_id = var.automation.project_id
+ name = "prod-resman-${var.fast_stage_2.networking.short_name}-0"
+ prefix = var.prefix
+ location = var.locations.gcs
+ versioning = true
+ iam = {
+ "roles/storage.objectAdmin" = [module.net-sa-rw[0].iam_email]
+ "roles/storage.objectViewer" = [module.net-sa-ro[0].iam_email]
+ }
+}
diff --git a/fast/stages/1-resman/stage-2-project-factory.tf b/fast/stages/1-resman/stage-2-project-factory.tf
new file mode 100644
index 000000000..f001c3cd0
--- /dev/null
+++ b/fast/stages/1-resman/stage-2-project-factory.tf
@@ -0,0 +1,73 @@
+/**
+ * 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.
+ */
+
+# automation service accounts
+
+module "pf-sa-rw" {
+ source = "../../../modules/iam-service-account"
+ count = var.fast_stage_2.project_factory.enabled ? 1 : 0
+ project_id = var.automation.project_id
+ name = "resman-${var.fast_stage_2.project_factory.short_name}-0"
+ display_name = "Terraform resman project factory main service account."
+ prefix = var.prefix
+ iam = {
+ "roles/iam.serviceAccountTokenCreator" = compact([
+ try(module.cicd-sa-rw["project_factory"].iam_email, null)
+ ])
+ }
+ iam_project_roles = {
+ (var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"]
+ }
+ iam_storage_roles = {
+ (var.automation.outputs_bucket) = ["roles/storage.objectAdmin"]
+ }
+}
+
+module "pf-sa-ro" {
+ source = "../../../modules/iam-service-account"
+ count = var.fast_stage_2.project_factory.enabled ? 1 : 0
+ project_id = var.automation.project_id
+ name = "resman-${var.fast_stage_2.project_factory.short_name}-0r"
+ display_name = "Terraform resman project factory main service account (read-only)."
+ prefix = var.prefix
+ iam = {
+ "roles/iam.serviceAccountTokenCreator" = compact([
+ try(module.cicd-sa-ro["project_factory"].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 "pf-bucket" {
+ source = "../../../modules/gcs"
+ count = var.fast_stage_2.project_factory.enabled ? 1 : 0
+ project_id = var.automation.project_id
+ name = "resman-${var.fast_stage_2.project_factory.short_name}-0"
+ prefix = var.prefix
+ location = var.locations.gcs
+ versioning = true
+ iam = {
+ "roles/storage.objectAdmin" = [module.pf-sa-rw[0].iam_email]
+ "roles/storage.objectViewer" = [module.pf-sa-ro[0].iam_email]
+ }
+}
diff --git a/fast/stages/1-resman/stage-2-security.tf b/fast/stages/1-resman/stage-2-security.tf
new file mode 100644
index 000000000..980295114
--- /dev/null
+++ b/fast/stages/1-resman/stage-2-security.tf
@@ -0,0 +1,222 @@
+/**
+ * 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.
+ */
+
+locals {
+ sec_use_env_folders = (
+ var.fast_stage_2.security.enabled &&
+ var.fast_stage_2.security.folder_config.create_env_folders
+ )
+ sec_s3_iam = !var.fast_stage_2.security.enabled ? {} : {
+ for v in local.stage3_iam_in_stage2 : "${v.role}:${v.env}" => (
+ v.sa == "rw"
+ ? module.stage3-sa-rw[v.s3].iam_email
+ : module.stage3-sa-ro[v.s3].iam_email
+ )...
+ if v.s2 == "security"
+ }
+}
+
+# top-level folder
+
+module "sec-folder" {
+ source = "../../../modules/folder"
+ count = var.fast_stage_2.security.enabled ? 1 : 0
+ parent = (
+ var.fast_stage_2.security.folder_config.parent_id == null
+ ? local.root_node
+ : try(
+ local.top_level_folder_ids[var.fast_stage_2.security.folder_config],
+ var.fast_stage_2.security.folder_config.parent_id
+ )
+ )
+ name = var.fast_stage_2.security.folder_config.name
+ iam = merge(
+ # stage own service accounts
+ {
+ "roles/logging.admin" = [module.sec-sa-rw[0].iam_email]
+ "roles/owner" = [module.sec-sa-rw[0].iam_email]
+ "roles/resourcemanager.folderAdmin" = [module.sec-sa-rw[0].iam_email]
+ "roles/resourcemanager.projectCreator" = [module.sec-sa-rw[0].iam_email]
+ "roles/resourcemanager.tagUser" = [module.net-sa-rw[0].iam_email]
+ "roles/viewer" = [module.sec-sa-ro[0].iam_email]
+ "roles/resourcemanager.folderViewer" = [module.sec-sa-ro[0].iam_email]
+ "roles/resourcemanager.tagViewer" = [module.net-sa-ro[0].iam_email]
+ },
+ # project factory service accounts
+ (var.fast_stage_2.project_factory.enabled) != true ? {} : {
+ "roles/cloudkms.cryptoKeyEncrypterDecrypter" = [
+ module.pf-sa-rw[0].iam_email
+ ]
+ (var.custom_roles.project_iam_viewer) = [
+ module.pf-sa-ro[0].iam_email
+ ]
+ "roles/cloudkms.viewer" = [
+ module.pf-sa-ro[0].iam_email
+ ]
+ }
+ )
+ iam_bindings = merge(
+ var.fast_stage_2.project_factory.enabled != true ? {} : {
+ pf_delegated_grant = {
+ role = "roles/resourcemanager.projectIamAdmin"
+ members = [module.pf-sa-rw[0].iam_email]
+ condition = {
+ expression = format(
+ "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])",
+ "'roles/cloudkms.cryptoKeyEncrypterDecrypter'"
+ )
+ title = "pf_delegated_grant"
+ description = "Project factory delegated grant."
+ }
+ }
+ },
+ # stage 3 IAM bindings use conditions based on environment
+ {
+ for k, v in local.sec_s3_iam : k => {
+ role = lookup(var.custom_roles, split(":", k)[0], split(":", k)[0])
+ members = v
+ condition = {
+ title = "stage 3 ${split(":", k)[1]}"
+ expression = <<-END
+ resource.matchTag(
+ '${local.tag_root}/${var.tag_names.environment}',
+ '${split(":", k)[1]}'
+ )
+ END
+ }
+ }
+ }
+ )
+ iam_by_principals = merge(
+ {
+ # replace with more selective custom roles for production deployments
+ (local.principals.gcp-security-admins) = ["roles/editor"]
+ },
+ var.fast_stage_2.security.folder_config.iam_by_principals
+ )
+ tag_bindings = {
+ context = try(
+ local.tag_values["${var.tag_names.context}/security"].id, null
+ )
+ }
+}
+
+# optional per-environment folders
+
+module "sec-folder-prod" {
+ source = "../../../modules/folder"
+ count = local.sec_use_env_folders ? 1 : 0
+ parent = module.sec-folder[0].id
+ name = var.environments["prod"].name
+ iam = {
+ # stage 3s service accounts
+ for role, attrs in local.sec_s3_iam.prod : role => [
+ for v in attrs : (
+ v.sa == "ro"
+ ? module.stage3-sa-ro[v.s3].iam_email
+ : module.stage3-sa-rw[v.s3].iam_email
+ )
+ ]
+ }
+ tag_bindings = {
+ environment = try(
+ local.tag_values["${var.tag_names.environment}/${var.environments["prod"].tag_name}"].id,
+ null
+ )
+ }
+}
+
+module "sec-folder-dev" {
+ source = "../../../modules/folder"
+ count = local.sec_use_env_folders ? 1 : 0
+ parent = module.sec-folder[0].id
+ name = var.environments["dev"].name
+ iam = {
+ # stage 3s service accounts
+ for role, attrs in local.sec_s3_iam.dev : role => [
+ for v in attrs : (
+ v.sa == "ro"
+ ? module.stage3-sa-ro[v.s3].iam_email
+ : module.stage3-sa-rw[v.s3].iam_email
+ )
+ ]
+ }
+ tag_bindings = {
+ environment = try(
+ local.tag_values["${var.tag_names.environment}/${var.environments["dev"].tag_name}"].id,
+ null
+ )
+ }
+}
+
+# automation service accounts
+
+module "sec-sa-rw" {
+ source = "../../../modules/iam-service-account"
+ count = var.fast_stage_2.security.enabled ? 1 : 0
+ project_id = var.automation.project_id
+ name = "prod-resman-${var.fast_stage_2.security.short_name}-0"
+ display_name = "Terraform resman security service account."
+ prefix = var.prefix
+ service_account_create = var.root_node == null
+ iam = {
+ "roles/iam.serviceAccountTokenCreator" = compact([
+ try(module.cicd-sa-rw["security"].iam_email, null)
+ ])
+ }
+ iam_project_roles = {
+ (var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"]
+ }
+ iam_storage_roles = {
+ (var.automation.outputs_bucket) = ["roles/storage.objectAdmin"]
+ }
+}
+
+module "sec-sa-ro" {
+ source = "../../../modules/iam-service-account"
+ count = var.fast_stage_2.security.enabled ? 1 : 0
+ project_id = var.automation.project_id
+ name = "prod-resman-${var.fast_stage_2.security.short_name}-0r"
+ display_name = "Terraform resman security service account (read-only)."
+ prefix = var.prefix
+ iam = {
+ "roles/iam.serviceAccountTokenCreator" = compact([
+ try(module.cicd-sa-ro["security"].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 "sec-bucket" {
+ source = "../../../modules/gcs"
+ count = var.fast_stage_2.security.enabled ? 1 : 0
+ project_id = var.automation.project_id
+ name = "prod-resman-${var.fast_stage_2.security.short_name}-0"
+ prefix = var.prefix
+ location = var.locations.gcs
+ versioning = true
+ iam = {
+ "roles/storage.objectAdmin" = [module.sec-sa-rw[0].iam_email]
+ "roles/storage.objectViewer" = [module.sec-sa-ro[0].iam_email]
+ }
+}
diff --git a/fast/stages/1-resman/stage-3.tf b/fast/stages/1-resman/stage-3.tf
new file mode 100644
index 000000000..9e03b48f0
--- /dev/null
+++ b/fast/stages/1-resman/stage-3.tf
@@ -0,0 +1,213 @@
+/**
+ * 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.
+ */
+
+locals {
+ # read and decode factory files
+ _stage3_path = try(
+ pathexpand(var.factories_config.stage_3), null
+ )
+ _stage3_files = try(
+ fileset(local._stage3_path, "**/*.yaml"),
+ []
+ )
+ _stage3 = {
+ for f in local._stage3_files :
+ split(".", f)[0] => yamldecode(file(
+ "${coalesce(local._stage3_path, "-")}/${f}"
+ ))
+ }
+ # merge stage 3 from factory and variable data
+ stage3 = merge(
+ # normalize factory data attributes with defaults and nulls
+ {
+ for k, v in local._stage3 : k => {
+ short_name = v.short_name
+ environment = try(v.environment, "dev")
+ implements_stage = try(v.implements_stage, null)
+ cicd_config = lookup(v, "cicd_config", null) == null ? null : {
+ identity_provider = v.cicd_config.identity_provider
+ repository = merge(v.cicd_config.repository, {
+ branch = try(v.cicd_config.repository.branch, null)
+ type = try(v.cicd_config.repository.type, "github")
+ })
+ }
+ folder_config = lookup(v, "folder_config", null) == null ? null : {
+ name = v.folder_config.name
+ iam_by_principals = try(v.folder_config.iam_by_principals, {})
+ parent_id = try(v.folder_config.parent_id, null)
+ tag_bindings = try(v.folder_config.tag_bindings, {})
+ }
+ organization_iam = lookup(v, "organization_iam", null) == null ? null : {
+ context_tag_value = v.organization_iam.context_tag_value
+ sa_roles = merge(
+ { ro = [], rw = [] }, v.organization_iam.sa_roles
+ )
+ }
+ stage2_iam = {
+ networking = {
+ iam_admin_delegated = try(
+ v.stage2_iam.networking.iam_admin_delegated, false
+ )
+ sa_roles = merge(
+ { ro = [], rw = [] }, try(v.stage2_iam.networking.sa_roles, {})
+ )
+ }
+ security = {
+ iam_admin_delegated = try(
+ v.stage2_iam.security.iam_admin_delegated, false
+ )
+ sa_roles = merge(
+ { ro = [], rw = [] }, try(v.stage2_iam.security.sa_roles, {})
+ )
+ }
+ }
+ }
+ },
+ var.fast_stage_3
+ )
+ # extract and normalize organization IAM for stage 3s
+ stage3_sa_roles_in_org = flatten([
+ for k, v in local.stage3 : [
+ for sa, roles in try(v.organization_iam.sa_roles, []) : [
+ for role in roles : {
+ context = try(v.organization_iam.context_tag_value, "")
+ env = var.environments[v.environment].tag_name
+ role = role
+ sa = sa
+ s3 = k
+ }
+ ]
+ ]
+ ])
+ # extract and normalize stage 2 IAM for stage 2s
+ stage3_iam_in_stage2 = flatten([
+ for k, v in local.stage3 : [
+ for s2, attrs in v.stage2_iam : [
+ for sa, roles in attrs.sa_roles : [
+ for role in roles : {
+ env = var.environments[v.environment].tag_name
+ role = lookup(var.custom_roles, role, role)
+ sa = sa
+ s2 = s2
+ s3 = k
+ }
+ ]
+ ]
+ ]
+ ])
+}
+
+# top-level folder
+
+module "stage3-folder" {
+ source = "../../../modules/folder"
+ for_each = {
+ for k, v in local.stage3 : k => v if v.folder_config != null
+ }
+ parent = (
+ each.value.folder_config.parent_id == null
+ ? local.root_node
+ : try(
+ local.top_level_folder_ids[each.value.folder_config.parent_id],
+ each.value.folder_config.parent_id
+ )
+ )
+ name = each.value.folder_config.name
+ iam = {
+ "roles/logging.admin" = [module.stage3-sa-rw[each.key].iam_email]
+ "roles/owner" = [module.stage3-sa-rw[each.key].iam_email]
+ "roles/resourcemanager.folderAdmin" = [module.stage3-sa-rw[each.key].iam_email]
+ "roles/resourcemanager.projectCreator" = [module.stage3-sa-rw[each.key].iam_email]
+ "roles/compute.xpnAdmin" = [module.stage3-sa-rw[each.key].iam_email]
+ "roles/viewer" = [module.stage3-sa-ro[each.key].iam_email]
+ "roles/resourcemanager.folderViewer" = [module.stage3-sa-ro[each.key].iam_email]
+
+ }
+ iam_by_principals = each.value.folder_config.iam_by_principals
+ tag_bindings = merge(
+ {
+ environment = local.tag_values["environment/${var.environments[each.value.environment].tag_name}"].id
+ },
+ {
+ for k, v in each.value.folder_config.tag_bindings : k => try(
+ local.tag_values[v].id, v
+ )
+ }
+ )
+ depends_on = [module.top-level-folder]
+}
+
+# automation service accounts
+
+module "stage3-sa-rw" {
+ source = "../../../modules/iam-service-account"
+ for_each = local.stage3
+ project_id = var.automation.project_id
+ name = "resman-${each.value.short_name}-0"
+ display_name = (
+ "Terraform resman ${each.key} service account."
+ )
+ prefix = "${var.prefix}-${each.value.environment}"
+ iam = {
+ "roles/iam.serviceAccountTokenCreator" = compact([
+ try(module.cicd-sa-rw["${each.key}-prod"].iam_email, null)
+ ])
+ }
+ iam_project_roles = {
+ (var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"]
+ }
+ iam_storage_roles = {
+ (var.automation.outputs_bucket) = ["roles/storage.objectAdmin"]
+ }
+}
+
+module "stage3-sa-ro" {
+ source = "../../../modules/iam-service-account"
+ for_each = local.stage3
+ project_id = var.automation.project_id
+ name = "resman-${each.value.short_name}-0r"
+ display_name = (
+ "Terraform resman ${each.key} service account (read-only)."
+ )
+ prefix = "${var.prefix}-${each.value.environment}"
+ iam = {
+ "roles/iam.serviceAccountTokenCreator" = compact([
+ try(module.cicd-sa-ro["${each.key}-prod"].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 "stage3-bucket" {
+ source = "../../../modules/gcs"
+ for_each = local.stage3
+ project_id = var.automation.project_id
+ name = "resman-${each.value.short_name}-0"
+ prefix = "${var.prefix}-${each.value.environment}"
+ location = var.locations.gcs
+ versioning = true
+ iam = {
+ "roles/storage.objectAdmin" = [module.stage3-sa-rw[each.key].iam_email]
+ "roles/storage.objectViewer" = [module.stage3-sa-ro[each.key].iam_email]
+ }
+}
diff --git a/fast/stages/1-resman/stage-cicd.tf b/fast/stages/1-resman/stage-cicd.tf
new file mode 100644
index 000000000..1e44acb29
--- /dev/null
+++ b/fast/stages/1-resman/stage-cicd.tf
@@ -0,0 +1,115 @@
+/**
+ * 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.
+ */
+
+locals {
+ # intermediate normalization of repository configurations
+ _cicd_configs = merge(
+ # stage 2s
+ {
+ for k, v in var.fast_stage_2 :
+ k => merge(v.cicd_config, {
+ env = "prod", short_name = v.short_name, lvl = 2
+ })
+ if v.cicd_config != null
+ },
+ # stage 3s
+ {
+ for k, v in local.stage3 :
+ k => merge(v.cicd_config, {
+ env = v.environment, short_name = coalesce(v.short_name, k), lvl = 3
+ })
+ if v.cicd_config != null
+ }
+ )
+ # finalize configurations and filter by valid identity provider and type
+ cicd_repositories = {
+ for k, v in local._cicd_configs : k => v if(
+ contains(keys(local.identity_providers), v.identity_provider) &&
+ fileexists("${path.module}/templates/workflow-${v.repository.type}.yaml")
+ )
+ }
+ # lists of input files for each stage
+ cicd_workflow_files = {
+ stage_2 = [
+ "0-bootstrap.auto.tfvars.json",
+ "1-resman.auto.tfvars.json",
+ "0-globals.auto.tfvars.json"
+ ]
+ stage_3 = [
+ for k, v in local._cicd_configs :
+ "2-${k}.auto.tfvars" if v.lvl == 2
+ ]
+ }
+}
+
+module "cicd-sa-rw" {
+ source = "../../../modules/iam-service-account"
+ for_each = local.cicd_repositories
+ project_id = var.automation.project_id
+ name = "resman-${each.value.short_name}-1"
+ display_name = (
+ "CI/CD ${each.value.lvl}-${each.value.short_name} ${each.value.env} service account."
+ )
+ prefix = "${var.prefix}-${each.value.env}"
+ iam = {
+ "roles/iam.workloadIdentityUser" = [
+ each.value.repository.branch == null
+ ? format(
+ local.identity_providers[each.value.identity_provider].principal_repo,
+ var.automation.federated_identity_pool,
+ each.value.repository.name
+ )
+ : format(
+ local.identity_providers[each.value.identity_provider].principal_branch,
+ var.automation.federated_identity_pool,
+ each.value.repository.name,
+ each.value.repository.branch
+ )
+ ]
+ }
+ iam_project_roles = {
+ (var.automation.project_id) = ["roles/logging.logWriter"]
+ }
+ iam_storage_roles = {
+ (var.automation.outputs_bucket) = ["roles/storage.objectViewer"]
+ }
+}
+
+module "cicd-sa-ro" {
+ source = "../../../modules/iam-service-account"
+ for_each = local.cicd_repositories
+ project_id = var.automation.project_id
+ name = "resman-${each.value.short_name}-1r"
+ display_name = (
+ "CI/CD ${each.value.lvl}-${each.value.short_name} ${each.value.env} service account (read-only)."
+ )
+ prefix = "${var.prefix}-${each.value.env}"
+ iam = {
+ "roles/iam.workloadIdentityUser" = [
+ format(
+ local.identity_providers[each.value.identity_provider].principal_repo,
+ var.automation.federated_identity_pool,
+ each.value.repository.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/templates/providers_gcs.tf.tpl b/fast/stages/1-resman/templates/providers.tf.tpl
similarity index 100%
rename from fast/stages/1-resman/templates/providers_gcs.tf.tpl
rename to fast/stages/1-resman/templates/providers.tf.tpl
diff --git a/fast/stages/1-resman/tenant-root.tf b/fast/stages/1-resman/tenant-root.tf
index c65bb0c02..e5d79c717 100644
--- a/fast/stages/1-resman/tenant-root.tf
+++ b/fast/stages/1-resman/tenant-root.tf
@@ -42,62 +42,12 @@ module "automation-project" {
(var.tag_names.context) = {
description = "Resource management context."
iam = try(local.tags.context.iam, {})
- values = {
- data = {
- iam = try(local.tags.context.values.data.iam, {})
- description = try(local.tags.context.values.data.description, null)
- }
- gke = {
- iam = try(local.tags.context.values.gke.iam, {})
- description = try(local.tags.context.values.gke.description, null)
- }
- gcve = {
- iam = try(local.tags.context.values.gcve.iam, {})
- description = try(local.tags.context.values.gcve.description, null)
- }
- networking = {
- iam = try(local.tags.context.values.networking.iam, {})
- description = try(local.tags.context.values.networking.description, null)
- }
- project-factory = {
- iam = try(local.tags.context.values.project-factory.iam, {})
- description = try(local.tags.context.values.project-factory.description, null)
- }
- sandbox = {
- iam = try(local.tags.context.values.sandbox.iam, {})
- description = try(local.tags.context.values.sandbox.description, null)
- }
- security = {
- iam = try(local.tags.context.values.security.iam, {})
- description = try(local.tags.context.values.security.description, null)
- }
- }
- }
+ values = local.context_tag_values
+ },
(var.tag_names.environment) = {
description = "Environment definition."
iam = try(local.tags.environment.iam, {})
- values = {
- development = {
- iam = try(local.tags.environment.values.development.iam, {})
- iam_bindings = {
- pf = {
- members = [module.branch-pf-sa.iam_email]
- role = "roles/resourcemanager.tagUser"
- }
- }
- description = try(local.tags.environment.values.development.description, null)
- }
- production = {
- iam = try(local.tags.environment.values.production.iam, {})
- iam_bindings = {
- pf = {
- members = [module.branch-pf-sa.iam_email]
- role = "roles/resourcemanager.tagUser"
- }
- }
- description = try(local.tags.environment.values.production.description, null)
- }
- }
+ values = local.environment_tag_values
}
})
}
diff --git a/fast/stages/1-resman/top-level-folders.tf b/fast/stages/1-resman/top-level-folders.tf
index e2e8901cf..578e6c2a8 100644
--- a/fast/stages/1-resman/top-level-folders.tf
+++ b/fast/stages/1-resman/top-level-folders.tf
@@ -15,6 +15,7 @@
*/
locals {
+ # read and decode factory files
_top_level_path = try(
pathexpand(var.factories_config.top_level_folders), null
)
@@ -28,20 +29,27 @@ locals {
"${coalesce(local._top_level_path, "-")}/${f}"
))
}
+ # extract automation configurations for folders that define them
top_level_automation = {
for k, v in local.top_level_folders :
- k => v.automation if try(v.automation.enable, null) == true
+ k => v.automation
+ if v.automation != null
}
+ # merge top folders from factory and variable data
top_level_folders = merge(
+ # normalize factory data attributes with defaults and nulls
{
for k, v in local._top_level_folders : k => merge(v, {
name = try(v.name, k)
- automation = try(v.automation, {
- enable = true
- sa_impersonation_principals = []
- })
+ automation = !can(v.automation) ? null : {
+ environment_name = try(v.automation.environment_name, "prod")
+ sa_impersonation_principals = try(v.automation.sa_impersonation_principals, [])
+ short_name = try(v.automation.short_name, null)
+ }
contacts = try(v.contacts, {})
+ factories_config = try(v.factories_config, null)
firewall_policy = try(v.firewall_policy, null)
+ is_fast_context = try(v.is_fast_context, true)
logging_data_access = try(v.logging_data_access, {})
logging_exclusions = try(v.logging_exclusions, {})
logging_settings = try(v.logging_settings, null)
@@ -51,26 +59,25 @@ locals {
iam_bindings_additive = try(v.iam_bindings_additive, {})
iam_by_principals = try(v.iam_by_principals, {})
org_policies = try(v.org_policies, {})
+ parent_id = try(v.parent_id, null)
tag_bindings = try(v.tag_bindings, {})
})
},
var.top_level_folders
)
top_level_sa = {
- for k, v in local.branch_service_accounts :
+ for k, v in local.stage_service_accounts :
k => "serviceAccount:${v}" if v != null
}
- top_level_tags = {
- for k, v in try(local.tag_values, {}) : k => v.id
- }
}
module "top-level-folder" {
source = "../../../modules/folder"
for_each = local.top_level_folders
- parent = local.root_node
+ parent = coalesce(each.value.parent_id, local.root_node)
name = each.value.name
contacts = each.value.contacts
+ factories_config = each.value.factories_config
firewall_policy = each.value.firewall_policy
logging_data_access = each.value.logging_data_access
logging_exclusions = each.value.logging_exclusions
@@ -97,21 +104,26 @@ module "top-level-folder" {
# we don't replace here to avoid dynamic values in keys
iam_by_principals = each.value.iam_by_principals
org_policies = each.value.org_policies
- tag_bindings = {
- for k, v in each.value.tag_bindings : k => lookup(
- local.top_level_tags, v, v
- )
- }
+ tag_bindings = merge(
+ # explicit tag bindings
+ {
+ for k, v in each.value.tag_bindings : k => try(local.tag_values[v].id, v)
+ },
+ # implicit tag binding on own context tag value
+ each.value.is_fast_context != true ? {} : {
+ context = local.tag_values["context/${each.key}"].id
+ }
+ )
}
module "top-level-sa" {
source = "../../../modules/iam-service-account"
for_each = local.top_level_automation
project_id = var.automation.project_id
- name = "prod-resman-${each.key}-0"
+ name = "${each.value.environment_name}-resman-${coalesce(each.value.short_name, each.key)}-0"
display_name = "Terraform resman ${each.key} folder service account."
prefix = var.prefix
- iam = {
+ iam = each.value.sa_impersonation_principals == null ? {} : {
"roles/iam.serviceAccountTokenCreator" = each.value.sa_impersonation_principals
}
iam_project_roles = {
@@ -126,7 +138,7 @@ module "top-level-bucket" {
source = "../../../modules/gcs"
for_each = local.top_level_automation
project_id = var.automation.project_id
- name = "prod-resman-${each.key}-0"
+ name = "${each.value.environment_name}-resman-${coalesce(each.value.short_name, each.key)}-0"
prefix = var.prefix
location = var.locations.gcs
versioning = true
diff --git a/fast/stages/1-resman/variables-fast.tf b/fast/stages/1-resman/variables-fast.tf
index 6f2a3db20..a35f5eca4 100644
--- a/fast/stages/1-resman/variables-fast.tf
+++ b/fast/stages/1-resman/variables-fast.tf
@@ -32,17 +32,6 @@ variable "automation" {
principal_branch = string
principal_repo = string
}))
- cicd_backends = object({
- terraform = object({
- organization = string
- workspaces = map(object({
- tags = list(string)
- name = string
- project = string
- }))
- hostname = string
- })
- })
service_accounts = object({
resman-r = string
})
@@ -65,19 +54,37 @@ 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
- network_firewall_policies_admin = string
- # TODO: remove after v34.0.0
- network_firewall_policies_viewer = optional(string)
- ngfw_enterprise_admin = string
- ngfw_enterprise_viewer = string
- organization_admin_viewer = string
- service_project_network_admin = string
- storage_viewer = string
+ billing_viewer = string
+ organization_admin_viewer = string
+ project_iam_viewer = string
+ service_project_network_admin = string
+ storage_viewer = string
+ gcve_network_admin = optional(string)
+ gcve_network_viewer = optional(string)
+ network_firewall_policies_admin = optional(string)
+ ngfw_enterprise_admin = optional(string)
+ ngfw_enterprise_viewer = optional(string)
})
default = null
}
+variable "environments" {
+ # tfdoc:variable:source 0-globals
+ description = "Environment names."
+ type = map(object({
+ name = string
+ tag_name = string
+ is_default = optional(bool, false)
+ }))
+ nullable = false
+ validation {
+ condition = anytrue([
+ for k, v in var.environments : v.is_default == true
+ ])
+ error_message = "At least one environment should be marked as default."
+ }
+}
+
variable "groups" {
# tfdoc:variable:source 0-bootstrap
# https://cloud.google.com/docs/enterprise/setup-checklist
diff --git a/fast/stages/1-resman/variables-stages.tf b/fast/stages/1-resman/variables-stages.tf
new file mode 100644
index 000000000..d3d244a8e
--- /dev/null
+++ b/fast/stages/1-resman/variables-stages.tf
@@ -0,0 +1,161 @@
+/**
+ * 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 "fast_stage_2" {
+ description = "FAST stages 2 configurations."
+ type = object({
+ networking = optional(object({
+ enabled = optional(bool, true)
+ short_name = optional(string, "net")
+ cicd_config = optional(object({
+ identity_provider = string
+ repository = object({
+ name = string
+ branch = optional(string)
+ parent_id = optional(string)
+ type = optional(string, "github")
+ })
+ }))
+ folder_config = optional(object({
+ create_env_folders = optional(bool, true)
+ iam_by_principals = optional(map(list(string)), {})
+ name = optional(string, "Networking")
+ parent_id = optional(string)
+ }), {})
+ }), {})
+ network_security = optional(object({
+ enabled = optional(bool, false)
+ short_name = optional(string, "nsec")
+ cicd_config = optional(object({
+ identity_provider = string
+ repository = object({
+ name = string
+ branch = optional(string)
+ parent_id = optional(string)
+ type = optional(string, "github")
+ })
+ }))
+ }), {})
+ project_factory = optional(object({
+ enabled = optional(bool, true)
+ short_name = optional(string, "pf")
+ cicd_config = optional(object({
+ identity_provider = string
+ repository = object({
+ name = string
+ branch = optional(string)
+ type = optional(string, "github")
+ })
+ }))
+ }), {})
+ security = optional(object({
+ enabled = optional(bool, true)
+ short_name = optional(string, "sec")
+ cicd_config = optional(object({
+ identity_provider = string
+ repository = object({
+ name = string
+ branch = optional(string)
+ type = optional(string, "github")
+ })
+ }))
+ folder_config = optional(object({
+ create_env_folders = optional(bool, false)
+ iam_by_principals = optional(map(list(string)), {})
+ name = optional(string, "Security")
+ parent_id = optional(string)
+ }), {})
+ }), {})
+ })
+ nullable = false
+ default = {}
+ validation {
+ condition = alltrue([
+ for k, v in var.fast_stage_2 :
+ v.cicd_config == null || contains(
+ ["github", "gitlab"],
+ coalesce(try(v.cicd_config.repository.type, null), "-")
+ )
+ ])
+ error_message = "Invalid CI/CD repository type."
+ }
+}
+
+variable "fast_stage_3" {
+ description = "FAST stages 3 configurations."
+ # key is used for file names and loop keys and is like 'data-platfom-dev'
+ type = map(object({
+ short_name = string
+ environment = optional(string, "dev")
+ cicd_config = optional(object({
+ identity_provider = string
+ repository = object({
+ name = string
+ branch = optional(string)
+ type = optional(string, "github")
+ })
+ }))
+ folder_config = optional(object({
+ name = string
+ iam_by_principals = optional(map(list(string)), {})
+ parent_id = optional(string)
+ tag_bindings = optional(map(string), {})
+ }))
+ organization_iam = optional(object({
+ context_tag_value = string
+ sa_roles = object({
+ ro = optional(list(string), [])
+ rw = optional(list(string), [])
+ })
+ }))
+ stage2_iam = optional(object({
+ networking = optional(object({
+ iam_admin_delegated = optional(bool, false)
+ sa_roles = optional(object({
+ ro = optional(list(string), [])
+ rw = optional(list(string), [])
+ }), {})
+ }), {})
+ security = optional(object({
+ iam_admin_delegated = optional(bool, false)
+ sa_roles = optional(object({
+ ro = optional(list(string), [])
+ rw = optional(list(string), [])
+ }), {})
+ }), {})
+ }), {})
+ }))
+ nullable = false
+ default = {}
+ # TODO: upgrade to cross-variable validation
+ validation {
+ condition = alltrue([
+ for k, v in var.fast_stage_3 :
+ contains(["dev", "prod"], coalesce(v.environment, "-"))
+ ])
+ error_message = "Invalid environment value."
+ }
+ validation {
+ condition = alltrue([
+ for k, v in var.fast_stage_3 :
+ v.cicd_config == null || contains(
+ ["github", "gitlab"],
+ coalesce(try(v.cicd_config.repository.type, null), "-")
+ )
+ ])
+ error_message = "Invalid CI/CD repository type."
+ }
+}
diff --git a/fast/stages/1-resman/variables-toplevel-folders.tf b/fast/stages/1-resman/variables-toplevel-folders.tf
new file mode 100644
index 000000000..a2f76e108
--- /dev/null
+++ b/fast/stages/1-resman/variables-toplevel-folders.tf
@@ -0,0 +1,99 @@
+/**
+ * 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 "top_level_folders" {
+ description = "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."
+ type = map(object({
+ name = string
+ parent_id = optional(string)
+ automation = optional(object({
+ environment_name = optional(string, "prod")
+ sa_impersonation_principals = optional(list(string), [])
+ short_name = optional(string)
+ }))
+ contacts = optional(map(list(string)), {})
+ factories_config = optional(object({
+ org_policies = optional(string)
+ }))
+ firewall_policy = optional(object({
+ name = string
+ policy = string
+ }))
+ # TODO: remember to document this, and how to use the same value in other folders
+ is_fast_context = optional(bool, true)
+ logging_data_access = optional(map(map(list(string))), {})
+ logging_exclusions = optional(map(string), {})
+ logging_settings = optional(object({
+ disable_default_sink = optional(bool)
+ storage_location = optional(string)
+ }))
+ logging_sinks = optional(map(object({
+ bq_partitioned_table = optional(bool, false)
+ description = optional(string)
+ destination = string
+ disabled = optional(bool, false)
+ exclusions = optional(map(string), {})
+ filter = optional(string)
+ iam = optional(bool, true)
+ include_children = optional(bool, true)
+ type = string
+ })), {})
+ iam = optional(map(list(string)), {})
+ iam_bindings = optional(map(object({
+ members = list(string)
+ role = string
+ condition = optional(object({
+ expression = string
+ title = string
+ description = optional(string)
+ }))
+ })), {})
+ iam_bindings_additive = optional(map(object({
+ member = string
+ role = string
+ condition = optional(object({
+ expression = string
+ title = string
+ description = optional(string)
+ }))
+ })), {})
+ iam_by_principals = optional(map(list(string)), {})
+ org_policies = optional(map(object({
+ inherit_from_parent = optional(bool) # for list policies only.
+ reset = optional(bool)
+ rules = optional(list(object({
+ allow = optional(object({
+ all = optional(bool)
+ values = optional(list(string))
+ }))
+ deny = optional(object({
+ all = optional(bool)
+ values = optional(list(string))
+ }))
+ enforce = optional(bool) # for boolean policies only.
+ condition = optional(object({
+ description = optional(string)
+ expression = optional(string)
+ location = optional(string)
+ title = optional(string)
+ }), {})
+ })), [])
+ })), {})
+ tag_bindings = optional(map(string), {})
+ }))
+ nullable = false
+ default = {}
+}
diff --git a/fast/stages/1-resman/variables.tf b/fast/stages/1-resman/variables.tf
index a2a454e8a..6443f02dc 100644
--- a/fast/stages/1-resman/variables.tf
+++ b/fast/stages/1-resman/variables.tf
@@ -17,146 +17,17 @@
# defaults for variables marked with global tfdoc annotations, can be set via
# the tfvars file generated in stage 00 and stored in its outputs
-variable "cicd_repositories" {
- description = "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."
- type = object({
- data_platform_dev = optional(object({
- name = string
- type = string
- branch = optional(string)
- identity_provider = optional(string)
- }))
- data_platform_prod = optional(object({
- name = string
- type = string
- branch = optional(string)
- identity_provider = optional(string)
- }))
- gke_dev = optional(object({
- name = string
- type = string
- branch = optional(string)
- identity_provider = optional(string)
- }))
- gke_prod = optional(object({
- name = string
- type = string
- branch = optional(string)
- identity_provider = optional(string)
- }))
- gcve_dev = optional(object({
- name = string
- type = string
- branch = optional(string)
- identity_provider = optional(string)
- }))
- gcve_prod = optional(object({
- name = string
- type = string
- branch = optional(string)
- identity_provider = optional(string)
- }))
- nsec = optional(object({
- name = string
- type = string
- branch = optional(string)
- identity_provider = optional(string)
- }))
- networking = optional(object({
- name = string
- type = string
- branch = optional(string)
- identity_provider = optional(string)
- }))
- project_factory = optional(object({
- name = string
- type = string
- branch = optional(string)
- identity_provider = optional(string)
- }))
- project_factory_dev = optional(object({
- name = string
- type = string
- branch = optional(string)
- identity_provider = optional(string)
- }))
- project_factory_prod = optional(object({
- name = string
- type = string
- branch = optional(string)
- identity_provider = optional(string)
- }))
- security = optional(object({
- name = string
- type = string
- branch = optional(string)
- identity_provider = optional(string)
- }))
- })
- default = null
- validation {
- condition = alltrue([
- for k, v in coalesce(var.cicd_repositories, {}) :
- v == null || try(v.name, null) != null
- ])
- error_message = "Non-null repositories need a non-null name."
- }
- validation {
- condition = alltrue([
- for k, v in coalesce(var.cicd_repositories, {}) :
- v == null || try(v.identity_provider, null) != null
- ])
- error_message = "Non-null repositories need a non-null provider."
- }
- validation {
- condition = alltrue([
- for k, v in coalesce(var.cicd_repositories, {}) :
- v == null || (
- contains(["github", "gitlab", "terraform"], coalesce(try(v.type, null), "null"))
- )
- ])
- error_message = "Invalid repository type, supported types: 'github', 'gitlab', or 'terraform'."
- }
-}
-
variable "factories_config" {
description = "Configuration for the resource factories or external data."
type = object({
- checklist_data = optional(string)
org_policies = optional(string, "data/org-policies")
+ stage_3 = optional(string, "data/stage-3")
top_level_folders = optional(string, "data/top-level-folders")
})
nullable = false
default = {}
}
-variable "fast_features" {
- description = "Selective control for top-level FAST features."
- type = object({
- data_platform = optional(bool, false)
- gke = optional(bool, false)
- gcve = optional(bool, false)
- nsec = optional(bool, false)
- sandbox = optional(bool, false)
- })
- default = {}
- nullable = false
-}
-
-variable "folder_iam" {
- description = "Authoritative IAM for top-level folders."
- type = object({
- data_platform = optional(map(list(string)), {})
- gcve = optional(map(list(string)), {})
- gke = optional(map(list(string)), {})
- sandbox = optional(map(list(string)), {})
- security = optional(map(list(string)), {})
- network = optional(map(list(string)), {})
- })
- nullable = false
- default = {}
-}
-
variable "outputs_location" {
description = "Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable."
type = string
@@ -197,80 +68,3 @@ variable "tags" {
error_message = "Use an empty map instead of null as value."
}
}
-
-variable "top_level_folders" {
- description = "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."
- type = map(object({
- name = string
- automation = optional(object({
- enable = optional(bool, true)
- sa_impersonation_principals = optional(list(string), [])
- }), {})
- contacts = optional(map(list(string)), {})
- firewall_policy = optional(object({
- name = string
- policy = string
- }))
- logging_data_access = optional(map(map(list(string))), {})
- logging_exclusions = optional(map(string), {})
- logging_settings = optional(object({
- disable_default_sink = optional(bool)
- storage_location = optional(string)
- }))
- logging_sinks = optional(map(object({
- bq_partitioned_table = optional(bool, false)
- description = optional(string)
- destination = string
- disabled = optional(bool, false)
- exclusions = optional(map(string), {})
- filter = optional(string)
- iam = optional(bool, true)
- include_children = optional(bool, true)
- type = string
- })), {})
- iam = optional(map(list(string)), {})
- iam_bindings = optional(map(object({
- members = list(string)
- role = string
- condition = optional(object({
- expression = string
- title = string
- description = optional(string)
- }))
- })), {})
- iam_bindings_additive = optional(map(object({
- member = string
- role = string
- condition = optional(object({
- expression = string
- title = string
- description = optional(string)
- }))
- })), {})
- iam_by_principals = optional(map(list(string)), {})
- org_policies = optional(map(object({
- inherit_from_parent = optional(bool) # for list policies only.
- reset = optional(bool)
- rules = optional(list(object({
- allow = optional(object({
- all = optional(bool)
- values = optional(list(string))
- }))
- deny = optional(object({
- all = optional(bool)
- values = optional(list(string))
- }))
- enforce = optional(bool) # for boolean policies only.
- condition = optional(object({
- description = optional(string)
- expression = optional(string)
- location = optional(string)
- title = optional(string)
- }), {})
- })), [])
- })), {})
- tag_bindings = optional(map(string), {})
- }))
- nullable = false
- default = {}
-}
diff --git a/fast/stages/1-tenant-factory/.fast-stage.env b/fast/stages/1-tenant-factory/.fast-stage.env
new file mode 100644
index 000000000..2feb424dd
--- /dev/null
+++ b/fast/stages/1-tenant-factory/.fast-stage.env
@@ -0,0 +1,5 @@
+FAST_STAGE_DESCRIPTION="tenant factory"
+FAST_STAGE_LEVEL=1
+FAST_STAGE_NAME=tenant-factory
+FAST_STAGE_DEPS="0-globals 0-bootstrap"
+# FAST_STAGE_OPTIONAL=""
diff --git a/fast/stages/1-tenant-factory/README.md b/fast/stages/1-tenant-factory/README.md
index af30740e8..adb91c678 100644
--- a/fast/stages/1-tenant-factory/README.md
+++ b/fast/stages/1-tenant-factory/README.md
@@ -13,6 +13,7 @@ Typical use cases include large organizations managing a single Cloud subscripti
- [Impersonating the automation service account](#impersonating-the-automation-service-account)
- [Variable configuration](#variable-configuration)
- [Running the stage](#running-the-stage)
+ - [Organization policy errors](#organization-policy-errors)
- [Tenant configuration](#tenant-configuration)
- [Configurations for both simple and FAST tenants](#configurations-for-both-simple-and-fast-tenants)
- [Configurations for FAST tenants](#configurations-for-fast-tenants)
@@ -90,26 +91,38 @@ The only real prerequisite is having fully deployed the [bootstrap](../0-bootstr
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.
+The commands to link or copy the provider and terraform variable files can be easily derived from the `fast-links.sh` script in the FAST stages 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
+../fast-links.sh ~/fast-config
-# copy and paste the following commands for '1-tenant-factory'
+# File linking commands for tenant factory stage
-ln -s ~/fast-config/providers/1-tenant-factory-providers.tf ./
-ln -s ~/fast-config/tfvars/0-globals.auto.tfvars.json ./
-ln -s ~/fast-config/tfvars/0-bootstrap.auto.tfvars.json ./
+# provider file
+ln -s ~/fast-config/fast-test-00/providers/1-resman-providers.tf ./
+
+# input files from other stages
+ln -s ~/fast-config/fast-test-00/tfvars/0-globals.auto.tfvars.json ./
+ln -s ~/fast-config/fast-test-00/tfvars/0-bootstrap.auto.tfvars.json ./
+
+# conventional place for stage tfvars (manually created)
+ln -s ~/fast-config/fast-test-00/1-tenant-factory.auto.tfvars ./
```
```bash
-../../stage-links.sh gs://xxx-prod-iac-core-outputs-0
+../fast-links.sh gs://xxx-prod-iac-core-outputs-0
-# copy and paste the following commands for '1-tenant-factory'
+# File linking commands for tenant factory stage
-gcloud storage cp gs://xxx-prod-iac-core-outputs-0/providers/1-tenant-factory-providers.tf ./
+# provider file
+gcloud storage cp gs://xxx-prod-iac-core-outputs-0/providers/1-resman-providers.tf ./
+
+# input files from other stages
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 ./
+
+# conventional place for stage tfvars (manually created)
+gcloud storage cp gs://xxx-prod-iac-core-outputs-0/1-tenant-factory.auto.tfvars ./
```
### Impersonating the automation service account
@@ -143,6 +156,12 @@ terraform init
terraform apply
```
+#### Organization policy errors
+
+If you get an organization policy error assigning IAM roles or setting essential contacts on tenant-level resources, make sure the tenant configuration contains the right customer id and domain in the `cloud_identity` attributes, and the administrative principals and essential contacts for the tenant belong to the right Cloud Identity.
+
+If both are correct, wait a couple of minutes for the organization policies to be enforced and retry. Remember to also check the organization-level IaC project org policies, which can be customized via the bootstrap stage variables.
+
## Tenant configuration
This stage has only three variables that can be customized:
@@ -281,7 +300,7 @@ gcloud storage cp gs://{prefix}-{tenant-shortname}-prod-iac-core-0/tfvars/0-glob
gcloud storage cp gs://{prefix}-{tenant-shortname}-prod-iac-core-0/tfvars/0-bootstrap.auto.tfvars.json ./
```
-
+
## Files
@@ -307,15 +326,15 @@ gcloud storage cp gs://{prefix}-{tenant-shortname}-prod-iac-core-0/tfvars/0-boot
| name | description | type | required | default | producer |
|---|---|:---:|:---:|:---:|:---:|
-| [automation](variables-fast.tf#L19) | Automation resources created by the bootstrap stage. | object({…}) | ✓ | | 0-bootstrap |
-| [billing_account](variables-fast.tf#L53) | 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#L110) | Logging resources created by the bootstrap stage. | object({…}) | ✓ | | 0-bootstrap |
-| [org_policy_tags](variables-fast.tf#L129) | Organization policy tags. | object({…}) | ✓ | | 0-bootstrap |
-| [organization](variables-fast.tf#L119) | Organization details. | object({…}) | ✓ | | 0-bootstrap |
-| [prefix](variables-fast.tf#L146) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 0-bootstrap |
-| [custom_roles](variables-fast.tf#L64) | Custom roles defined at the org level, in key => id format. | object({…}) | | null | 0-bootstrap |
-| [groups](variables-fast.tf#L82) | 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#L97) | Optional locations for GCS, BigQuery, and logging buckets created here. | object({…}) | | {} | 0-bootstrap |
+| [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#L97) | Logging resources created by the bootstrap stage. | object({…}) | ✓ | | 0-bootstrap |
+| [org_policy_tags](variables-fast.tf#L116) | Organization policy tags. | object({…}) | ✓ | | 0-bootstrap |
+| [organization](variables-fast.tf#L106) | Organization details. | object({…}) | ✓ | | 0-bootstrap |
+| [prefix](variables-fast.tf#L133) | 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#L69) | 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#L84) | 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({…}) | | {} | |
@@ -325,5 +344,5 @@ gcloud storage cp gs://{prefix}-{tenant-shortname}-prod-iac-core-0/tfvars/0-boot
| name | description | sensitive | consumers |
|---|---|:---:|---|
-| [tenants](outputs.tf#L202) | Tenant base configuration. | | |
+| [tenants](outputs.tf#L130) | Tenant base configuration. | | |
diff --git a/fast/stages/1-tenant-factory/outputs.tf b/fast/stages/1-tenant-factory/outputs.tf
index adda64df1..71ec64f67 100644
--- a/fast/stages/1-tenant-factory/outputs.tf
+++ b/fast/stages/1-tenant-factory/outputs.tf
@@ -15,9 +15,7 @@
*/
locals {
- _tpl_providers_gcs = "${path.module}/templates/providers_gcs.tf.tpl"
- _tpl_providers_terraform = "${path.module}/templates/providers_terraform.tf.tpl"
- _tpl_providers = var.automation.cicd_backends != null && try(var.automation.cicd_backends.terraform, null) != null ? local._tpl_providers_terraform : local._tpl_providers_gcs
+ _tpl_providers = "${path.module}/templates/providers.tf.tpl"
tenant_cicd_workflows = {
for k, v in local.cicd_repositories :
k => templatefile("${path.module}/templates/workflow-${v.type}.yaml", {
@@ -53,91 +51,21 @@ locals {
vpcsc_policy_id = try(module.tenant-vpcsc-policy[k].id, null)
}
}
- _tenant_providers = {
- for k, v in local.fast_tenants : k => {
+ tenant_providers = {
+ for k, v in local.fast_tenants : k => templatefile(local._tpl_providers, {
backend_extra = null
bucket = module.tenant-automation-tf-resman-gcs[k].name
name = k
sa = module.tenant-automation-tf-resman-sa[k].email
- }
+ })
}
- tenant_providers = {
- for k, v in local._tenant_providers : k => (
- var.automation.cicd_backends != null && try(var.automation.cicd_backends.terraform, null) != null ?
- templatefile(
- local._tpl_providers_terraform,
- merge(
- {
- name = v.name,
- sa = v.sa
- },
- {
- workspaces = lookup(
- var.automation.cicd_backends.terraform.workspaces,
- v.name,
- {
- tags = null,
- name = null,
- project = null
- }
- )
- },
- {
- organization = var.automation.cicd_backends.terraform.organization,
- hostname = var.automation.cicd_backends.terraform.hostname
- }
- )
- ) :
- templatefile(local._tpl_providers_gcs, {
- name = v.name,
- sa = v.sa,
- bucket = v.bucket,
- backend_extra = v.backend_extra
- })
- )
- }
- _tenant_providers_r = {
- for k, v in local.fast_tenants : k => {
+ tenant_providers_r = {
+ for k, v in local.fast_tenants : k => templatefile(local._tpl_providers, {
backend_extra = null
bucket = module.tenant-automation-tf-resman-gcs[k].name
name = k
sa = module.tenant-automation-tf-resman-r-sa[k].email
- }
- }
- tenant_providers_r = {
- for k, v in local._tenant_providers_r : k => (
- var.automation.cicd_backends != null && try(var.automation.cicd_backends.terraform, null) != null ?
- templatefile(
- local._tpl_providers_terraform,
- merge(
- {
- name = v.name,
- sa = v.sa
- },
- {
- workspaces = lookup(
- var.automation.cicd_backends.terraform.workspaces,
- v.name,
- {
- tags = null,
- name = null,
- project = null
- }
- )
- },
- {
- organization = var.automation.cicd_backends.terraform.organization,
- hostname = var.automation.cicd_backends.terraform.hostname
- }
- )
- ) :
- templatefile(local._tpl_providers_gcs, {
- name = v.name,
- sa = v.sa,
- bucket = v.bucket,
- backend_extra = v.backend_extra
- })
- )
+ })
}
tenant_globals = {
for k, v in local.fast_tenants : k => {
diff --git a/fast/stages/1-tenant-factory/templates/providers_gcs.tf.tpl b/fast/stages/1-tenant-factory/templates/providers.tf.tpl
similarity index 100%
rename from fast/stages/1-tenant-factory/templates/providers_gcs.tf.tpl
rename to fast/stages/1-tenant-factory/templates/providers.tf.tpl
diff --git a/fast/stages/1-tenant-factory/tenant-core.tf b/fast/stages/1-tenant-factory/tenant-core.tf
index 496dcf54f..c4d3086c9 100644
--- a/fast/stages/1-tenant-factory/tenant-core.tf
+++ b/fast/stages/1-tenant-factory/tenant-core.tf
@@ -25,7 +25,7 @@ module "tenant-core-logbucket" {
for_each = local.tenants
parent_type = "project"
parent = var.logging.project_id
- id = "tenant-${each.key}-audit"
+ id = "tn-${each.key}-audit"
location = var.locations.logging
log_analytics = { enable = true }
}
@@ -36,7 +36,7 @@ module "tenant-core-folder" {
parent = local.root_node
name = "${each.value.descriptive_name} Core"
logging_sinks = {
- "tenant-${each.key}-audit" = {
+ "tn-${each.key}-audit" = {
destination = module.tenant-core-logbucket[each.key].id
filter = <<-FILTER
log_id("cloudaudit.googleapis.com/activity") OR
@@ -48,6 +48,16 @@ module "tenant-core-folder" {
}
}
org_policies = each.value.cloud_identity == null ? {} : {
+ "essentialcontacts.allowedContactDomains" = {
+ rules = [{
+ allow = {
+ values = formatlist("@%s", compact([
+ var.organization.domain,
+ try(each.value.cloud_identity.domain, null)
+ ]))
+ }
+ }]
+ }
"iam.allowedPolicyMemberDomains" = {
rules = [{
allow = {
diff --git a/fast/stages/1-tenant-factory/tenant-fast-vpcsc.tf b/fast/stages/1-tenant-factory/tenant-fast-vpcsc.tf
index 6330f5244..12b235bec 100644
--- a/fast/stages/1-tenant-factory/tenant-fast-vpcsc.tf
+++ b/fast/stages/1-tenant-factory/tenant-fast-vpcsc.tf
@@ -29,10 +29,11 @@ module "tenant-vpcsc-policy" {
}
iam_bindings_additive = merge(
{
- tenant_admins = {
- role = "roles/accesscontextmanager.policyAdmin"
- member = each.value.admin_principal
- }
+ # uncomment this if tenant admins are allowed by org-level DRS policy
+ # tenant_admins = {
+ # role = "roles/accesscontextmanager.policyAdmin"
+ # member = each.value.admin_principal
+ # }
tenant_sa = {
role = "roles/accesscontextmanager.policyAdmin"
member = module.tenant-sa[each.key].iam_email
diff --git a/fast/stages/1-tenant-factory/tenant.tf b/fast/stages/1-tenant-factory/tenant.tf
index 79c202ef7..b143639f2 100644
--- a/fast/stages/1-tenant-factory/tenant.tf
+++ b/fast/stages/1-tenant-factory/tenant.tf
@@ -97,7 +97,7 @@ module "tenant-sa" {
source = "../../../modules/iam-service-account"
for_each = local.tenants
project_id = var.automation.project_id
- name = "tenant-${each.key}-0"
+ name = "tn-${each.key}-0"
display_name = "Terraform tenant ${each.key} service account."
prefix = var.prefix
iam = {
@@ -114,7 +114,7 @@ module "tenant-gcs" {
source = "../../../modules/gcs"
for_each = local.tenants
project_id = var.automation.project_id
- name = "tenant-${each.key}-0"
+ name = "tn-${each.key}-0"
prefix = var.prefix
location = each.value.locations.gcs
versioning = true
diff --git a/fast/stages/1-tenant-factory/variables-fast.tf b/fast/stages/1-tenant-factory/variables-fast.tf
index 011708c12..e8179a2bb 100644
--- a/fast/stages/1-tenant-factory/variables-fast.tf
+++ b/fast/stages/1-tenant-factory/variables-fast.tf
@@ -32,17 +32,6 @@ variable "automation" {
principal_branch = string
principal_repo = string
}))
- cicd_backends = object({
- terraform = object({
- organization = string
- workspaces = map(object({
- tags = list(string)
- name = string
- project = string
- }))
- hostname = string
- })
- })
service_accounts = object({
resman = string
resman-r = string
@@ -67,14 +56,12 @@ variable "custom_roles" {
type = object({
gcve_network_admin = string
network_firewall_policies_admin = string
- # TODO: remove after v34.0.0
- network_firewall_policies_viewer = optional(string)
- ngfw_enterprise_admin = optional(string)
- ngfw_enterprise_viewer = optional(string)
- organization_admin_viewer = string
- service_project_network_admin = string
- storage_viewer = string
- tenant_network_admin = string
+ ngfw_enterprise_admin = optional(string)
+ ngfw_enterprise_viewer = optional(string)
+ organization_admin_viewer = string
+ service_project_network_admin = string
+ storage_viewer = string
+ tenant_network_admin = string
})
default = null
}
diff --git a/fast/stages/1-vpcsc/.fast-stage.env b/fast/stages/1-vpcsc/.fast-stage.env
new file mode 100644
index 000000000..40c84f9b6
--- /dev/null
+++ b/fast/stages/1-vpcsc/.fast-stage.env
@@ -0,0 +1,5 @@
+FAST_STAGE_DESCRIPTION="vpc service controls"
+FAST_STAGE_LEVEL=1
+FAST_STAGE_NAME=vpcsc
+FAST_STAGE_DEPS="0-globals 0-bootstrap"
+# FAST_STAGE_OPTIONAL=""
\ No newline at end of file
diff --git a/fast/stages/1-vpcsc/README.md b/fast/stages/1-vpcsc/README.md
index 24e64628d..cc348c903 100644
--- a/fast/stages/1-vpcsc/README.md
+++ b/fast/stages/1-vpcsc/README.md
@@ -91,27 +91,39 @@ It's of course possible to run this stage in isolation, but that's outside the s
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 get from the `stage-links.sh` script in the FAST root folder, passing it a single argument with the local output files folder or GCS output bucket. The following examples demonstrate both cases, and the resulting commands that then need to be copy/pasted and run.
+The commands to link or copy the provider and terraform variable files can be get from the `fast-links.sh` script in the FAST stages folder, passing it a single argument with the local output files folder or GCS output bucket. 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
+../fast-links.sh ~/fast-config
-# copy and paste the following commands for '1-vpcsc'
+# File linking commands for vpc service controls stage
-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 ./
+# provider file
+ln -s ~/fast-config/fast-test-00/providers/1-vpcsc-providers.tf ./
+
+# input files from other stages
+ln -s ~/fast-config/fast-test-00/tfvars/0-globals.auto.tfvars.json ./
+ln -s ~/fast-config/fast-test-00/tfvars/0-bootstrap.auto.tfvars.json ./
+
+# conventional place for stage tfvars (manually created)
+ln -s ~/fast-config/fast-test-00/1-vpcsc.auto.tfvars ./
```
```bash
# the outputs bucket name is in the stage 0 outputs and tfvars file
-../../stage-links.sh gs://xxx-prod-iac-core-outputs-0
+../fast-links.sh gs://xxx-prod-iac-core-outputs-0
-# copy and paste the following commands for '2-security'
+# File linking commands for vpc service controls stage
-gcloud alpha storage cp gs://xxx-prod-iac-core-outputs-0/tfvars/0-globals.auto.tfvars.json ./
-gcloud alpha storage cp gs://xxx-prod-iac-core-outputs-0/tfvars/0-bootstrap.auto.tfvars.json ./
-gcloud alpha storage cp gs://xxx-prod-iac-core-outputs-0/tfvars/1-resman.auto.tfvars.json ./
+# provider file
+gcloud storage cp gs://xxx-prod-iac-core-outputs-0/providers/1-vpcsc-providers.tf ./
+
+# input files from other stages
+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 ./
+
+# conventional place for stage tfvars (manually created)
+gcloud storage cp gs://xxx-prod-iac-core-outputs-0/1-vpcsc.auto.tfvars ./
```
### Impersonating the automation service account
@@ -274,7 +286,7 @@ Some references that might be useful in setting up this stage:
- [VPC SC CSCC requirements](https://cloud.google.com/security-command-center/docs/troubleshooting).
-
+
## Files
diff --git a/fast/stages/2-network-security/.fast-stage.env b/fast/stages/2-network-security/.fast-stage.env
new file mode 100644
index 000000000..6c51deaae
--- /dev/null
+++ b/fast/stages/2-network-security/.fast-stage.env
@@ -0,0 +1,5 @@
+FAST_STAGE_DESCRIPTION="network securoty (optional)"
+FAST_STAGE_LEVEL=2
+FAST_STAGE_NAME=network-security
+FAST_STAGE_DEPS="0-globals 0-bootstrap 1-resman"
+FAST_STAGE_OPTIONAL="2-networking 2-security"
\ No newline at end of file
diff --git a/fast/stages/3-network-security/README.md b/fast/stages/2-network-security/README.md
similarity index 79%
rename from fast/stages/3-network-security/README.md
rename to fast/stages/2-network-security/README.md
index cf52c977c..ebad67615 100644
--- a/fast/stages/3-network-security/README.md
+++ b/fast/stages/2-network-security/README.md
@@ -52,30 +52,48 @@ Before running this stage, you need to make sure you have the correct credential
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.
+The commands to link or copy the provider and terraform variable files can be easily derived from the `fast-links.sh` script in the FAST stages 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
+../fast-links.sh ~/fast-config
-# copy and paste the following commands for '3-network-security'
+# File linking commands for network securoty (optional) stage
-ln -s ~/fast-config/providers/3-network-security-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 ./
+# provider file
+ln -s ~/fast-config/fast-test-00/providers/2-network-security-providers.tf ./
+
+# input files from other stages
+ln -s ~/fast-config/fast-test-00/tfvars/0-globals.auto.tfvars.json ./
+ln -s ~/fast-config/fast-test-00/tfvars/0-bootstrap.auto.tfvars.json ./
+ln -s ~/fast-config/fast-test-00/tfvars/1-resman.auto.tfvars.json ./
+
+# conventional place for stage tfvars (manually created)
+ln -s ~/fast-config/fast-test-00/2-network-security.auto.tfvars ./
+
+# optional files
+ln -s ~/fast-config/fast-test-00/2-networking.auto.tfvars.json ./
+ln -s ~/fast-config/fast-test-00/2-security.auto.tfvars.json ./
```
```bash
-../../stage-links.sh gs://xxx-prod-iac-core-outputs-0
+../fast-links.sh gs://xxx-prod-iac-core-outputs-0
-# copy and paste the following commands for '3-network-security'
+# File linking commands for network securoty (optional) stage
-gcloud storage cp gs://xxx-prod-iac-core-outputs-0/providers/3-network-security-providers.tf ./
+# provider file
+gcloud storage cp gs://xxx-prod-iac-core-outputs-0/providers/2-network-security-providers.tf ./
+
+# input files from other stages
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 ./
+
+# conventional place for stage tfvars (manually created)
+gcloud storage cp gs://xxx-prod-iac-core-outputs-0/2-network-security.auto.tfvars ./
+
+# optional files
+gcloud storage cp gs://xxx-prod-iac-core-outputs-0/2-networking.auto.tfvars.json ./
+gcloud storage cp gs://xxx-prod-iac-core-outputs-0/2-security.auto.tfvars.json ./
```
### Impersonating the automation service account
@@ -143,7 +161,7 @@ You can optionally enable TLS inspection in stage [2-security](../2-security/REA
Ingesting outputs from [stage 2-security](../2-security/README.md), this stage will configure TLS inspection in NGFW Enterprise and will reference the CAs and the trust-configs you created in [stage 2-security](../2-security/README.md).
Make sure the CAs and the trusted configs created for NGFW Enterprise in the [2-security stage](../2-security/README.md) match the region where you defined your zonal firewall endpoints.
-
+
## Files
@@ -152,28 +170,30 @@ Make sure the CAs and the trusted configs created for NGFW Enterprise in the [2-
| [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 | | |
+| [outputs.tf](./outputs.tf) | Module outputs. | | google_storage_bucket_object · local_file |
+| [variables-fast.tf](./variables-fast.tf) | FAST stage interface. | | |
| [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#L72) | Organization details. | object({…}) | ✓ | | 00-globals |
-| [prefix](variables-fast.tf#L82) | 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#L92) | Self link for the shared VPC. | object({…}) | ✓ | | 2-networking |
+| [automation](variables-fast.tf#L19) | Automation resources created by the bootstrap stage. | object({…}) | ✓ | | 0-bootstrap |
+| [billing_account](variables-fast.tf#L27) | 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#L40) | 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#L82) | Organization details. | object({…}) | ✓ | | 00-globals |
+| [prefix](variables-fast.tf#L92) | 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#L102) | 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 |
+| [host_project_ids](variables-fast.tf#L51) | Host project for the shared VPC. | object({…}) | | {} | 2-networking |
| [ngfw_enterprise_config](variables.tf#L35) | NGFW Enterprise configuration. | object({…}) | | {…} | |
-| [ngfw_tls_configs](variables-fast.tf#L52) | The NGFW Enterprise TLS configurations. | object({…}) | | {…} | 2-security |
+| [ngfw_tls_configs](variables-fast.tf#L62) | The NGFW Enterprise TLS configurations. | object({…}) | | {…} | 2-security |
+| [outputs_location](variables.tf#L51) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string | | null | |
## 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. | | |
+| [ngfw_enterprise_endpoint_ids](outputs.tf#L69) | The NGFW Enterprise endpoint ids. | | |
+| [ngfw_enterprise_endpoints_quota_project](outputs.tf#L74) | The NGFW Enterprise endpoints quota project. | | |
diff --git a/fast/stages/3-network-security/data/cidrs.yaml b/fast/stages/2-network-security/data/cidrs.yaml
similarity index 100%
rename from fast/stages/3-network-security/data/cidrs.yaml
rename to fast/stages/2-network-security/data/cidrs.yaml
diff --git a/fast/stages/3-network-security/data/firewall-policy-rules/dev/egress.yaml b/fast/stages/2-network-security/data/firewall-policy-rules/dev/egress.yaml
similarity index 100%
rename from fast/stages/3-network-security/data/firewall-policy-rules/dev/egress.yaml
rename to fast/stages/2-network-security/data/firewall-policy-rules/dev/egress.yaml
diff --git a/fast/stages/3-network-security/data/firewall-policy-rules/dev/ingress.yaml b/fast/stages/2-network-security/data/firewall-policy-rules/dev/ingress.yaml
similarity index 100%
rename from fast/stages/3-network-security/data/firewall-policy-rules/dev/ingress.yaml
rename to fast/stages/2-network-security/data/firewall-policy-rules/dev/ingress.yaml
diff --git a/fast/stages/3-network-security/data/firewall-policy-rules/prod/egress.yaml b/fast/stages/2-network-security/data/firewall-policy-rules/prod/egress.yaml
similarity index 100%
rename from fast/stages/3-network-security/data/firewall-policy-rules/prod/egress.yaml
rename to fast/stages/2-network-security/data/firewall-policy-rules/prod/egress.yaml
diff --git a/fast/stages/3-network-security/data/firewall-policy-rules/prod/ingress.yaml b/fast/stages/2-network-security/data/firewall-policy-rules/prod/ingress.yaml
similarity index 100%
rename from fast/stages/3-network-security/data/firewall-policy-rules/prod/ingress.yaml
rename to fast/stages/2-network-security/data/firewall-policy-rules/prod/ingress.yaml
diff --git a/fast/stages/3-network-security/diagram.png b/fast/stages/2-network-security/diagram.png
similarity index 100%
rename from fast/stages/3-network-security/diagram.png
rename to fast/stages/2-network-security/diagram.png
diff --git a/fast/stages/3-network-security/diagram.svg b/fast/stages/2-network-security/diagram.svg
similarity index 100%
rename from fast/stages/3-network-security/diagram.svg
rename to fast/stages/2-network-security/diagram.svg
diff --git a/fast/stages/3-network-security/main.tf b/fast/stages/2-network-security/main.tf
similarity index 100%
rename from fast/stages/3-network-security/main.tf
rename to fast/stages/2-network-security/main.tf
diff --git a/fast/stages/2-network-security/net-dev.tf b/fast/stages/2-network-security/net-dev.tf
new file mode 100644
index 000000000..b068a8f6c
--- /dev/null
+++ b/fast/stages/2-network-security/net-dev.tf
@@ -0,0 +1,92 @@
+/**
+ * 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.
+
+moved {
+ from = google_network_security_security_profile.dev_sec_profile
+ to = google_network_security_security_profile.dev
+}
+
+resource "google_network_security_security_profile" "dev" {
+ name = "${var.prefix}-dev-sp-0"
+ type = "THREAT_PREVENTION"
+ parent = "organizations/${var.organization.id}"
+ location = "global"
+}
+
+moved {
+ from = google_network_security_security_profile_group.dev_sec_profile_group
+ to = google_network_security_security_profile_group.dev
+}
+
+resource "google_network_security_security_profile_group" "dev" {
+ 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.id, null
+ )
+}
+
+moved {
+ from = google_network_security_firewall_endpoint_association.dev_fw_ep_association
+ to = google_network_security_firewall_endpoint_association.dev
+}
+
+resource "google_network_security_firewall_endpoint_association" "dev" {
+ 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)
+ # If TLS inspection is enabled, link the regional TLS inspection policy
+ tls_inspection_policy = (
+ var.ngfw_tls_configs.tls_enabled
+ # TODO: make this try less verbose and more readable
+ ? try(
+ var.ngfw_tls_configs.tls_ip_ids_by_region.dev[substr(each.value, 0, length(each.value) - 2)],
+ null
+ )
+ : 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 = local.security_profile_group_ids.dev
+ }
+ 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/2-network-security/net-prod.tf b/fast/stages/2-network-security/net-prod.tf
new file mode 100644
index 000000000..74d18ce1b
--- /dev/null
+++ b/fast/stages/2-network-security/net-prod.tf
@@ -0,0 +1,92 @@
+/**
+ * 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.
+
+moved {
+ from = google_network_security_security_profile.prod_sec_profile
+ to = google_network_security_security_profile.prod
+}
+
+resource "google_network_security_security_profile" "prod" {
+ name = "${var.prefix}-prod-sp-0"
+ type = "THREAT_PREVENTION"
+ parent = "organizations/${var.organization.id}"
+ location = "global"
+}
+
+moved {
+ from = google_network_security_security_profile_group.prod_sec_profile_group
+ to = google_network_security_security_profile_group.prod
+}
+
+resource "google_network_security_security_profile_group" "prod" {
+ 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.id, null
+ )
+}
+
+moved {
+ from = google_network_security_firewall_endpoint_association.prod_fw_ep_association
+ to = google_network_security_firewall_endpoint_association.prod
+}
+
+resource "google_network_security_firewall_endpoint_association" "prod" {
+ 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)
+ # If TLS inspection is enabled, link the regional TLS inspection policy
+ tls_inspection_policy = (
+ var.ngfw_tls_configs.tls_enabled
+ # TODO: make this try less verbose and more readable
+ ? try(
+ var.ngfw_tls_configs.tls_ip_ids_by_region.prod[substr(each.value, 0, length(each.value) - 2)],
+ null
+ )
+ : 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 = local.security_profile_group_ids.prod
+ }
+ 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/2-network-security/outputs.tf b/fast/stages/2-network-security/outputs.tf
new file mode 100644
index 000000000..acd5944e2
--- /dev/null
+++ b/fast/stages/2-network-security/outputs.tf
@@ -0,0 +1,77 @@
+/**
+ * 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.
+ */
+
+locals {
+ security_profile_group_ids = {
+ dev = format(
+ "//networksecurity.googleapis.com/%s",
+ try(google_network_security_security_profile_group.dev.id, "")
+ )
+ prod = format(
+ "//networksecurity.googleapis.com/%s",
+ try(google_network_security_security_profile_group.prod.id, "")
+ )
+ }
+ tfvars = {
+ association_ids = {
+ dev = {
+ for k, v in google_network_security_firewall_endpoint_association.dev :
+ k => v.id
+ }
+ prod = {
+ for k, v in google_network_security_firewall_endpoint_association.prod :
+ k => v.id
+ }
+ }
+ endpoint_ids = {
+ for _, v in google_network_security_firewall_endpoint.firewall_endpoint
+ : v.location => v.id
+ }
+ firewall_policy_ids = {
+ dev = module.dev-spoke-firewall-policy.id
+ prod = module.prod-spoke-firewall-policy.id
+ }
+ security_profile_group_ids = local.security_profile_group_ids
+ quota_project_id = module.ngfw-quota-project.id
+ }
+}
+
+# generate tfvars file for subsequent stages
+
+resource "local_file" "tfvars" {
+ for_each = var.outputs_location == null ? {} : { 1 = 1 }
+ file_permission = "0644"
+ filename = "${try(pathexpand(var.outputs_location), "")}/tfvars/2-nsec.auto.tfvars.json"
+ content = jsonencode(local.tfvars)
+}
+
+resource "google_storage_bucket_object" "tfvars" {
+ bucket = var.automation.outputs_bucket
+ name = "tfvars/2-nsec.auto.tfvars.json"
+ content = jsonencode(local.tfvars)
+}
+
+# outputs
+
+output "ngfw_enterprise_endpoint_ids" {
+ description = "The NGFW Enterprise endpoint ids."
+ value = local.tfvars.endpoint_ids
+}
+
+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/schemas/firewall-policy-rules.schema.json b/fast/stages/2-network-security/schemas/firewall-policy-rules.schema.json
similarity index 100%
rename from fast/stages/3-network-security/schemas/firewall-policy-rules.schema.json
rename to fast/stages/2-network-security/schemas/firewall-policy-rules.schema.json
diff --git a/fast/stages/3-network-security/variables-fast.tf b/fast/stages/2-network-security/variables-fast.tf
similarity index 92%
rename from fast/stages/3-network-security/variables-fast.tf
rename to fast/stages/2-network-security/variables-fast.tf
index e6b6de55c..45fb1c0fb 100644
--- a/fast/stages/3-network-security/variables-fast.tf
+++ b/fast/stages/2-network-security/variables-fast.tf
@@ -14,6 +14,16 @@
* limitations under the License.
*/
+# tfdoc:file:description FAST stage interface.
+
+variable "automation" {
+ # tfdoc:variable:source 0-bootstrap
+ description = "Automation resources created by the bootstrap stage."
+ type = object({
+ outputs_bucket = string
+ })
+}
+
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."
diff --git a/fast/stages/3-network-security/variables.tf b/fast/stages/2-network-security/variables.tf
similarity index 87%
rename from fast/stages/3-network-security/variables.tf
rename to fast/stages/2-network-security/variables.tf
index d291577fc..94f00b6fe 100644
--- a/fast/stages/3-network-security/variables.tf
+++ b/fast/stages/2-network-security/variables.tf
@@ -47,3 +47,9 @@ variable "ngfw_enterprise_config" {
]
}
}
+
+variable "outputs_location" {
+ description = "Path where providers and tfvars files for the following stages are written. Leave empty to disable."
+ type = string
+ default = null
+}
diff --git a/fast/stages/2-networking-a-simple/.fast-stage.env b/fast/stages/2-networking-a-simple/.fast-stage.env
new file mode 100644
index 000000000..592fb344a
--- /dev/null
+++ b/fast/stages/2-networking-a-simple/.fast-stage.env
@@ -0,0 +1,5 @@
+FAST_STAGE_DESCRIPTION="networking (simple)"
+FAST_STAGE_LEVEL=2
+FAST_STAGE_NAME=networking
+FAST_STAGE_DEPS="0-globals 0-bootstrap 1-resman"
+FAST_STAGE_OPTIONAL="2-nsec"
\ No newline at end of file
diff --git a/fast/stages/2-networking-a-simple/README.md b/fast/stages/2-networking-a-simple/README.md
index 86c20bde8..574689ef2 100644
--- a/fast/stages/2-networking-a-simple/README.md
+++ b/fast/stages/2-networking-a-simple/README.md
@@ -109,7 +109,7 @@ This is a summary of the main options:
- Cons: additional cost, marginal increase in latency, requires multiple tunnels for full bandwidth
- [NCC](https://cloud.google.com/network-connectivity/docs/network-connectivity-center)
- Pros: full bandwidth with no configurations, no extra latency, transitivity between spokes, feature (PSC transitivity, Private NAT, rich roadmap)
- - Cons: traffic between spokes incour charges, PSA transitivity currently not supported, architectures involving NVAs can't currently easily be implemented
+ - Cons: traffic between spokes incour charges, PSA transitivity currently not supported, architectures involving NVAs can't currently easily be implemented
- [Multi-NIC appliances](https://cloud.google.com/architecture/best-practices-vpc-design#multi-nic) (implemented by [2-networking-b-nva](../2-networking-b-nva/)
- Pros: additional security features (e.g. IPS), potentially better integration with on-prem systems by using the same vendor
- Cons: complex HA/failover setup, limited by VM bandwidth and scale, additional costs for VMs and licenses, out of band management of a critical cloud component
@@ -280,28 +280,46 @@ Before running this stage, you need to make sure you have the correct credential
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.
+The commands to link or copy the provider and terraform variable files can be easily derived from the `fast-links.sh` script in the FAST stages 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
+../fast-links.sh ~/fast-config
-# copy and paste the following commands for '2-networking-*'
+# File linking commands for networking (simple) stage
-ln -s ~/fast-config/providers/2-networking-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 ./
+# provider file
+ln -s ~/fast-config/fast-test-00/providers/2-networking-providers.tf ./
+
+# input files from other stages
+ln -s ~/fast-config/fast-test-00/tfvars/0-globals.auto.tfvars.json ./
+ln -s ~/fast-config/fast-test-00/tfvars/0-bootstrap.auto.tfvars.json ./
+ln -s ~/fast-config/fast-test-00/tfvars/1-resman.auto.tfvars.json ./
+
+# conventional place for stage tfvars (manually created)
+ln -s ~/fast-config/fast-test-00/2-networking.auto.tfvars ./
+
+# optional files
+ln -s ~/fast-config/fast-test-00/2-nsec.auto.tfvars.json ./
```
```bash
-../../stage-links.sh gs://xxx-prod-iac-core-outputs-0
+../fast-links.sh gs://xxx-prod-iac-core-outputs-0
-# copy and paste the following commands for '2-networking-*'
+# File linking commands for networking (simple) stage
+# provider file
gcloud storage cp gs://xxx-prod-iac-core-outputs-0/providers/2-networking-providers.tf ./
+
+# input files from other stages
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 ./
+
+# conventional place for stage tfvars (manually created)
+gcloud storage cp gs://xxx-prod-iac-core-outputs-0/2-networking.auto.tfvars ./
+
+# optional files
+gcloud storage cp gs://xxx-prod-iac-core-outputs-0/2-nsec.auto.tfvars.json ./
```
### Impersonating the automation service account
@@ -452,7 +470,7 @@ VPN configuration also controls BGP advertisements, which requires the following
DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS resolution to Landing through DNS peering, and optionally define a private zone (e.g. `dev.gcp.example.com`) which the landing peers to. To configure DNS for a new environment, copy one of the other environments DNS files [e.g. (dns-dev.tf)](dns-dev.tf) into a new `dns-*.tf` file suffixed with the environment name (e.g. `dns-staging.tf`), and update its content accordingly. Don't forget to add a peering zone from the landing to the newly created environment private zone.
-
+
## Files
@@ -483,21 +501,22 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS
|---|---|:---:|:---:|:---:|:---:|
| [automation](variables-fast.tf#L19) | Automation resources created by the bootstrap stage. | object({…}) | ✓ | | 0-bootstrap |
| [billing_account](variables-fast.tf#L27) | 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#L50) | 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#L60) | Organization details. | object({…}) | ✓ | | 0-bootstrap |
-| [prefix](variables-fast.tf#L70) | Prefix used for resources that need unique names. Use a maximum of 9 chars for organizations, and 11 chars for tenants. | string | ✓ | | 0-bootstrap |
+| [environments](variables-fast.tf#L49) | Environment names. | map(object({…})) | ✓ | | 0-globals |
+| [folder_ids](variables-fast.tf#L66) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. | object({…}) | ✓ | | 1-resman |
+| [prefix](variables-fast.tf#L76) | Prefix used for resources that need unique names. Use a maximum of 9 chars for organizations, and 11 chars for tenants. | string | ✓ | | 0-bootstrap |
| [alert_config](variables.tf#L17) | Configuration for monitoring alerts. | object({…}) | | {…} | |
| [create_test_instances](variables.tf#L42) | Enables the creation of test VMs in each VPC, useful to test and troubleshoot connectivity. | bool | | false | |
+| [custom_roles](variables-fast.tf#L40) | Custom roles defined at the org level, in key => id format. | object({…}) | | null | 0-bootstrap |
| [dns](variables.tf#L48) | DNS configuration. | object({…}) | | {} | |
| [enable_cloud_nat](variables.tf#L58) | Deploy Cloud NAT. | bool | | false | |
| [essential_contacts](variables.tf#L65) | Email used for essential contacts, unset if null. | string | | null | |
| [factories_config](variables.tf#L71) | Configuration for network resource factories. | object({…}) | | {…} | |
-| [fast_features](variables-fast.tf#L40) | Selective control for top-level FAST features. | object({…}) | | {} | 0-0-bootstrap |
| [outputs_location](variables.tf#L92) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string | | null | |
| [psa_ranges](variables.tf#L98) | IP ranges used for Private Service Access (CloudSQL, etc.). | object({…}) | | {} | |
| [regions](variables.tf#L118) | Region definitions. | object({…}) | | {…} | |
-| [service_accounts](variables-fast.tf#L80) | Automation service accounts in name => email format. | object({…}) | | null | 1-resman |
| [spoke_configs](variables.tf#L130) | Spoke connectivity configurations. | object({…}) | | {…} | |
+| [stage_config](variables-fast.tf#L86) | FAST stage configuration. | object({…}) | | {} | 1-resman |
+| [tag_values](variables-fast.tf#L100) | Root-level tag values. | map(string) | | {} | 1-resman |
| [vpn_onprem_primary_config](variables.tf#L199) | VPN gateway configuration for onprem interconnection in the primary region. | object({…}) | | null | |
## Outputs
diff --git a/fast/stages/2-networking-a-simple/main.tf b/fast/stages/2-networking-a-simple/main.tf
index b1b56e72c..1126bc491 100644
--- a/fast/stages/2-networking-a-simple/main.tf
+++ b/fast/stages/2-networking-a-simple/main.tf
@@ -17,23 +17,25 @@
# tfdoc:file:description Networking folder and hierarchical policy.
locals {
- service_accounts = {
- for k, v in coalesce(var.service_accounts, {}) :
- k => "serviceAccount:${v}" if v != null
+ env_tag_values = {
+ for k, v in var.environments :
+ k => var.tag_values["environment/${v.tag_name}"]
}
- spoke_connection = coalesce(
- var.spoke_configs.peering_configs != null ? "peering" : null,
- var.spoke_configs.vpn_configs != null ? "vpn" : null,
- var.spoke_configs.ncc_configs != null ? "ncc" : null,
- )
- stage3_sas_delegated_grants = [
+ has_env_folders = var.folder_ids.networking-dev != null
+ iam_delegated = join(",", formatlist("'%s'", [
"roles/composer.sharedVpcAgent",
"roles/compute.networkUser",
"roles/compute.networkViewer",
"roles/container.hostServiceAgentUser",
"roles/multiclusterservicediscovery.serviceAgent",
"roles/vpcaccess.user",
- ]
+ ]))
+ iam_delegated_principals = try(
+ var.stage_config["networking"].iam_delegated_principals, {}
+ )
+ iam_viewer_principals = try(
+ var.stage_config["networking"].iam_viewer_principals, {}
+ )
# combine all regions from variables and subnets
regions = distinct(concat(
values(var.regions),
@@ -41,13 +43,16 @@ locals {
values(module.landing-vpc.subnet_regions),
values(module.prod-spoke-vpc.subnet_regions),
))
+ spoke_connection = coalesce(
+ var.spoke_configs.peering_configs != null ? "peering" : null,
+ var.spoke_configs.vpn_configs != null ? "vpn" : null,
+ var.spoke_configs.ncc_configs != null ? "ncc" : null,
+ )
}
module "folder" {
source = "../../../modules/folder"
- parent = "organizations/${var.organization.id}"
- name = "Networking"
- folder_create = var.folder_ids.networking == null
+ folder_create = false
id = var.folder_ids.networking
contacts = (
var.essential_contacts == null
diff --git a/fast/stages/2-networking-a-simple/monitoring.tf b/fast/stages/2-networking-a-simple/monitoring.tf
index 0875e3a69..5142ed4fd 100644
--- a/fast/stages/2-networking-a-simple/monitoring.tf
+++ b/fast/stages/2-networking-a-simple/monitoring.tf
@@ -29,4 +29,7 @@ resource "google_monitoring_dashboard" "dashboard" {
for_each = local.dashboards
project = module.landing-project.project_id
dashboard_json = file(each.value)
+ lifecycle {
+ ignore_changes = [dashboard_json]
+ }
}
diff --git a/fast/stages/2-networking-a-simple/net-dev.tf b/fast/stages/2-networking-a-simple/net-dev.tf
index f48917ae7..ad14b3622 100644
--- a/fast/stages/2-networking-a-simple/net-dev.tf
+++ b/fast/stages/2-networking-a-simple/net-dev.tf
@@ -20,55 +20,49 @@ module "dev-spoke-project" {
source = "../../../modules/project"
billing_account = var.billing_account.id
name = "dev-net-spoke-0"
- parent = var.folder_ids.networking-dev
- prefix = var.prefix
- services = concat(
- [
- "container.googleapis.com",
- "compute.googleapis.com",
- "dns.googleapis.com",
- "iap.googleapis.com",
- "networkmanagement.googleapis.com",
- "networksecurity.googleapis.com",
- "servicenetworking.googleapis.com",
- "stackdriver.googleapis.com",
- "vpcaccess.googleapis.com"
- ],
- (
- var.fast_features.gcve
- ? ["vmwareengine.googleapis.com"]
- : []
- )
+ parent = coalesce(
+ var.folder_ids.networking-dev,
+ var.folder_ids.networking
)
+ prefix = var.prefix
+ services = [
+ "container.googleapis.com",
+ "compute.googleapis.com",
+ "dns.googleapis.com",
+ "iap.googleapis.com",
+ "networkmanagement.googleapis.com",
+ "networksecurity.googleapis.com",
+ "servicenetworking.googleapis.com",
+ "stackdriver.googleapis.com",
+ "vpcaccess.googleapis.com",
+ "vmwareengine.googleapis.com"
+ ]
shared_vpc_host_config = {
enabled = true
}
metric_scopes = [module.landing-project.project_id]
+ # optionally delegate a fixed set of IAM roles to selected principals
iam = {
- "roles/dns.admin" = compact([
- try(local.service_accounts.gke-dev, null),
- ])
+ (var.custom_roles.project_iam_viewer) = try(local.iam_viewer_principals["dev"], [])
}
- # allow specific service accounts to assign a set of roles
- iam_bindings = {
- sa_delegated_grants = {
- role = "roles/resourcemanager.projectIamAdmin"
- members = compact([
- try(local.service_accounts.data-platform-dev, null),
- try(local.service_accounts.project-factory, null),
- try(local.service_accounts.project-factory-dev, null),
- try(local.service_accounts.project-factory-prod, null),
- try(local.service_accounts.gke-dev, null),
- ])
- condition = {
- title = "dev_stage3_sa_delegated_grants"
- description = "Development host project delegated grants."
- expression = format(
- "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])",
- join(",", formatlist("'%s'", local.stage3_sas_delegated_grants))
- )
+ iam_bindings = (
+ lookup(local.iam_delegated_principals, "dev", null) == null ? {} : {
+ sa_delegated_grants = {
+ role = "roles/resourcemanager.projectIamAdmin"
+ members = try(local.iam_delegated_principals["dev"], [])
+ condition = {
+ title = "dev_stage3_sa_delegated_grants"
+ description = "${var.environments["dev"].name} host project delegated grants."
+ expression = format(
+ "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])",
+ local.iam_delegated
+ )
+ }
}
}
+ )
+ tag_bindings = local.has_env_folders ? {} : {
+ environment = local.env_tag_values["dev"]
}
}
diff --git a/fast/stages/2-networking-a-simple/net-landing.tf b/fast/stages/2-networking-a-simple/net-landing.tf
index f6ee4a0d5..67e1c9d92 100644
--- a/fast/stages/2-networking-a-simple/net-landing.tf
+++ b/fast/stages/2-networking-a-simple/net-landing.tf
@@ -20,23 +20,25 @@ module "landing-project" {
source = "../../../modules/project"
billing_account = var.billing_account.id
name = "prod-net-landing-0"
- parent = var.folder_ids.networking-prod
- prefix = var.prefix
- services = concat([
+ parent = coalesce(
+ var.folder_ids.networking-prod,
+ var.folder_ids.networking
+ )
+ prefix = var.prefix
+ services = [
"compute.googleapis.com",
"dns.googleapis.com",
"iap.googleapis.com",
+ "networkconnectivity.googleapis.com",
"networkmanagement.googleapis.com",
"stackdriver.googleapis.com"
- ], (
- local.spoke_connection == "ncc"
- ? ["networkconnectivity.googleapis.com"]
- : []
- )
- )
+ ]
shared_vpc_host_config = {
enabled = true
}
+ tag_bindings = local.has_env_folders ? {} : {
+ environment = local.env_tag_values["prod"]
+ }
}
module "landing-vpc" {
diff --git a/fast/stages/2-networking-a-simple/net-prod.tf b/fast/stages/2-networking-a-simple/net-prod.tf
index f2e52abe5..cfef3f425 100644
--- a/fast/stages/2-networking-a-simple/net-prod.tf
+++ b/fast/stages/2-networking-a-simple/net-prod.tf
@@ -20,54 +20,49 @@ module "prod-spoke-project" {
source = "../../../modules/project"
billing_account = var.billing_account.id
name = "prod-net-spoke-0"
- parent = var.folder_ids.networking-prod
- prefix = var.prefix
- services = concat(
- [
- "container.googleapis.com",
- "compute.googleapis.com",
- "dns.googleapis.com",
- "iap.googleapis.com",
- "networkmanagement.googleapis.com",
- "networksecurity.googleapis.com",
- "servicenetworking.googleapis.com",
- "stackdriver.googleapis.com",
- "vpcaccess.googleapis.com"
- ],
- (
- var.fast_features.gcve
- ? ["vmwareengine.googleapis.com"]
- : []
- )
+ parent = coalesce(
+ var.folder_ids.networking-prod,
+ var.folder_ids.networking
)
+ prefix = var.prefix
+ services = [
+ "container.googleapis.com",
+ "compute.googleapis.com",
+ "dns.googleapis.com",
+ "iap.googleapis.com",
+ "networkmanagement.googleapis.com",
+ "networksecurity.googleapis.com",
+ "servicenetworking.googleapis.com",
+ "stackdriver.googleapis.com",
+ "vpcaccess.googleapis.com",
+ "vmwareengine.googleapis.com"
+ ]
shared_vpc_host_config = {
enabled = true
}
metric_scopes = [module.landing-project.project_id]
+ # optionally delegate a fixed set of IAM roles to selected principals
iam = {
- "roles/dns.admin" = compact([
- try(local.service_accounts.gke-prod, null),
- ])
+ (var.custom_roles.project_iam_viewer) = try(local.iam_viewer_principals["prod"], [])
}
- # allow specific service accounts to assign a set of roles
- iam_bindings = {
- sa_delegated_grants = {
- role = "roles/resourcemanager.projectIamAdmin"
- members = compact([
- try(local.service_accounts.data-platform-prod, null),
- try(local.service_accounts.project-factory, null),
- try(local.service_accounts.project-factory-prod, null),
- try(local.service_accounts.gke-prod, null),
- ])
- condition = {
- title = "prod_stage3_sa_delegated_grants"
- description = "Production host project delegated grants."
- expression = format(
- "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])",
- join(",", formatlist("'%s'", local.stage3_sas_delegated_grants))
- )
+ iam_bindings = (
+ lookup(local.iam_delegated_principals, "prod", null) == null ? {} : {
+ sa_delegated_grants = {
+ role = "roles/resourcemanager.projectIamAdmin"
+ members = try(local.iam_delegated_principals["prod"], [])
+ condition = {
+ title = "prod_stage3_sa_delegated_grants"
+ description = "${var.environments["prod"].name} host project delegated grants."
+ expression = format(
+ "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])",
+ local.iam_delegated
+ )
+ }
}
}
+ )
+ tag_bindings = local.has_env_folders ? {} : {
+ environment = local.env_tag_values["prod"]
}
}
diff --git a/fast/stages/2-networking-a-simple/outputs.tf b/fast/stages/2-networking-a-simple/outputs.tf
index 007b7948c..e38837c7f 100644
--- a/fast/stages/2-networking-a-simple/outputs.tf
+++ b/fast/stages/2-networking-a-simple/outputs.tf
@@ -26,9 +26,9 @@ locals {
prod-spoke-0 = module.prod-spoke-project.number
}
subnet_self_links = {
- prod-landing = module.landing-vpc.subnet_self_links
- dev-spoke-0 = module.dev-spoke-vpc.subnet_self_links
- prod-spoke-0 = module.prod-spoke-vpc.subnet_self_links
+ prod-landing = module.landing-vpc.subnet_ids
+ dev-spoke-0 = module.dev-spoke-vpc.subnet_ids
+ prod-spoke-0 = module.prod-spoke-vpc.subnet_ids
}
subnet_proxy_only_self_links = {
prod-landing = {
@@ -61,9 +61,9 @@ locals {
vpc_self_links = local.vpc_self_links
}
vpc_self_links = {
- prod-landing = module.landing-vpc.self_link
- dev-spoke-0 = module.dev-spoke-vpc.self_link
- prod-spoke-0 = module.prod-spoke-vpc.self_link
+ prod-landing = module.landing-vpc.id
+ dev-spoke-0 = module.dev-spoke-vpc.id
+ prod-spoke-0 = module.prod-spoke-vpc.id
}
}
diff --git a/fast/stages/2-networking-a-simple/variables-fast.tf b/fast/stages/2-networking-a-simple/variables-fast.tf
index e9c032671..dd7f96bf5 100644
--- a/fast/stages/2-networking-a-simple/variables-fast.tf
+++ b/fast/stages/2-networking-a-simple/variables-fast.tf
@@ -37,33 +37,39 @@ variable "billing_account" {
}
}
-variable "fast_features" {
- # tfdoc:variable:source 0-0-bootstrap
- description = "Selective control for top-level FAST features."
+variable "custom_roles" {
+ # tfdoc:variable:source 0-bootstrap
+ description = "Custom roles defined at the org level, in key => id format."
type = object({
- gcve = optional(bool, false)
+ project_iam_viewer = string
})
- default = {}
+ default = null
+}
+
+variable "environments" {
+ # tfdoc:variable:source 0-globals
+ description = "Environment names."
+ type = map(object({
+ name = string
+ tag_name = string
+ is_default = optional(bool, false)
+ }))
nullable = false
+ validation {
+ condition = anytrue([
+ for k, v in var.environments : v.is_default == true
+ ])
+ error_message = "At least one environment should be marked as default."
+ }
}
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."
+ description = "Folders to be used for the networking resources in folders/nnnnnnnnnnn format."
type = object({
networking = string
- networking-dev = string
- networking-prod = string
- })
-}
-
-variable "organization" {
- # tfdoc:variable:source 0-bootstrap
- description = "Organization details."
- type = object({
- domain = string
- id = number
- customer_id = string
+ networking-dev = optional(string)
+ networking-prod = optional(string)
})
}
@@ -77,18 +83,23 @@ variable "prefix" {
}
}
-variable "service_accounts" {
+variable "stage_config" {
# tfdoc:variable:source 1-resman
- description = "Automation service accounts in name => email format."
+ description = "FAST stage configuration."
type = object({
- data-platform-dev = string
- data-platform-prod = string
- gke-dev = string
- gke-prod = string
- project-factory = string
- project-factory-dev = string
- project-factory-prod = string
+ networking = optional(object({
+ short_name = optional(string)
+ iam_delegated_principals = optional(map(list(string)), {})
+ iam_viewer_principals = optional(map(list(string)), {})
+ }), {})
})
- default = null
+ default = {}
+ nullable = false
}
+variable "tag_values" {
+ # tfdoc:variable:source 1-resman
+ description = "Root-level tag values."
+ type = map(string)
+ default = {}
+}
diff --git a/fast/stages/2-networking-b-nva/.fast-stage.env b/fast/stages/2-networking-b-nva/.fast-stage.env
new file mode 100644
index 000000000..3e8057f51
--- /dev/null
+++ b/fast/stages/2-networking-b-nva/.fast-stage.env
@@ -0,0 +1,5 @@
+FAST_STAGE_DESCRIPTION="networking (nva)"
+FAST_STAGE_LEVEL=2
+FAST_STAGE_NAME=networking
+FAST_STAGE_DEPS="0-globals 0-bootstrap 1-resman"
+FAST_STAGE_OPTIONAL="2-nsec"
\ No newline at end of file
diff --git a/fast/stages/2-networking-b-nva/README.md b/fast/stages/2-networking-b-nva/README.md
index 24f3e29ae..c8f9b78bb 100644
--- a/fast/stages/2-networking-b-nva/README.md
+++ b/fast/stages/2-networking-b-nva/README.md
@@ -82,6 +82,11 @@ The final number of subnets, and their IP addressing will depend on the user-spe
## Design overview and choices
### Deployment models
+
+<<<<<<< HEAD
+
+=======
+>>>>>>> origin/master
This stage support three different deployment models that can be controlled by `var.network_mode`. The stage deploys networking resources in two different regions and supports both regional and multi-regional VPCs. Depending on the selected deployment model different routing strategies and NVAs failover modes can be implemented.
- **Simple NVA**: This network mode deploys multi-regional VPCs, the network appliances are configured behind a "ILB Sandwitch" (two different network passthrough internal load balancers on each of `dmz` and `landing` VPCs), with static routes sending traffic for specific destinations to specific network appliances group through the load balancer.
@@ -348,28 +353,46 @@ Note that by default the "Simple NVA" architecture is deployed - in order to ena
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.
+The commands to link or copy the provider and terraform variable files can be easily derived from the `fast-links.sh` script in the FAST stages 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
+../fast-links.sh ~/fast-config
-# copy and paste the following commands for '2-networking-*'
+# File linking commands for networking (nva) stage
-ln -s ~/fast-config/providers/2-networking-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 ./
+# provider file
+ln -s ~/fast-config/fast-test-00/providers/2-networking-providers.tf ./
+
+# input files from other stages
+ln -s ~/fast-config/fast-test-00/tfvars/0-globals.auto.tfvars.json ./
+ln -s ~/fast-config/fast-test-00/tfvars/0-bootstrap.auto.tfvars.json ./
+ln -s ~/fast-config/fast-test-00/tfvars/1-resman.auto.tfvars.json ./
+
+# conventional place for stage tfvars (manually created)
+ln -s ~/fast-config/fast-test-00/2-networking.auto.tfvars ./
+
+# optional files
+ln -s ~/fast-config/fast-test-00/2-nsec.auto.tfvars.json ./
```
```bash
-../../stage-links.sh gs://xxx-prod-iac-core-outputs-0
+../fast-links.sh gs://xxx-prod-iac-core-outputs-0
-# copy and paste the following commands for '2-networking-*'
+# File linking commands for networking (nva) stage
+# provider file
gcloud storage cp gs://xxx-prod-iac-core-outputs-0/providers/2-networking-providers.tf ./
+
+# input files from other stages
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 ./
+
+# conventional place for stage tfvars (manually created)
+gcloud storage cp gs://xxx-prod-iac-core-outputs-0/2-networking.auto.tfvars ./
+
+# optional files
+gcloud storage cp gs://xxx-prod-iac-core-outputs-0/2-nsec.auto.tfvars.json ./
```
### Impersonating the automation service account
@@ -506,7 +529,7 @@ If NCC-RA is enabled, you can configure the NVAs deployed updating the sample BG
DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS resolution to Landing through DNS peering, and optionally define a private zone (e.g. `dev.gcp.example.com`) which the landing peers to. To configure DNS for a new environment, copy one of the other environments DNS files [e.g. (dns-dev.tf)](dns-dev.tf) into a new `dns-*.tf` file suffixed with the environment name (e.g. `dns-staging.tf`), and update its content accordingly. Don't forget to add a peering zone from the landing to the newly created environment private zone.
-
+
## Files
@@ -529,7 +552,7 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS
| [outputs.tf](./outputs.tf) | Module outputs. | | google_storage_bucket_object · local_file |
| [regions.tf](./regions.tf) | Compute short names for regions. | | |
| [test-resources.tf](./test-resources.tf) | Temporary instances for testing | | |
-| [variables-fast.tf](./variables-fast.tf) | None | | |
+| [variables-fast.tf](./variables-fast.tf) | FAST stage interface. | | |
| [variables.tf](./variables.tf) | Module variables. | | |
| [vpn-onprem.tf](./vpn-onprem.tf) | VPN between landing and onprem. | net-vpn-ha | |
@@ -537,24 +560,25 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS
| name | description | type | required | default | producer |
|---|---|:---:|:---:|:---:|:---:|
-| [automation](variables-fast.tf#L17) | Automation resources created by the bootstrap stage. | object({…}) | ✓ | | 0-bootstrap |
-| [billing_account](variables-fast.tf#L25) | 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#L48) | 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#L58) | Organization details. | object({…}) | ✓ | | 0-bootstrap |
-| [prefix](variables-fast.tf#L68) | Prefix used for resources that need unique names. Use a maximum of 9 chars for organizations, and 11 chars for tenants. | string | ✓ | | 0-bootstrap |
+| [automation](variables-fast.tf#L19) | Automation resources created by the bootstrap stage. | object({…}) | ✓ | | 0-bootstrap |
+| [billing_account](variables-fast.tf#L27) | Billing account id. If billing account is not part of the same org set `is_org_level` to false. | object({…}) | ✓ | | 0-bootstrap |
+| [environments](variables-fast.tf#L49) | Environment names. | map(object({…})) | ✓ | | 0-globals |
+| [folder_ids](variables-fast.tf#L66) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. | object({…}) | ✓ | | 1-resman |
+| [prefix](variables-fast.tf#L76) | Prefix used for resources that need unique names. Use a maximum of 9 chars for organizations, and 11 chars for tenants. | string | ✓ | | 0-bootstrap |
| [alert_config](variables.tf#L17) | Configuration for monitoring alerts. | object({…}) | | {…} | |
| [create_test_instances](variables.tf#L42) | Enables the creation of test VMs in each VPC, useful to test and troubleshoot connectivity. | bool | | false | |
+| [custom_roles](variables-fast.tf#L40) | Custom roles defined at the org level, in key => id format. | object({…}) | | null | 0-bootstrap |
| [dns](variables.tf#L48) | DNS configuration. | object({…}) | | {} | |
| [enable_cloud_nat](variables.tf#L58) | Deploy Cloud NAT. | bool | | false | |
| [essential_contacts](variables.tf#L65) | Email used for essential contacts, unset if null. | string | | null | |
| [factories_config](variables.tf#L71) | Configuration for network resource factories. | object({…}) | | {…} | |
-| [fast_features](variables-fast.tf#L38) | Selective control for top-level FAST features. | object({…}) | | {} | 0-0-bootstrap |
| [gcp_ranges](variables.tf#L92) | GCP address ranges in name => range format. | map(string) | | {…} | |
| [network_mode](variables.tf#L109) | Selection of the network design to deploy. | string | | "simple" | |
| [outputs_location](variables.tf#L120) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string | | null | |
| [psa_ranges](variables.tf#L126) | IP ranges used for Private Service Access (e.g. CloudSQL). Ranges is in name => range format. | object({…}) | | {} | |
| [regions](variables.tf#L146) | Region definitions. | object({…}) | | {…} | |
-| [service_accounts](variables-fast.tf#L78) | Automation service accounts in name => email format. | object({…}) | | null | 1-resman |
+| [stage_config](variables-fast.tf#L86) | FAST stage configuration. | object({…}) | | {} | 1-resman |
+| [tag_values](variables-fast.tf#L100) | Root-level tag values. | map(string) | | {} | 1-resman |
| [vpn_onprem_primary_config](variables.tf#L158) | VPN gateway configuration for onprem interconnection in the primary region. | object({…}) | | null | |
| [vpn_onprem_secondary_config](variables.tf#L201) | VPN gateway configuration for onprem interconnection in the secondary region. | object({…}) | | null | |
diff --git a/fast/stages/2-networking-b-nva/main.tf b/fast/stages/2-networking-b-nva/main.tf
index 44e44ee7b..179ddbfaf 100644
--- a/fast/stages/2-networking-b-nva/main.tf
+++ b/fast/stages/2-networking-b-nva/main.tf
@@ -17,6 +17,37 @@
# tfdoc:file:description Networking folder and hierarchical policy.
locals {
+ env_tag_values = {
+ for k, v in var.environments : k => var.tag_values["environment/${v.tag_name}"]
+ }
+ has_env_folders = var.folder_ids.networking-dev != null
+ iam_delegated = join(",", formatlist("'%s'", [
+ "roles/composer.sharedVpcAgent",
+ "roles/compute.networkUser",
+ "roles/compute.networkViewer",
+ "roles/container.hostServiceAgentUser",
+ "roles/multiclusterservicediscovery.serviceAgent",
+ "roles/vpcaccess.user",
+ ]))
+ iam_delegated_principals = try(
+ var.stage_config["networking"].iam_delegated_principals, {}
+ )
+ iam_viewer_principals = try(
+ var.stage_config["networking"].iam_viewer_principals, {}
+ )
+ # select the NVA ILB as next hop for spoke VPC routing depending on net mode
+ nva_load_balancers = (var.network_mode == "ncc_ra") ? null : {
+ primary = (
+ var.network_mode == "simple"
+ ? local._simple_nva_lb.primary
+ : local._regional_nva_lb.primary
+ )
+ secondary = (
+ var.network_mode == "simple"
+ ? local._simple_nva_lb.secondary
+ : local._regional_nva_lb.secondary
+ )
+ }
nva_zones = ["b", "c"]
# combine all regions from variables and subnets
regions = distinct(concat(
@@ -26,25 +57,11 @@ locals {
values(module.dmz-vpc.subnet_regions),
values(module.prod-spoke-vpc.subnet_regions),
))
- service_accounts = {
- for k, v in coalesce(var.service_accounts, {}) :
- k => "serviceAccount:${v}" if v != null
- }
- stage3_sas_delegated_grants = [
- "roles/composer.sharedVpcAgent",
- "roles/compute.networkUser",
- "roles/compute.networkViewer",
- "roles/container.hostServiceAgentUser",
- "roles/multiclusterservicediscovery.serviceAgent",
- "roles/vpcaccess.user",
- ]
}
module "folder" {
source = "../../../modules/folder"
- parent = "organizations/${var.organization.id}"
- name = "Networking"
- folder_create = var.folder_ids.networking == null
+ folder_create = false
id = var.folder_ids.networking
contacts = (
var.essential_contacts == null
diff --git a/fast/stages/2-networking-b-nva/monitoring.tf b/fast/stages/2-networking-b-nva/monitoring.tf
index be3a47faa..95bb097ae 100644
--- a/fast/stages/2-networking-b-nva/monitoring.tf
+++ b/fast/stages/2-networking-b-nva/monitoring.tf
@@ -29,4 +29,7 @@ resource "google_monitoring_dashboard" "dashboard" {
for_each = local.dashboards
project = module.landing-project.project_id
dashboard_json = file(each.value)
+ lifecycle {
+ ignore_changes = [dashboard_json]
+ }
}
diff --git a/fast/stages/2-networking-b-nva/net-dev.tf b/fast/stages/2-networking-b-nva/net-dev.tf
index 858a4d25b..eec1d5586 100644
--- a/fast/stages/2-networking-b-nva/net-dev.tf
+++ b/fast/stages/2-networking-b-nva/net-dev.tf
@@ -20,9 +20,12 @@ module "dev-spoke-project" {
source = "../../../modules/project"
billing_account = var.billing_account.id
name = "dev-net-spoke-0"
- parent = var.folder_ids.networking-dev
- prefix = var.prefix
- services = concat([
+ parent = coalesce(
+ var.folder_ids.networking-dev,
+ var.folder_ids.networking
+ )
+ prefix = var.prefix
+ services = [
"container.googleapis.com",
"compute.googleapis.com",
"dns.googleapis.com",
@@ -32,37 +35,33 @@ module "dev-spoke-project" {
"servicenetworking.googleapis.com",
"stackdriver.googleapis.com",
"vpcaccess.googleapis.com"
- ],
- )
+ ]
shared_vpc_host_config = {
enabled = true
}
metric_scopes = [module.landing-project.project_id]
+ # optionally delegate a fixed set of IAM roles to selected principals
iam = {
- "roles/dns.admin" = compact([
- try(local.service_accounts.gke-dev, null),
- ])
+ (var.custom_roles.project_iam_viewer) = try(local.iam_viewer_principals["dev"], [])
}
- # allow specific service accounts to assign a set of roles
- iam_bindings = {
- sa_delegated_grants = {
- role = "roles/resourcemanager.projectIamAdmin"
- members = compact([
- try(local.service_accounts.data-platform-dev, null),
- try(local.service_accounts.project-factory, null),
- try(local.service_accounts.project-factory-dev, null),
- try(local.service_accounts.project-factory-prod, null),
- try(local.service_accounts.gke-dev, null),
- ])
- condition = {
- title = "dev_stage3_sa_delegated_grants"
- description = "Development host project delegated grants."
- expression = format(
- "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])",
- join(",", formatlist("'%s'", local.stage3_sas_delegated_grants))
- )
+ iam_bindings = (
+ lookup(local.iam_delegated_principals, "dev", null) == null ? {} : {
+ sa_delegated_grants = {
+ role = "roles/resourcemanager.projectIamAdmin"
+ members = try(local.iam_delegated_principals["dev"], [])
+ condition = {
+ title = "dev_stage3_sa_delegated_grants"
+ description = "${var.environments["dev"].name} host project delegated grants."
+ expression = format(
+ "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])",
+ local.iam_delegated
+ )
+ }
}
}
+ )
+ tag_bindings = local.has_env_folders ? {} : {
+ environment = local.env_tag_values["dev"]
}
}
diff --git a/fast/stages/2-networking-b-nva/net-landing.tf b/fast/stages/2-networking-b-nva/net-landing.tf
index 095260ae5..5bd65e0b8 100644
--- a/fast/stages/2-networking-b-nva/net-landing.tf
+++ b/fast/stages/2-networking-b-nva/net-landing.tf
@@ -20,29 +20,26 @@ module "landing-project" {
source = "../../../modules/project"
billing_account = var.billing_account.id
name = "prod-net-landing-0"
- parent = var.folder_ids.networking-prod
- prefix = var.prefix
- services = concat([
+ parent = coalesce(
+ var.folder_ids.networking-prod,
+ var.folder_ids.networking
+ )
+ prefix = var.prefix
+ services = [
"compute.googleapis.com",
"dns.googleapis.com",
"iap.googleapis.com",
+ "networkconnectivity.googleapis.com",
"networkmanagement.googleapis.com",
"stackdriver.googleapis.com",
- ],
- (
- var.network_mode == "ncc_ra"
- ? ["networkconnectivity.googleapis.com"]
- : []
- ),
- (
- var.fast_features.gcve
- ? ["vmwareengine.googleapis.com"]
- : []
- )
- )
+ "vmwareengine.googleapis.com"
+ ]
shared_vpc_host_config = {
enabled = true
}
+ tag_bindings = local.has_env_folders ? {} : {
+ environment = local.env_tag_values["prod"]
+ }
}
# DMZ (untrusted) VPC
diff --git a/fast/stages/2-networking-b-nva/net-prod.tf b/fast/stages/2-networking-b-nva/net-prod.tf
index a97ffa066..bb59e58a4 100644
--- a/fast/stages/2-networking-b-nva/net-prod.tf
+++ b/fast/stages/2-networking-b-nva/net-prod.tf
@@ -15,29 +15,17 @@
*/
# tfdoc:file:description Production spoke VPC and related resources.
-locals {
- _simple_nva_lb = {
- primary = (var.network_mode == "simple" ? module.ilb-nva-landing["primary"].forwarding_rule_addresses[""] : null)
- secondary = (var.network_mode == "simple" ? module.ilb-nva-landing["secondary"].forwarding_rule_addresses[""] : null)
- }
- _regional_nva_lb = {
- primary = (var.network_mode == "regional_vpc" ? module.ilb-regional-nva-landing["primary"].forwarding_rule_addresses[""] : null)
- secondary = (var.network_mode == "regional_vpc" ? module.ilb-regional-nva-landing["secondary"].forwarding_rule_addresses[""] : null)
- }
- # On the basis of the network modes selects the NVA internal load balancer as next hop for spoke VPC routing
- nva_load_balancers = (var.network_mode == "ncc_ra") ? null : {
- primary = (var.network_mode == "simple" ? local._simple_nva_lb.primary : local._regional_nva_lb.primary)
- secondary = (var.network_mode == "simple" ? local._simple_nva_lb.secondary : local._regional_nva_lb.secondary)
- }
-}
module "prod-spoke-project" {
source = "../../../modules/project"
billing_account = var.billing_account.id
name = "prod-net-spoke-0"
- parent = var.folder_ids.networking-prod
- prefix = var.prefix
- services = concat([
+ parent = coalesce(
+ var.folder_ids.networking-prod,
+ var.folder_ids.networking
+ )
+ prefix = var.prefix
+ services = [
"container.googleapis.com",
"compute.googleapis.com",
"dns.googleapis.com",
@@ -47,36 +35,33 @@ module "prod-spoke-project" {
"servicenetworking.googleapis.com",
"stackdriver.googleapis.com",
"vpcaccess.googleapis.com"
- ]
- )
+ ]
shared_vpc_host_config = {
enabled = true
}
metric_scopes = [module.landing-project.project_id]
+ # optionally delegate a fixed set of IAM roles to selected principals
iam = {
- "roles/dns.admin" = compact([
- try(local.service_accounts.gke-prod, null),
- ])
+ (var.custom_roles.project_iam_viewer) = try(local.iam_viewer_principals["prod"], [])
}
- # allow specific service accounts to assign a set of roles
- iam_bindings = {
- sa_delegated_grants = {
- role = "roles/resourcemanager.projectIamAdmin"
- members = compact([
- try(local.service_accounts.data-platform-prod, null),
- try(local.service_accounts.project-factory, null),
- try(local.service_accounts.project-factory-prod, null),
- try(local.service_accounts.gke-prod, null),
- ])
- condition = {
- title = "prod_stage3_sa_delegated_grants"
- description = "Production host project delegated grants."
- expression = format(
- "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])",
- join(",", formatlist("'%s'", local.stage3_sas_delegated_grants))
- )
+ iam_bindings = (
+ lookup(local.iam_delegated_principals, "prod", null) == null ? {} : {
+ sa_delegated_grants = {
+ role = "roles/resourcemanager.projectIamAdmin"
+ members = try(local.iam_delegated_principals["prod"], [])
+ condition = {
+ title = "prod_stage3_sa_delegated_grants"
+ description = "${var.environments["prod"].name} host project delegated grants."
+ expression = format(
+ "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])",
+ local.iam_delegated
+ )
+ }
}
}
+ )
+ tag_bindings = local.has_env_folders ? {} : {
+ environment = local.env_tag_values["prod"]
}
}
diff --git a/fast/stages/2-networking-b-nva/nva-regional-vpc.tf b/fast/stages/2-networking-b-nva/nva-regional-vpc.tf
index d711d1775..95dc28f9c 100644
--- a/fast/stages/2-networking-b-nva/nva-regional-vpc.tf
+++ b/fast/stages/2-networking-b-nva/nva-regional-vpc.tf
@@ -15,6 +15,18 @@
*/
locals {
+ _regional_nva_lb = {
+ primary = (
+ var.network_mode == "regional_vpc"
+ ? module.ilb-regional-nva-landing["primary"].forwarding_rule_addresses[""]
+ : null
+ )
+ secondary = (
+ var.network_mode == "regional_vpc"
+ ? module.ilb-regional-nva-landing["secondary"].forwarding_rule_addresses[""]
+ : null
+ )
+ }
# routing_config should be aligned to the NVA network interfaces - i.e.
# local.simple_routing_config[0] sets up the first interface, and so on.
regional_vpc_routing_config = {
diff --git a/fast/stages/2-networking-b-nva/nva-simple.tf b/fast/stages/2-networking-b-nva/nva-simple.tf
index 22e20f60b..ab794fd2d 100644
--- a/fast/stages/2-networking-b-nva/nva-simple.tf
+++ b/fast/stages/2-networking-b-nva/nva-simple.tf
@@ -15,6 +15,18 @@
*/
locals {
+ _simple_nva_lb = {
+ primary = (
+ var.network_mode == "simple"
+ ? module.ilb-nva-landing["primary"].forwarding_rule_addresses[""]
+ : null
+ )
+ secondary = (
+ var.network_mode == "simple"
+ ? module.ilb-nva-landing["secondary"].forwarding_rule_addresses[""]
+ : null
+ )
+ }
# routing_config should be aligned to the NVA network interfaces - i.e.
# local.simple_routing_config[0] sets up the first interface, and so on.
simple_routing_config = [
diff --git a/fast/stages/2-networking-b-nva/outputs.tf b/fast/stages/2-networking-b-nva/outputs.tf
index cc16c4e84..a143a2415 100644
--- a/fast/stages/2-networking-b-nva/outputs.tf
+++ b/fast/stages/2-networking-b-nva/outputs.tf
@@ -26,14 +26,14 @@ locals {
prod-spoke-0 = module.prod-spoke-project.number
}
subnet_self_links = merge({
- prod-dmz = module.dmz-vpc.subnet_self_links
- prod-landing = module.landing-vpc.subnet_self_links
- dev-spoke-0 = module.dev-spoke-vpc.subnet_self_links
- prod-spoke-0 = module.prod-spoke-vpc.subnet_self_links
+ prod-dmz = module.dmz-vpc.subnet_ids
+ prod-landing = module.landing-vpc.subnet_ids
+ dev-spoke-0 = module.dev-spoke-vpc.subnet_ids
+ prod-spoke-0 = module.prod-spoke-vpc.subnet_ids
},
(var.network_mode == "regional_vpc") ? {
- regional-vpc-primary-0 = module.regional-primary-vpc[0].subnet_self_links
- regional-vpc-secondary-0 = module.regional-secondary-vpc[0].subnet_self_links
+ regional-vpc-primary-0 = module.regional-primary-vpc[0].subnet_ids
+ regional-vpc-secondary-0 = module.regional-secondary-vpc[0].subnet_ids
} : {}
)
subnet_proxy_only_self_links = {
@@ -74,14 +74,14 @@ locals {
}
vpc_self_links = merge(
{
- prod-landing = module.landing-vpc.self_link
- prod-dmz = module.dmz-vpc.self_link
- dev-spoke-0 = module.dev-spoke-vpc.self_link
- prod-spoke-0 = module.prod-spoke-vpc.self_link
+ prod-landing = module.landing-vpc.id
+ prod-dmz = module.dmz-vpc.id
+ dev-spoke-0 = module.dev-spoke-vpc.id
+ prod-spoke-0 = module.prod-spoke-vpc.id
},
(var.network_mode == "regional_vpc") ? {
- regional-vpc-primary-0 = module.regional-primary-vpc[0].self_link
- regional-vpc-secondary-0 = module.regional-secondary-vpc[0].self_link
+ regional-vpc-primary-0 = module.regional-primary-vpc[0].id
+ regional-vpc-secondary-0 = module.regional-secondary-vpc[0].id
} : {}
)
}
diff --git a/fast/stages/2-networking-b-nva/variables-fast.tf b/fast/stages/2-networking-b-nva/variables-fast.tf
index bdb3ae8d7..dd7f96bf5 100644
--- a/fast/stages/2-networking-b-nva/variables-fast.tf
+++ b/fast/stages/2-networking-b-nva/variables-fast.tf
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+# tfdoc:file:description FAST stage interface.
+
variable "automation" {
# tfdoc:variable:source 0-bootstrap
description = "Automation resources created by the bootstrap stage."
@@ -35,33 +37,39 @@ variable "billing_account" {
}
}
-variable "fast_features" {
- # tfdoc:variable:source 0-0-bootstrap
- description = "Selective control for top-level FAST features."
+variable "custom_roles" {
+ # tfdoc:variable:source 0-bootstrap
+ description = "Custom roles defined at the org level, in key => id format."
type = object({
- gcve = optional(bool, false)
+ project_iam_viewer = string
})
- default = {}
+ default = null
+}
+
+variable "environments" {
+ # tfdoc:variable:source 0-globals
+ description = "Environment names."
+ type = map(object({
+ name = string
+ tag_name = string
+ is_default = optional(bool, false)
+ }))
nullable = false
+ validation {
+ condition = anytrue([
+ for k, v in var.environments : v.is_default == true
+ ])
+ error_message = "At least one environment should be marked as default."
+ }
}
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."
+ description = "Folders to be used for the networking resources in folders/nnnnnnnnnnn format."
type = object({
networking = string
- networking-dev = string
- networking-prod = string
- })
-}
-
-variable "organization" {
- # tfdoc:variable:source 0-bootstrap
- description = "Organization details."
- type = object({
- domain = string
- id = number
- customer_id = string
+ networking-dev = optional(string)
+ networking-prod = optional(string)
})
}
@@ -75,17 +83,23 @@ variable "prefix" {
}
}
-variable "service_accounts" {
+variable "stage_config" {
# tfdoc:variable:source 1-resman
- description = "Automation service accounts in name => email format."
+ description = "FAST stage configuration."
type = object({
- data-platform-dev = string
- data-platform-prod = string
- gke-dev = string
- gke-prod = string
- project-factory = string
- project-factory-dev = string
- project-factory-prod = string
+ networking = optional(object({
+ short_name = optional(string)
+ iam_delegated_principals = optional(map(list(string)), {})
+ iam_viewer_principals = optional(map(list(string)), {})
+ }), {})
})
- default = null
+ default = {}
+ nullable = false
+}
+
+variable "tag_values" {
+ # tfdoc:variable:source 1-resman
+ description = "Root-level tag values."
+ type = map(string)
+ default = {}
}
diff --git a/fast/stages/2-networking-c-separate-envs/.fast-stage.env b/fast/stages/2-networking-c-separate-envs/.fast-stage.env
new file mode 100644
index 000000000..0c1d6b578
--- /dev/null
+++ b/fast/stages/2-networking-c-separate-envs/.fast-stage.env
@@ -0,0 +1,5 @@
+FAST_STAGE_DESCRIPTION="networking (separate environments)"
+FAST_STAGE_LEVEL=2
+FAST_STAGE_NAME=networking
+FAST_STAGE_DEPS="0-globals 0-bootstrap 1-resman"
+FAST_STAGE_OPTIONAL="2-nsec"
\ No newline at end of file
diff --git a/fast/stages/2-networking-c-separate-envs/README.md b/fast/stages/2-networking-c-separate-envs/README.md
index 66cf2c02c..71d8487c6 100644
--- a/fast/stages/2-networking-c-separate-envs/README.md
+++ b/fast/stages/2-networking-c-separate-envs/README.md
@@ -175,28 +175,46 @@ Before running this stage, you need to make sure you have the correct credential
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.
+The commands to link or copy the provider and terraform variable files can be easily derived from the `fast-links.sh` script in the FAST stages 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
+../fast-links.sh ~/fast-config
-# copy and paste the following commands for '2-networking-*'
+# File linking commands for networking (separate environments) stage
-ln -s ~/fast-config/providers/2-networking-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 ./
+# provider file
+ln -s ~/fast-config/fast-test-00/providers/2-networking-providers.tf ./
+
+# input files from other stages
+ln -s ~/fast-config/fast-test-00/tfvars/0-globals.auto.tfvars.json ./
+ln -s ~/fast-config/fast-test-00/tfvars/0-bootstrap.auto.tfvars.json ./
+ln -s ~/fast-config/fast-test-00/tfvars/1-resman.auto.tfvars.json ./
+
+# conventional place for stage tfvars (manually created)
+ln -s ~/fast-config/fast-test-00/2-networking.auto.tfvars ./
+
+# optional files
+ln -s ~/fast-config/fast-test-00/2-nsec.auto.tfvars.json ./
```
```bash
-../../stage-links.sh gs://xxx-prod-iac-core-outputs-0
+../fast-links.sh gs://xxx-prod-iac-core-outputs-0
-# copy and paste the following commands for '2-networking-*'
+# File linking commands for networking (separate environments) stage
+# provider file
gcloud storage cp gs://xxx-prod-iac-core-outputs-0/providers/2-networking-providers.tf ./
+
+# input files from other stages
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 ./
+
+# conventional place for stage tfvars (manually created)
+gcloud storage cp gs://xxx-prod-iac-core-outputs-0/2-networking.auto.tfvars ./
+
+# optional files
+gcloud storage cp gs://xxx-prod-iac-core-outputs-0/2-nsec.auto.tfvars.json ./
```
### Impersonating the automation service account
@@ -316,7 +334,7 @@ Regions are defined via the `regions` variable which sets up a mapping between t
- change the values of the mappings in the `regions` variable to the regions you are going to use
- change the regions in the factory subnet files in the `data` folder
-
+
## Files
@@ -332,7 +350,7 @@ Regions are defined via the `regions` variable which sets up a mapping between t
| [outputs.tf](./outputs.tf) | Module outputs. | | google_storage_bucket_object · local_file |
| [regions.tf](./regions.tf) | Compute short names for regions. | | |
| [test-resources.tf](./test-resources.tf) | Temporary instances for testing | compute-vm | |
-| [variables-fast.tf](./variables-fast.tf) | None | | |
+| [variables-fast.tf](./variables-fast.tf) | FAST stage interface. | | |
| [variables.tf](./variables.tf) | Module variables. | | |
| [vpn-onprem.tf](./vpn-onprem.tf) | VPN between landing and onprem. | net-vpn-ha | |
@@ -340,21 +358,22 @@ Regions are defined via the `regions` variable which sets up a mapping between t
| name | description | type | required | default | producer |
|---|---|:---:|:---:|:---:|:---:|
-| [automation](variables-fast.tf#L17) | Automation resources created by the bootstrap stage. | object({…}) | ✓ | | 0-bootstrap |
-| [billing_account](variables-fast.tf#L25) | 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#L48) | 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#L58) | Organization details. | object({…}) | ✓ | | 0-bootstrap |
-| [prefix](variables-fast.tf#L68) | Prefix used for resources that need unique names. Use a maximum of 9 chars for organizations, and 11 chars for tenants. | string | ✓ | | 0-bootstrap |
+| [automation](variables-fast.tf#L19) | Automation resources created by the bootstrap stage. | object({…}) | ✓ | | 0-bootstrap |
+| [billing_account](variables-fast.tf#L27) | Billing account id. If billing account is not part of the same org set `is_org_level` to false. | object({…}) | ✓ | | 0-bootstrap |
+| [environments](variables-fast.tf#L49) | Environment names. | map(object({…})) | ✓ | | 0-globals |
+| [folder_ids](variables-fast.tf#L66) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. | object({…}) | ✓ | | 1-resman |
+| [prefix](variables-fast.tf#L76) | Prefix used for resources that need unique names. Use a maximum of 9 chars for organizations, and 11 chars for tenants. | string | ✓ | | 0-bootstrap |
| [alert_config](variables.tf#L17) | Configuration for monitoring alerts. | object({…}) | | {…} | |
+| [custom_roles](variables-fast.tf#L40) | Custom roles defined at the org level, in key => id format. | object({…}) | | null | 0-bootstrap |
| [dns](variables.tf#L42) | DNS configuration. | object({…}) | | {} | |
| [enable_cloud_nat](variables.tf#L53) | Deploy Cloud NAT. | bool | | false | |
| [essential_contacts](variables.tf#L60) | Email used for essential contacts, unset if null. | string | | null | |
| [factories_config](variables.tf#L66) | Configuration for network resource factories. | object({…}) | | {…} | |
-| [fast_features](variables-fast.tf#L38) | Selective control for top-level FAST features. | object({…}) | | {} | 0-0-bootstrap |
| [outputs_location](variables.tf#L87) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string | | null | |
| [psa_ranges](variables.tf#L93) | IP ranges used for Private Service Access (e.g. CloudSQL). | object({…}) | | {} | |
| [regions](variables.tf#L113) | Region definitions. | object({…}) | | {…} | |
-| [service_accounts](variables-fast.tf#L78) | Automation service accounts in name => email format. | object({…}) | | null | 1-resman |
+| [stage_config](variables-fast.tf#L86) | FAST stage configuration. | object({…}) | | {} | 1-resman |
+| [tag_values](variables-fast.tf#L100) | Root-level tag values. | map(string) | | {} | 1-resman |
| [vpn_onprem_dev_primary_config](variables.tf#L123) | VPN gateway configuration for onprem interconnection from dev in the primary region. | object({…}) | | null | |
| [vpn_onprem_prod_primary_config](variables.tf#L166) | VPN gateway configuration for onprem interconnection from prod in the primary region. | object({…}) | | null | |
@@ -362,11 +381,11 @@ Regions are defined via the `regions` variable which sets up a mapping between t
| name | description | sensitive | consumers |
|---|---|:---:|---|
-| [dev_cloud_dns_inbound_policy](outputs.tf#L77) | IP Addresses for Cloud DNS inbound policy for the dev environment. | | |
-| [host_project_ids](outputs.tf#L82) | Network project ids. | | |
-| [host_project_numbers](outputs.tf#L87) | Network project numbers. | | |
-| [prod_cloud_dns_inbound_policy](outputs.tf#L92) | IP Addresses for Cloud DNS inbound policy for the prod environment. | | |
-| [shared_vpc_self_links](outputs.tf#L97) | Shared VPC host projects. | | |
-| [tfvars](outputs.tf#L102) | Terraform variables file for the following stages. | ✓ | |
-| [vpn_gateway_endpoints](outputs.tf#L108) | External IP Addresses for the GCP VPN gateways. | | |
+| [dev_cloud_dns_inbound_policy](outputs.tf#L79) | IP Addresses for Cloud DNS inbound policy for the dev environment. | | |
+| [host_project_ids](outputs.tf#L84) | Network project ids. | | |
+| [host_project_numbers](outputs.tf#L89) | Network project numbers. | | |
+| [prod_cloud_dns_inbound_policy](outputs.tf#L94) | IP Addresses for Cloud DNS inbound policy for the prod environment. | | |
+| [shared_vpc_self_links](outputs.tf#L99) | Shared VPC host projects. | | |
+| [tfvars](outputs.tf#L104) | Terraform variables file for the following stages. | ✓ | |
+| [vpn_gateway_endpoints](outputs.tf#L110) | External IP Addresses for the GCP VPN gateways. | | |
diff --git a/fast/stages/2-networking-c-separate-envs/main.tf b/fast/stages/2-networking-c-separate-envs/main.tf
index fd7b76e4d..7497e2d50 100644
--- a/fast/stages/2-networking-c-separate-envs/main.tf
+++ b/fast/stages/2-networking-c-separate-envs/main.tf
@@ -17,28 +17,36 @@
# tfdoc:file:description Networking folder and hierarchical policy.
locals {
+ env_tag_values = {
+ for k, v in var.environments :
+ k => var.tag_values["environment/${v.tag_name}"]
+ }
+ has_env_folders = var.folder_ids.networking-dev != null
+ iam_delegated = join(",", formatlist("'%s'", [
+ "roles/composer.sharedVpcAgent",
+ "roles/compute.networkUser",
+ "roles/compute.networkViewer",
+ "roles/container.hostServiceAgentUser",
+ "roles/multiclusterservicediscovery.serviceAgent",
+ "roles/vpcaccess.user",
+ ]))
+ iam_delegated_principals = try(
+ var.stage_config["networking"].iam_delegated_principals, {}
+ )
+ iam_viewer_principals = try(
+ var.stage_config["networking"].iam_viewer_principals, {}
+ )
# combine all regions from variables and subnets
regions = distinct(concat(
values(var.regions),
values(module.dev-spoke-vpc.subnet_regions),
values(module.prod-spoke-vpc.subnet_regions),
))
- stage3_sas_delegated_grants = [
- "roles/composer.sharedVpcAgent",
- "roles/compute.networkUser",
- "roles/container.hostServiceAgentUser",
- "roles/vpcaccess.user",
- ]
- service_accounts = {
- for k, v in coalesce(var.service_accounts, {}) : k => "serviceAccount:${v}" if v != null
- }
}
module "folder" {
source = "../../../modules/folder"
- parent = "organizations/${var.organization.id}"
- name = "Networking"
- folder_create = var.folder_ids.networking == null
+ folder_create = false
id = var.folder_ids.networking
contacts = (
var.essential_contacts == null
diff --git a/fast/stages/2-networking-c-separate-envs/monitoring.tf b/fast/stages/2-networking-c-separate-envs/monitoring.tf
index 01ed0c479..d3750fee0 100644
--- a/fast/stages/2-networking-c-separate-envs/monitoring.tf
+++ b/fast/stages/2-networking-c-separate-envs/monitoring.tf
@@ -29,10 +29,16 @@ resource "google_monitoring_dashboard" "dev-dashboard" {
for_each = local.dashboards
project = module.dev-spoke-project.project_id
dashboard_json = file(each.value)
+ lifecycle {
+ ignore_changes = [dashboard_json]
+ }
}
resource "google_monitoring_dashboard" "prod-dashboard" {
for_each = local.dashboards
project = module.prod-spoke-project.project_id
dashboard_json = file(each.value)
+ lifecycle {
+ ignore_changes = [dashboard_json]
+ }
}
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 3ee211ba7..185db01ff 100644
--- a/fast/stages/2-networking-c-separate-envs/net-dev.tf
+++ b/fast/stages/2-networking-c-separate-envs/net-dev.tf
@@ -20,9 +20,12 @@ module "dev-spoke-project" {
source = "../../../modules/project"
billing_account = var.billing_account.id
name = "dev-net-spoke-0"
- parent = var.folder_ids.networking-dev
- prefix = var.prefix
- services = concat([
+ parent = coalesce(
+ var.folder_ids.networking-dev,
+ var.folder_ids.networking
+ )
+ prefix = var.prefix
+ services = [
"container.googleapis.com",
"compute.googleapis.com",
"dns.googleapis.com",
@@ -31,43 +34,35 @@ module "dev-spoke-project" {
"networksecurity.googleapis.com",
"servicenetworking.googleapis.com",
"stackdriver.googleapis.com",
+ "vmwareengine.googleapis.com",
"vpcaccess.googleapis.com"
- ],
- (
- var.fast_features.gcve
- ? ["vmwareengine.googleapis.com"]
- : []
- )
- )
+ ]
shared_vpc_host_config = {
enabled = true
service_projects = []
}
+ # optionally delegate a fixed set of IAM roles to selected principals
iam = {
- "roles/dns.admin" = compact([
- try(local.service_accounts.gke-dev, null),
- ])
+ (var.custom_roles.project_iam_viewer) = try(local.iam_viewer_principals["dev"], [])
}
- # allow specific service accounts to assign a set of roles
- iam_bindings = {
- sa_delegated_grants = {
- role = "roles/resourcemanager.projectIamAdmin"
- members = compact([
- try(local.service_accounts.data-platform-dev, null),
- try(local.service_accounts.project-factory, null),
- try(local.service_accounts.project-factory-dev, null),
- try(local.service_accounts.project-factory-prod, null),
- try(local.service_accounts.gke-dev, null),
- ])
- condition = {
- title = "dev_stage3_sa_delegated_grants"
- description = "Development host project delegated grants."
- expression = format(
- "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])",
- join(",", formatlist("'%s'", local.stage3_sas_delegated_grants))
- )
+ iam_bindings = (
+ lookup(local.iam_delegated_principals, "dev", null) == null ? {} : {
+ sa_delegated_grants = {
+ role = "roles/resourcemanager.projectIamAdmin"
+ members = try(local.iam_delegated_principals["dev"], [])
+ condition = {
+ title = "dev_stage3_sa_delegated_grants"
+ description = "${var.environments["dev"].name} host project delegated grants."
+ expression = format(
+ "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])",
+ local.iam_delegated
+ )
+ }
}
}
+ )
+ tag_bindings = local.has_env_folders ? {} : {
+ environment = local.env_tag_values["dev"]
}
}
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 1f3432cd4..f25c9f556 100644
--- a/fast/stages/2-networking-c-separate-envs/net-prod.tf
+++ b/fast/stages/2-networking-c-separate-envs/net-prod.tf
@@ -20,9 +20,12 @@ module "prod-spoke-project" {
source = "../../../modules/project"
billing_account = var.billing_account.id
name = "prod-net-spoke-0"
- parent = var.folder_ids.networking-prod
- prefix = var.prefix
- services = concat([
+ parent = coalesce(
+ var.folder_ids.networking-prod,
+ var.folder_ids.networking
+ )
+ prefix = var.prefix
+ services = [
"container.googleapis.com",
"compute.googleapis.com",
"dns.googleapis.com",
@@ -31,42 +34,35 @@ module "prod-spoke-project" {
"networksecurity.googleapis.com",
"servicenetworking.googleapis.com",
"stackdriver.googleapis.com",
+ "vmwareengine.googleapis.com",
"vpcaccess.googleapis.com"
- ],
- (
- var.fast_features.gcve
- ? ["vmwareengine.googleapis.com"]
- : []
- )
- )
+ ]
shared_vpc_host_config = {
enabled = true
service_projects = []
}
+ # optionally delegate a fixed set of IAM roles to selected principals
iam = {
- "roles/dns.admin" = compact([
- try(local.service_accounts.gke-prod, null),
- ])
+ (var.custom_roles.project_iam_viewer) = try(local.iam_viewer_principals["prod"], [])
}
- # allow specific service accounts to assign a set of roles
- iam_bindings = {
- sa_delegated_grants = {
- role = "roles/resourcemanager.projectIamAdmin"
- members = compact([
- try(local.service_accounts.data-platform-prod, null),
- try(local.service_accounts.project-factory, null),
- try(local.service_accounts.project-factory-prod, null),
- try(local.service_accounts.gke-prod, null),
- ])
- condition = {
- title = "prod_stage3_sa_delegated_grants"
- description = "Production host project delegated grants."
- expression = format(
- "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])",
- join(",", formatlist("'%s'", local.stage3_sas_delegated_grants))
- )
+ iam_bindings = (
+ lookup(local.iam_delegated_principals, "prod", null) == null ? {} : {
+ sa_delegated_grants = {
+ role = "roles/resourcemanager.projectIamAdmin"
+ members = try(local.iam_delegated_principals["prod"], [])
+ condition = {
+ title = "prod_stage3_sa_delegated_grants"
+ description = "${var.environments["prod"].name} host project delegated grants."
+ expression = format(
+ "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])",
+ local.iam_delegated
+ )
+ }
}
}
+ )
+ tag_bindings = local.has_env_folders ? {} : {
+ environment = local.env_tag_values["prod"]
}
}
diff --git a/fast/stages/2-networking-c-separate-envs/outputs.tf b/fast/stages/2-networking-c-separate-envs/outputs.tf
index cef97ca01..22a667895 100644
--- a/fast/stages/2-networking-c-separate-envs/outputs.tf
+++ b/fast/stages/2-networking-c-separate-envs/outputs.tf
@@ -24,15 +24,17 @@ locals {
prod-spoke-0 = module.prod-spoke-project.number
}
subnet_self_links = {
- dev-spoke-0 = module.dev-spoke-vpc.subnet_self_links
- prod-spoke-0 = module.prod-spoke-vpc.subnet_self_links
+ dev-spoke-0 = module.dev-spoke-vpc.subnet_ids
+ prod-spoke-0 = module.prod-spoke-vpc.subnet_ids
}
subnet_proxy_only_self_links = {
dev-spoke-0 = {
- for k, v in module.dev-spoke-vpc.subnets_proxy_only : k => v.id
+ for k, v in module.dev-spoke-vpc.subnets_proxy_only :
+ k => v.id
}
prod-spoke-0 = {
- for k, v in module.prod-spoke-vpc.subnets_proxy_only : k => v.id
+ for k, v in module.prod-spoke-vpc.subnets_proxy_only :
+ k => v.id
}
}
subnet_psc_self_links = {
@@ -52,8 +54,8 @@ locals {
vpc_self_links = local.vpc_self_links
}
vpc_self_links = {
- dev-spoke-0 = module.dev-spoke-vpc.self_link
- prod-spoke-0 = module.prod-spoke-vpc.self_link
+ dev-spoke-0 = module.dev-spoke-vpc.id
+ prod-spoke-0 = module.prod-spoke-vpc.id
}
}
diff --git a/fast/stages/2-networking-c-separate-envs/variables-fast.tf b/fast/stages/2-networking-c-separate-envs/variables-fast.tf
index bdb3ae8d7..dd7f96bf5 100644
--- a/fast/stages/2-networking-c-separate-envs/variables-fast.tf
+++ b/fast/stages/2-networking-c-separate-envs/variables-fast.tf
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+# tfdoc:file:description FAST stage interface.
+
variable "automation" {
# tfdoc:variable:source 0-bootstrap
description = "Automation resources created by the bootstrap stage."
@@ -35,33 +37,39 @@ variable "billing_account" {
}
}
-variable "fast_features" {
- # tfdoc:variable:source 0-0-bootstrap
- description = "Selective control for top-level FAST features."
+variable "custom_roles" {
+ # tfdoc:variable:source 0-bootstrap
+ description = "Custom roles defined at the org level, in key => id format."
type = object({
- gcve = optional(bool, false)
+ project_iam_viewer = string
})
- default = {}
+ default = null
+}
+
+variable "environments" {
+ # tfdoc:variable:source 0-globals
+ description = "Environment names."
+ type = map(object({
+ name = string
+ tag_name = string
+ is_default = optional(bool, false)
+ }))
nullable = false
+ validation {
+ condition = anytrue([
+ for k, v in var.environments : v.is_default == true
+ ])
+ error_message = "At least one environment should be marked as default."
+ }
}
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."
+ description = "Folders to be used for the networking resources in folders/nnnnnnnnnnn format."
type = object({
networking = string
- networking-dev = string
- networking-prod = string
- })
-}
-
-variable "organization" {
- # tfdoc:variable:source 0-bootstrap
- description = "Organization details."
- type = object({
- domain = string
- id = number
- customer_id = string
+ networking-dev = optional(string)
+ networking-prod = optional(string)
})
}
@@ -75,17 +83,23 @@ variable "prefix" {
}
}
-variable "service_accounts" {
+variable "stage_config" {
# tfdoc:variable:source 1-resman
- description = "Automation service accounts in name => email format."
+ description = "FAST stage configuration."
type = object({
- data-platform-dev = string
- data-platform-prod = string
- gke-dev = string
- gke-prod = string
- project-factory = string
- project-factory-dev = string
- project-factory-prod = string
+ networking = optional(object({
+ short_name = optional(string)
+ iam_delegated_principals = optional(map(list(string)), {})
+ iam_viewer_principals = optional(map(list(string)), {})
+ }), {})
})
- default = null
+ default = {}
+ nullable = false
+}
+
+variable "tag_values" {
+ # tfdoc:variable:source 1-resman
+ description = "Root-level tag values."
+ type = map(string)
+ default = {}
}
diff --git a/fast/stages/2-project-factory/.fast-stage.env b/fast/stages/2-project-factory/.fast-stage.env
new file mode 100644
index 000000000..a22865d96
--- /dev/null
+++ b/fast/stages/2-project-factory/.fast-stage.env
@@ -0,0 +1,5 @@
+FAST_STAGE_DESCRIPTION="project factory (org level)"
+FAST_STAGE_LEVEL=2
+FAST_STAGE_NAME=project-factory
+FAST_STAGE_DEPS="0-globals 0-bootstrap 1-resman"
+FAST_STAGE_OPTIONAL="2-networking 2-security"
\ No newline at end of file
diff --git a/fast/stages/2-project-factory/README.md b/fast/stages/2-project-factory/README.md
index 3a6ae140e..159fa54fd 100644
--- a/fast/stages/2-project-factory/README.md
+++ b/fast/stages/2-project-factory/README.md
@@ -100,34 +100,48 @@ The `data` folder in this stage contains factory files that can be used as examp
As all other FAST stages, the [mechanism](../0-bootstrap/README.md#output-files-and-cross-stage-variables) used to pass variable values and pre-built provider files from one stage to the next 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.
+The commands to link or copy the provider and terraform variable files can be easily derived from the `fast-links.sh` script in the FAST stages 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
+../fast-links.sh ~/fast-config
-# copy and paste the following commands for '2-project-factory'
+# File linking commands for project factory (org level) stage
-ln -s ~/fast-config/providers/2-project-factory-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 ./
-# optional but recommended
-ln -s ~/fast-config/tfvars/2-networking.auto.tfvars.json ./
-ln -s ~/fast-config/tfvars/2-security.auto.tfvars.json ./
+# provider file
+ln -s ~/fast-config/fast-test-00/providers/2-project-factory-providers.tf ./
+
+# input files from other stages
+ln -s ~/fast-config/fast-test-00/tfvars/0-globals.auto.tfvars.json ./
+ln -s ~/fast-config/fast-test-00/tfvars/0-bootstrap.auto.tfvars.json ./
+ln -s ~/fast-config/fast-test-00/tfvars/1-resman.auto.tfvars.json ./
+
+# conventional place for stage tfvars (manually created)
+ln -s ~/fast-config/fast-test-00/2-project-factory.auto.tfvars ./
+
+# optional files
+ln -s ~/fast-config/fast-test-00/2-networking.auto.tfvars.json ./
+ln -s ~/fast-config/fast-test-00/2-security.auto.tfvars.json ./
```
```bash
-../../../stage-links.sh gs://xxx-prod-iac-core-outputs-0
+../fast-links.sh gs://xxx-prod-iac-core-outputs-0
-# copy and paste the following commands for '2-project-factory'
+# File linking commands for project factory (org level) stage
+# provider file
gcloud storage cp gs://xxx-prod-iac-core-outputs-0/providers/2-project-factory-providers.tf ./
+
+# input files from other stages
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 ./
-# optional but recommended
-gcloud storage cp gs://xxx-prod-iac-core-outputs-0/tfvars/2-networking.auto.tfvars.json ./
-gcloud storage cp gs://xxx-prod-iac-core-outputs-0/tfvars/2-security.auto.tfvars.json ./
+
+# conventional place for stage tfvars (manually created)
+gcloud storage cp gs://xxx-prod-iac-core-outputs-0/2-project-factory.auto.tfvars ./
+
+# optional files
+gcloud storage cp gs://xxx-prod-iac-core-outputs-0/2-networking.auto.tfvars.json ./
+gcloud storage cp gs://xxx-prod-iac-core-outputs-0/2-security.auto.tfvars.json ./
```
If you're not using FAST, refer to the [Variables](#variables) table at the bottom of this document for a full list of variables, their origin (e.g., a stage or specific to this one), and descriptions explaining their meaning.
@@ -324,7 +338,7 @@ This approach leverages the per-environment project factory service accounts and
The approach is not shown here but reasonably easy to implement. The main project factory output file can also be used to set up folder id susbtitution in the per-environment factories.
-
+
## Files
diff --git a/fast/stages/2-security/.fast-stage.env b/fast/stages/2-security/.fast-stage.env
new file mode 100644
index 000000000..d174c2162
--- /dev/null
+++ b/fast/stages/2-security/.fast-stage.env
@@ -0,0 +1,5 @@
+FAST_STAGE_DESCRIPTION="security"
+FAST_STAGE_LEVEL=2
+FAST_STAGE_NAME=security
+FAST_STAGE_DEPS="0-globals 0-bootstrap 1-resman"
+FAST_STAGE_OPTIONAL="2-nsec"
\ No newline at end of file
diff --git a/fast/stages/2-security/README.md b/fast/stages/2-security/README.md
index 6ee1c93ce..aa13a0a15 100644
--- a/fast/stages/2-security/README.md
+++ b/fast/stages/2-security/README.md
@@ -58,7 +58,7 @@ The stage lets you also create Certificate Manager trust configs. With trust con
### NGFW Enterprise and TLS inspection support
-We deploy NGFW Enterprise in the [network-security stage](../3-network-security/README.md). If you require TLS inspection, NGFW needs to interact with CAS and -optionally- Certificate Manager trust-configs. These components bind to firewall endpoint associations (created in the [network-security stage](../3-network-security/README.md)) with zonal TLS inspection policies.
+We deploy NGFW Enterprise in the [network security stage](../2-network-security/README.md). If you require TLS inspection, NGFW needs to interact with CAS and -optionally- Certificate Manager trust-configs. These components bind to firewall endpoint associations (created in the network security stage) with zonal TLS inspection policies.
Using this module, you can define CAS configurations and trust-configs for NGFW Enterprise. You can create them using the `cas_configs` and `trust_configs` variables. Anyway, these will need to use specific keys (defined in `ngfw_tls_configs.keys`), so that FAST knows which configurations to use for NGFW Enterprise.
You can then enable TLS inspection and customize its behavior for NGFW Enterprise, using the `ngfw_tls_configs.tls_inspection` variable. FAST will create the TLS inspection policies for you in the regions where you defined your CAs for NGFW Enterprise.
When you create your CAs and trust-configs for NGFW Enterprise, make sure their region matches the zones where you will define your firewall endpoints.
@@ -76,28 +76,46 @@ Before running this stage, you need to make sure you have the correct credential
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.
+The commands to link or copy the provider and terraform variable files can be easily derived from the `fast-links.sh` script in the FAST stages 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
+../fast-links.sh ~/fast-config
-# copy and paste the following commands for '2-security'
+# File linking commands for security stage
-ln -s ~/fast-config/providers/2-security-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 ./
+# provider file
+ln -s ~/fast-config/fast-test-00/providers/2-security-providers.tf ./
+
+# input files from other stages
+ln -s ~/fast-config/fast-test-00/tfvars/0-globals.auto.tfvars.json ./
+ln -s ~/fast-config/fast-test-00/tfvars/0-bootstrap.auto.tfvars.json ./
+ln -s ~/fast-config/fast-test-00/tfvars/1-resman.auto.tfvars.json ./
+
+# conventional place for stage tfvars (manually created)
+ln -s ~/fast-config/fast-test-00/2-security.auto.tfvars ./
+
+# optional files
+ln -s ~/fast-config/fast-test-00/2-nsec.auto.tfvars.json ./
```
```bash
-../../stage-links.sh gs://xxx-prod-iac-core-outputs-0
+../fast-links.sh gs://xxx-prod-iac-core-outputs-0
-# copy and paste the following commands for '2-security'
+# File linking commands for security stage
+# provider file
gcloud storage cp gs://xxx-prod-iac-core-outputs-0/providers/2-security-providers.tf ./
+
+# input files from other stages
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 ./
+
+# conventional place for stage tfvars (manually created)
+gcloud storage cp gs://xxx-prod-iac-core-outputs-0/2-security.auto.tfvars ./
+
+# optional files
+gcloud storage cp gs://xxx-prod-iac-core-outputs-0/2-nsec.auto.tfvars.json ./
```
### Impersonating the automation service account
@@ -171,7 +189,7 @@ kms_keys = {
}
storage = {
iam = null
- labels = { service = "compute" }
+ labels = { service = "storage" }
locations = ["europe"]
rotation_period = null
}
@@ -262,7 +280,7 @@ tls_inspection = {
}
```
-
+
## Files
@@ -281,16 +299,18 @@ tls_inspection = {
|---|---|:---:|:---:|:---:|:---:|
| [automation](variables-fast.tf#L17) | Automation resources created by the bootstrap stage. | object({…}) | ✓ | | 0-bootstrap |
| [billing_account](variables-fast.tf#L25) | 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#L38) | Folder name => id mappings, the 'security' folder name must exist. | object({…}) | ✓ | | 1-resman |
-| [organization](variables-fast.tf#L46) | Organization details. | object({…}) | ✓ | | 0-bootstrap |
-| [prefix](variables-fast.tf#L56) | Prefix used for resources that need unique names. Use a maximum of 9 chars for organizations, and 11 chars for tenants. | string | ✓ | | 0-bootstrap |
-| [service_accounts](variables-fast.tf#L66) | Automation service accounts that can assign the encrypt/decrypt roles on keys. | object({…}) | ✓ | | 1-resman |
-| [cas_configs](variables.tf#L18) | The CAS CAs to add to each environment. | object({…}) | | {…} | |
-| [essential_contacts](variables.tf#L179) | Email used for essential contacts, unset if null. | string | | null | |
-| [kms_keys](variables.tf#L185) | KMS keys to create, keyed by name. | map(object({…})) | | {} | |
-| [ngfw_tls_configs](variables.tf#L224) | The CAS and trust configurations key names to be used for NGFW Enterprise. | object({…}) | | {…} | |
-| [outputs_location](variables.tf#L250) | Path where providers, tfvars files, and lists for the following stages are written. Leave empty to disable. | string | | null | |
-| [trust_configs](variables.tf#L256) | The trust configs grouped by environment. | object({…}) | | {…} | |
+| [environments](variables-fast.tf#L47) | Environment names. | map(object({…})) | ✓ | | 0-globals |
+| [folder_ids](variables-fast.tf#L64) | Folder name => id mappings, the 'security' folder name must exist. | object({…}) | ✓ | | 1-resman |
+| [prefix](variables-fast.tf#L74) | Prefix used for resources that need unique names. Use a maximum of 9 chars for organizations, and 11 chars for tenants. | string | ✓ | | 0-bootstrap |
+| [cas_configs](variables.tf#L17) | The CAS CAs to add to each environment. | object({…}) | | {…} | |
+| [custom_roles](variables-fast.tf#L38) | Custom roles defined at the org level, in key => id format. | object({…}) | | null | 0-bootstrap |
+| [essential_contacts](variables.tf#L178) | Email used for essential contacts, unset if null. | string | | null | |
+| [kms_keys](variables.tf#L184) | KMS keys to create, keyed by name. | map(object({…})) | | {} | |
+| [ngfw_tls_configs](variables.tf#L223) | The CAS and trust configurations key names to be used for NGFW Enterprise. | object({…}) | | {…} | |
+| [outputs_location](variables.tf#L249) | Path where providers, tfvars files, and lists for the following stages are written. Leave empty to disable. | string | | null | |
+| [stage_config](variables-fast.tf#L84) | FAST stage configuration. | object({…}) | | {} | 1-resman |
+| [tag_values](variables-fast.tf#L98) | Root-level tag values. | map(string) | | {} | 1-resman |
+| [trust_configs](variables.tf#L255) | The trust configs grouped by environment. | object({…}) | | {…} | |
## Outputs
diff --git a/fast/stages/2-security/core-dev.tf b/fast/stages/2-security/core-dev.tf
index 9ac7d417f..2c089db12 100644
--- a/fast/stages/2-security/core-dev.tf
+++ b/fast/stages/2-security/core-dev.tf
@@ -15,45 +15,45 @@
*/
locals {
- # Extract NGFW locations from dev CAS
ngfw_dev_locations = toset([
- for k, v in var.cas_configs.dev
- : v.location
+ for k, v in var.cas_configs.dev : v.location
if contains(var.ngfw_tls_configs.keys.dev.cas, k)
])
- ngfw_dev_sa_agent_cas_iam_bindings_additive = {
- nsec_dev_agent_sa_binding = {
- member = module.dev-sec-project.service_agents["networksecurity"].iam_email
- role = "roles/privateca.certificateManager"
- }
- }
- dev_kms_restricted_admins = [
- for sa in distinct(compact([
- var.service_accounts.data-platform-dev,
- var.service_accounts.project-factory,
- var.service_accounts.project-factory-dev,
- var.service_accounts.project-factory-prod
- ])) : "serviceAccount:${sa}"
- ]
}
module "dev-sec-project" {
- source = "../../../modules/project"
- name = "dev-sec-core-0"
- parent = var.folder_ids.security
+ source = "../../../modules/project"
+ name = "dev-sec-core-0"
+ parent = coalesce(
+ var.folder_ids.security-dev, var.folder_ids.security
+ )
prefix = var.prefix
billing_account = var.billing_account.id
+ labels = { environment = "dev" }
+ services = local.project_services
+ tag_bindings = local.has_env_folders ? {} : {
+ environment = local.env_tag_values["dev"]
+ }
+ # optionally delegate a fixed set of IAM roles to selected principals
iam = {
- "roles/cloudkms.viewer" = local.dev_kms_restricted_admins
+ (var.custom_roles.project_iam_viewer) = try(local.iam_viewer_principals["dev"], [])
}
- iam_bindings_additive = {
- for member in local.dev_kms_restricted_admins :
- "kms_restricted_admin.${member}" => merge(local.kms_restricted_admin_template, {
- member = member
- })
- }
- labels = { environment = "dev", team = "security" }
- services = local.project_services
+ iam_bindings = (
+ lookup(local.iam_delegated_principals, "dev", null) == null ? {} : {
+ sa_delegated_grants = {
+ role = "roles/resourcemanager.projectIamAdmin"
+ members = try(local.iam_delegated_principals["dev"], [])
+ condition = {
+ title = "dev_stage3_sa_delegated_grants"
+ description = "${var.environments["dev"].name} project delegated grants."
+ expression = format(
+ "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])",
+ local.iam_delegated
+ )
+ }
+ }
+ }
+ )
}
module "dev-sec-kms" {
@@ -77,7 +77,15 @@ module "dev-cas" {
iam_bindings = each.value.iam_bindings
iam_bindings_additive = (
contains(var.ngfw_tls_configs.keys.dev.cas, each.key)
- ? merge(local.ngfw_dev_sa_agent_cas_iam_bindings_additive, each.value.iam_bindings_additive)
+ ? merge(
+ {
+ nsec_agent = {
+ member = module.dev-sec-project.service_agents["networksecurity"].iam_email
+ role = "roles/privateca.certificateManager"
+ }
+ },
+ each.value.iam_bindings_additive
+ )
: each.value.iam_bindings_additive
)
iam_by_principals = each.value.iam_by_principals
diff --git a/fast/stages/2-security/core-prod.tf b/fast/stages/2-security/core-prod.tf
index c98fe7028..b74a5376a 100644
--- a/fast/stages/2-security/core-prod.tf
+++ b/fast/stages/2-security/core-prod.tf
@@ -15,44 +15,45 @@
*/
locals {
- # Extract NGFW locations from prod CAS
ngfw_prod_locations = toset([
- for k, v in var.cas_configs.prod
- : v.location
+ for k, v in var.cas_configs.prod : v.location
if contains(var.ngfw_tls_configs.keys.prod.cas, k)
])
- ngfw_prod_sa_agent_cas_iam_bindings_additive = {
- nsec_prod_agent_sa_binding = {
- member = module.prod-sec-project.service_agents["networksecurity"].iam_email
- role = "roles/privateca.certificateManager"
- }
- }
- prod_kms_restricted_admins = [
- for sa in distinct(compact([
- var.service_accounts.data-platform-prod,
- var.service_accounts.project-factory,
- var.service_accounts.project-factory-prod
- ])) : "serviceAccount:${sa}"
- ]
}
module "prod-sec-project" {
- source = "../../../modules/project"
- name = "prod-sec-core-0"
- parent = var.folder_ids.security
+ source = "../../../modules/project"
+ name = "prod-sec-core-0"
+ parent = coalesce(
+ var.folder_ids.security-prod, var.folder_ids.security
+ )
prefix = var.prefix
billing_account = var.billing_account.id
+ labels = { environment = "prod" }
+ services = local.project_services
+ tag_bindings = local.has_env_folders ? {} : {
+ environment = local.env_tag_values["prod"]
+ }
+ # optionally delegate a fixed set of IAM roles to selected principals
iam = {
- "roles/cloudkms.viewer" = local.prod_kms_restricted_admins
+ (var.custom_roles.project_iam_viewer) = try(local.iam_viewer_principals["prod"], [])
}
- iam_bindings_additive = {
- for member in local.prod_kms_restricted_admins :
- "kms_restricted_admin.${member}" => merge(local.kms_restricted_admin_template, {
- member = member
- })
- }
- labels = { environment = "prod", team = "security" }
- services = local.project_services
+ iam_bindings = (
+ lookup(local.iam_delegated_principals, "prod", null) == null ? {} : {
+ sa_delegated_grants = {
+ role = "roles/resourcemanager.projectIamAdmin"
+ members = try(local.iam_delegated_principals["prod"], [])
+ condition = {
+ title = "prod_stage3_sa_delegated_grants"
+ description = "${var.environments["prod"].name} project delegated grants."
+ expression = format(
+ "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])",
+ local.iam_delegated
+ )
+ }
+ }
+ }
+ )
}
module "prod-sec-kms" {
@@ -76,7 +77,15 @@ module "prod-cas" {
iam_bindings = each.value.iam_bindings
iam_bindings_additive = (
contains(var.ngfw_tls_configs.keys.prod.cas, each.key)
- ? merge(local.ngfw_prod_sa_agent_cas_iam_bindings_additive, each.value.iam_bindings_additive)
+ ? merge(
+ {
+ nsec_agent = {
+ member = module.prod-sec-project.service_agents["networksecurity"].iam_email
+ role = "roles/privateca.certificateManager"
+ }
+ },
+ each.value.iam_bindings_additive
+ )
: each.value.iam_bindings_additive
)
iam_by_principals = each.value.iam_by_principals
diff --git a/fast/stages/2-security/main.tf b/fast/stages/2-security/main.tf
index ba9b6d8a4..5aa17e87e 100644
--- a/fast/stages/2-security/main.tf
+++ b/fast/stages/2-security/main.tf
@@ -15,24 +15,20 @@
*/
locals {
- # additive IAM binding for delegated KMS admins
- kms_restricted_admin_template = {
- role = "roles/cloudkms.admin"
- condition = {
- title = "kms_sa_delegated_grants"
- description = "Automation service account delegated grants."
- expression = format(
- <<-EOT
- api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s]) &&
- resource.type == 'cloudkms.googleapis.com/CryptoKey'
- EOT
- , join(",", formatlist("'%s'", [
- "roles/cloudkms.cryptoKeyEncrypterDecrypter",
- "roles/cloudkms.cryptoKeyEncrypterDecrypterViaDelegation"
- ]))
- )
- }
+ env_tag_values = {
+ for k, v in var.environments :
+ k => var.tag_values["environment/${v.tag_name}"]
}
+ has_env_folders = var.folder_ids.security-dev != null
+ iam_delegated = join(",", formatlist("'%s'", [
+ "roles/cloudkms.cryptoKeyEncrypterDecrypter"
+ ]))
+ iam_delegated_principals = try(
+ var.stage_config["security"].iam_delegated_principals, {}
+ )
+ iam_viewer_principals = try(
+ var.stage_config["security"].iam_viewer_principals, {}
+ )
# list of locations with keys
kms_locations = distinct(flatten([
for k, v in var.kms_keys : v.locations
@@ -59,9 +55,7 @@ locals {
module "folder" {
source = "../../../modules/folder"
- parent = "organizations/${var.organization.id}"
- name = "Security"
- folder_create = var.folder_ids.security == null
+ folder_create = false
id = var.folder_ids.security
contacts = (
var.essential_contacts == null
diff --git a/fast/stages/2-security/variables-fast.tf b/fast/stages/2-security/variables-fast.tf
index 7d6259920..b8a664e52 100644
--- a/fast/stages/2-security/variables-fast.tf
+++ b/fast/stages/2-security/variables-fast.tf
@@ -35,21 +35,39 @@ variable "billing_account" {
}
}
+variable "custom_roles" {
+ # tfdoc:variable:source 0-bootstrap
+ description = "Custom roles defined at the org level, in key => id format."
+ type = object({
+ project_iam_viewer = string
+ })
+ default = null
+}
+
+variable "environments" {
+ # tfdoc:variable:source 0-globals
+ description = "Environment names."
+ type = map(object({
+ name = string
+ tag_name = string
+ is_default = optional(bool, false)
+ }))
+ nullable = false
+ validation {
+ condition = anytrue([
+ for k, v in var.environments : v.is_default == true
+ ])
+ error_message = "At least one environment should be marked as default."
+ }
+}
+
variable "folder_ids" {
# tfdoc:variable:source 1-resman
description = "Folder name => id mappings, the 'security' folder name must exist."
type = object({
- security = string
- })
-}
-
-variable "organization" {
- # tfdoc:variable:source 0-bootstrap
- description = "Organization details."
- type = object({
- domain = string
- id = number
- customer_id = string
+ security = string
+ security-dev = optional(string)
+ security-prod = optional(string)
})
}
@@ -63,16 +81,23 @@ variable "prefix" {
}
}
-variable "service_accounts" {
+variable "stage_config" {
# tfdoc:variable:source 1-resman
- description = "Automation service accounts that can assign the encrypt/decrypt roles on keys."
+ description = "FAST stage configuration."
type = object({
- data-platform-dev = string
- data-platform-prod = string
- nsec = string
- nsec-r = string
- project-factory = string
- project-factory-dev = string
- project-factory-prod = string
+ security = optional(object({
+ short_name = optional(string)
+ iam_delegated_principals = optional(map(list(string)), {})
+ iam_viewer_principals = optional(map(list(string)), {})
+ }), {})
})
+ default = {}
+ nullable = false
+}
+
+variable "tag_values" {
+ # tfdoc:variable:source 1-resman
+ description = "Root-level tag values."
+ type = map(string)
+ default = {}
}
diff --git a/fast/stages/2-security/variables.tf b/fast/stages/2-security/variables.tf
index e4c3a3623..b13967c0d 100644
--- a/fast/stages/2-security/variables.tf
+++ b/fast/stages/2-security/variables.tf
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-# Refer
variable "cas_configs" {
description = "The CAS CAs to add to each environment."
type = object({
diff --git a/fast/stages/3-data-platform/README.md b/fast/stages/3-data-platform/README.md
deleted file mode 100644
index fa04c41f8..000000000
--- a/fast/stages/3-data-platform/README.md
+++ /dev/null
@@ -1,6 +0,0 @@
-# Data Platform
-
-The Data Platform builds on top of your foundations to create and set up projects and related resources, used for your data workloads and pipelines.
-It is organized in folders representing environments (e.g. `dev`, `prod`), each implemented by a stand-alone Terraform setup.
-
-This directory contains a [Data Platform for the `dev` environment](./dev/) that can be used as-is, and cloned with few changes to implement further environments. Refer to the example [`dev/README.md`](./dev/README.md) for configuration details.
diff --git a/fast/stages/3-data-platform/dev/IAM.md b/fast/stages/3-data-platform/dev/IAM.md
deleted file mode 100644
index 02a5df7a9..000000000
--- a/fast/stages/3-data-platform/dev/IAM.md
+++ /dev/null
@@ -1,89 +0,0 @@
-# IAM bindings reference
-
-Legend: + additive, • conditional.
-
-## Project cmn
-
-| members | roles |
-|---|---|
-|gcp-data-analysts
group|[roles/datacatalog.viewer](https://cloud.google.com/iam/docs/understanding-roles#datacatalog.viewer) |
-|gcp-data-engineers
group|[roles/dlp.estimatesAdmin](https://cloud.google.com/iam/docs/understanding-roles#dlp.estimatesAdmin)
[roles/dlp.reader](https://cloud.google.com/iam/docs/understanding-roles#dlp.reader)
[roles/dlp.user](https://cloud.google.com/iam/docs/understanding-roles#dlp.user) |
-|gcp-data-security
group|[roles/datacatalog.admin](https://cloud.google.com/iam/docs/understanding-roles#datacatalog.admin)
[roles/dlp.admin](https://cloud.google.com/iam/docs/understanding-roles#dlp.admin) |
-|load-df
serviceAccount|[roles/datacatalog.viewer](https://cloud.google.com/iam/docs/understanding-roles#datacatalog.viewer)
[roles/dlp.user](https://cloud.google.com/iam/docs/understanding-roles#dlp.user) |
-|trf-bq
serviceAccount|[roles/datacatalog.categoryFineGrainedReader](https://cloud.google.com/iam/docs/understanding-roles#datacatalog.categoryFineGrainedReader)
[roles/datacatalog.viewer](https://cloud.google.com/iam/docs/understanding-roles#datacatalog.viewer) |
-|trf-df
serviceAccount|[roles/datacatalog.categoryFineGrainedReader](https://cloud.google.com/iam/docs/understanding-roles#datacatalog.categoryFineGrainedReader)
[roles/datacatalog.viewer](https://cloud.google.com/iam/docs/understanding-roles#datacatalog.viewer)
[roles/dlp.user](https://cloud.google.com/iam/docs/understanding-roles#dlp.user) |
-
-## Project drp
-
-| members | roles |
-|---|---|
-|gcp-data-engineers
group|[roles/bigquery.dataEditor](https://cloud.google.com/iam/docs/understanding-roles#bigquery.dataEditor)
[roles/bigquery.user](https://cloud.google.com/iam/docs/understanding-roles#bigquery.user) |
-|drp-bq
serviceAccount|[roles/bigquery.dataEditor](https://cloud.google.com/iam/docs/understanding-roles#bigquery.dataEditor) |
-|drp-cs
serviceAccount|[roles/storage.objectCreator](https://cloud.google.com/iam/docs/understanding-roles#storage.objectCreator) |
-|drp-ps
serviceAccount|[roles/pubsub.publisher](https://cloud.google.com/iam/docs/understanding-roles#pubsub.publisher) |
-|load-df
serviceAccount|[roles/bigquery.user](https://cloud.google.com/iam/docs/understanding-roles#bigquery.user)
[roles/pubsub.subscriber](https://cloud.google.com/iam/docs/understanding-roles#pubsub.subscriber)
[roles/storage.objectAdmin](https://cloud.google.com/iam/docs/understanding-roles#storage.objectAdmin) |
-|orc-cmp
serviceAccount|[roles/pubsub.subscriber](https://cloud.google.com/iam/docs/understanding-roles#pubsub.subscriber)
[roles/storage.objectViewer](https://cloud.google.com/iam/docs/understanding-roles#storage.objectViewer) |
-
-## Project dwh-conf
-
-| members | roles |
-|---|---|
-|gcp-data-analysts
group|[roles/bigquery.dataViewer](https://cloud.google.com/iam/docs/understanding-roles#bigquery.dataViewer)
[roles/bigquery.jobUser](https://cloud.google.com/iam/docs/understanding-roles#bigquery.jobUser)
[roles/datacatalog.tagTemplateViewer](https://cloud.google.com/iam/docs/understanding-roles#datacatalog.tagTemplateViewer)
[roles/datacatalog.viewer](https://cloud.google.com/iam/docs/understanding-roles#datacatalog.viewer)
[roles/storage.objectViewer](https://cloud.google.com/iam/docs/understanding-roles#storage.objectViewer) |
-|gcp-data-engineers
group|[roles/bigquery.dataViewer](https://cloud.google.com/iam/docs/understanding-roles#bigquery.dataViewer)
[roles/bigquery.jobUser](https://cloud.google.com/iam/docs/understanding-roles#bigquery.jobUser)
[roles/datacatalog.tagTemplateViewer](https://cloud.google.com/iam/docs/understanding-roles#datacatalog.tagTemplateViewer)
[roles/datacatalog.viewer](https://cloud.google.com/iam/docs/understanding-roles#datacatalog.viewer)
[roles/storage.objectViewer](https://cloud.google.com/iam/docs/understanding-roles#storage.objectViewer) |
-|SERVICE_IDENTITY_service-networking
serviceAccount|[roles/servicenetworking.serviceAgent](https://cloud.google.com/iam/docs/understanding-roles#servicenetworking.serviceAgent) +|
-|trf-bq
serviceAccount|[roles/bigquery.dataOwner](https://cloud.google.com/iam/docs/understanding-roles#bigquery.dataOwner)
[roles/bigquery.jobUser](https://cloud.google.com/iam/docs/understanding-roles#bigquery.jobUser) |
-|trf-df
serviceAccount|[roles/bigquery.dataOwner](https://cloud.google.com/iam/docs/understanding-roles#bigquery.dataOwner)
[roles/storage.objectAdmin](https://cloud.google.com/iam/docs/understanding-roles#storage.objectAdmin) |
-
-## Project dwh-cur
-
-| members | roles |
-|---|---|
-|gcp-data-analysts
group|[roles/bigquery.dataViewer](https://cloud.google.com/iam/docs/understanding-roles#bigquery.dataViewer)
[roles/bigquery.jobUser](https://cloud.google.com/iam/docs/understanding-roles#bigquery.jobUser)
[roles/datacatalog.tagTemplateViewer](https://cloud.google.com/iam/docs/understanding-roles#datacatalog.tagTemplateViewer)
[roles/datacatalog.viewer](https://cloud.google.com/iam/docs/understanding-roles#datacatalog.viewer)
[roles/storage.objectViewer](https://cloud.google.com/iam/docs/understanding-roles#storage.objectViewer) |
-|gcp-data-engineers
group|[roles/bigquery.dataViewer](https://cloud.google.com/iam/docs/understanding-roles#bigquery.dataViewer)
[roles/bigquery.jobUser](https://cloud.google.com/iam/docs/understanding-roles#bigquery.jobUser)
[roles/datacatalog.tagTemplateViewer](https://cloud.google.com/iam/docs/understanding-roles#datacatalog.tagTemplateViewer)
[roles/datacatalog.viewer](https://cloud.google.com/iam/docs/understanding-roles#datacatalog.viewer)
[roles/storage.objectViewer](https://cloud.google.com/iam/docs/understanding-roles#storage.objectViewer) |
-|SERVICE_IDENTITY_service-networking
serviceAccount|[roles/servicenetworking.serviceAgent](https://cloud.google.com/iam/docs/understanding-roles#servicenetworking.serviceAgent) +|
-|trf-bq
serviceAccount|[roles/bigquery.dataOwner](https://cloud.google.com/iam/docs/understanding-roles#bigquery.dataOwner)
[roles/bigquery.jobUser](https://cloud.google.com/iam/docs/understanding-roles#bigquery.jobUser) |
-|trf-df
serviceAccount|[roles/bigquery.dataOwner](https://cloud.google.com/iam/docs/understanding-roles#bigquery.dataOwner)
[roles/storage.objectAdmin](https://cloud.google.com/iam/docs/understanding-roles#storage.objectAdmin) |
-
-## Project dwh-lnd
-
-| members | roles |
-|---|---|
-|gcp-data-engineers
group|[roles/bigquery.dataViewer](https://cloud.google.com/iam/docs/understanding-roles#bigquery.dataViewer)
[roles/bigquery.jobUser](https://cloud.google.com/iam/docs/understanding-roles#bigquery.jobUser)
[roles/datacatalog.tagTemplateViewer](https://cloud.google.com/iam/docs/understanding-roles#datacatalog.tagTemplateViewer)
[roles/datacatalog.viewer](https://cloud.google.com/iam/docs/understanding-roles#datacatalog.viewer)
[roles/storage.objectViewer](https://cloud.google.com/iam/docs/understanding-roles#storage.objectViewer) |
-|SERVICE_IDENTITY_service-networking
serviceAccount|[roles/servicenetworking.serviceAgent](https://cloud.google.com/iam/docs/understanding-roles#servicenetworking.serviceAgent) +|
-|load-df
serviceAccount|[roles/bigquery.dataOwner](https://cloud.google.com/iam/docs/understanding-roles#bigquery.dataOwner)
[roles/bigquery.jobUser](https://cloud.google.com/iam/docs/understanding-roles#bigquery.jobUser)
[roles/storage.objectCreator](https://cloud.google.com/iam/docs/understanding-roles#storage.objectCreator) |
-|trf-bq
serviceAccount|[roles/bigquery.dataViewer](https://cloud.google.com/iam/docs/understanding-roles#bigquery.dataViewer)
[roles/datacatalog.categoryAdmin](https://cloud.google.com/iam/docs/understanding-roles#datacatalog.categoryAdmin) |
-|trf-df
serviceAccount|[roles/bigquery.dataViewer](https://cloud.google.com/iam/docs/understanding-roles#bigquery.dataViewer) |
-
-## Project lod
-
-| members | roles |
-|---|---|
-|gcp-data-engineers
group|[roles/dataflow.admin](https://cloud.google.com/iam/docs/understanding-roles#dataflow.admin)
[roles/dataflow.developer](https://cloud.google.com/iam/docs/understanding-roles#dataflow.developer) |
-|SERVICE_IDENTITY_dataflow-service-producer-prod
serviceAccount|[roles/storage.objectAdmin](https://cloud.google.com/iam/docs/understanding-roles#storage.objectAdmin) |
-|SERVICE_IDENTITY_service-networking
serviceAccount|[roles/servicenetworking.serviceAgent](https://cloud.google.com/iam/docs/understanding-roles#servicenetworking.serviceAgent) +|
-|load-df
serviceAccount|[roles/bigquery.jobUser](https://cloud.google.com/iam/docs/understanding-roles#bigquery.jobUser)
[roles/dataflow.admin](https://cloud.google.com/iam/docs/understanding-roles#dataflow.admin)
[roles/dataflow.worker](https://cloud.google.com/iam/docs/understanding-roles#dataflow.worker)
[roles/storage.objectAdmin](https://cloud.google.com/iam/docs/understanding-roles#storage.objectAdmin) |
-|orc-cmp
serviceAccount|[roles/dataflow.admin](https://cloud.google.com/iam/docs/understanding-roles#dataflow.admin) |
-
-## Project orc
-
-| members | roles |
-|---|---|
-|gcp-data-engineers
group|[roles/artifactregistry.admin](https://cloud.google.com/iam/docs/understanding-roles#artifactregistry.admin)
[roles/bigquery.dataEditor](https://cloud.google.com/iam/docs/understanding-roles#bigquery.dataEditor)
[roles/bigquery.jobUser](https://cloud.google.com/iam/docs/understanding-roles#bigquery.jobUser)
[roles/cloudbuild.builds.editor](https://cloud.google.com/iam/docs/understanding-roles#cloudbuild.builds.editor)
[roles/composer.admin](https://cloud.google.com/iam/docs/understanding-roles#composer.admin)
[roles/composer.environmentAndStorageObjectAdmin](https://cloud.google.com/iam/docs/understanding-roles#composer.environmentAndStorageObjectAdmin)
[roles/composer.user](https://cloud.google.com/iam/docs/understanding-roles#composer.user)
[roles/iam.serviceAccountUser](https://cloud.google.com/iam/docs/understanding-roles#iam.serviceAccountUser)
[roles/iap.httpsResourceAccessor](https://cloud.google.com/iam/docs/understanding-roles#iap.httpsResourceAccessor)
[roles/serviceusage.serviceUsageConsumer](https://cloud.google.com/iam/docs/understanding-roles#serviceusage.serviceUsageConsumer)
[roles/storage.objectAdmin](https://cloud.google.com/iam/docs/understanding-roles#storage.objectAdmin) |
-|SERVICE_IDENTITY_cloudcomposer-accounts
serviceAccount|[roles/composer.ServiceAgentV2Ext](https://cloud.google.com/iam/docs/understanding-roles#composer.ServiceAgentV2Ext)
[roles/storage.objectAdmin](https://cloud.google.com/iam/docs/understanding-roles#storage.objectAdmin) |
-|SERVICE_IDENTITY_gcp-sa-cloudbuild
serviceAccount|[roles/storage.objectAdmin](https://cloud.google.com/iam/docs/understanding-roles#storage.objectAdmin) |
-|SERVICE_IDENTITY_service-networking
serviceAccount|[roles/servicenetworking.serviceAgent](https://cloud.google.com/iam/docs/understanding-roles#servicenetworking.serviceAgent) +|
-|load-df
serviceAccount|[roles/artifactregistry.reader](https://cloud.google.com/iam/docs/understanding-roles#artifactregistry.reader)
[roles/bigquery.dataEditor](https://cloud.google.com/iam/docs/understanding-roles#bigquery.dataEditor)
[roles/storage.objectViewer](https://cloud.google.com/iam/docs/understanding-roles#storage.objectViewer) |
-|orc-cmp
serviceAccount|[roles/bigquery.jobUser](https://cloud.google.com/iam/docs/understanding-roles#bigquery.jobUser)
[roles/composer.worker](https://cloud.google.com/iam/docs/understanding-roles#composer.worker)
[roles/iam.serviceAccountUser](https://cloud.google.com/iam/docs/understanding-roles#iam.serviceAccountUser)
[roles/storage.objectAdmin](https://cloud.google.com/iam/docs/understanding-roles#storage.objectAdmin) |
-|orc-sa-df-build
serviceAccount|[roles/cloudbuild.serviceAgent](https://cloud.google.com/iam/docs/understanding-roles#cloudbuild.serviceAgent)
[roles/storage.objectAdmin](https://cloud.google.com/iam/docs/understanding-roles#storage.objectAdmin) |
-|trf-df
serviceAccount|[roles/bigquery.dataEditor](https://cloud.google.com/iam/docs/understanding-roles#bigquery.dataEditor) |
-
-## Project trf
-
-| members | roles |
-|---|---|
-|gcp-data-engineers
group|[roles/bigquery.jobUser](https://cloud.google.com/iam/docs/understanding-roles#bigquery.jobUser)
[roles/dataflow.admin](https://cloud.google.com/iam/docs/understanding-roles#dataflow.admin) |
-|SERVICE_IDENTITY_dataflow-service-producer-prod
serviceAccount|[roles/storage.objectAdmin](https://cloud.google.com/iam/docs/understanding-roles#storage.objectAdmin) |
-|SERVICE_IDENTITY_service-networking
serviceAccount|[roles/servicenetworking.serviceAgent](https://cloud.google.com/iam/docs/understanding-roles#servicenetworking.serviceAgent) +|
-|orc-cmp
serviceAccount|[roles/dataflow.admin](https://cloud.google.com/iam/docs/understanding-roles#dataflow.admin) |
-|trf-bq
serviceAccount|[roles/bigquery.jobUser](https://cloud.google.com/iam/docs/understanding-roles#bigquery.jobUser) |
-|trf-df
serviceAccount|[roles/dataflow.worker](https://cloud.google.com/iam/docs/understanding-roles#dataflow.worker)
[roles/storage.objectAdmin](https://cloud.google.com/iam/docs/understanding-roles#storage.objectAdmin) |
diff --git a/fast/stages/3-data-platform/dev/README.md b/fast/stages/3-data-platform/dev/README.md
deleted file mode 100644
index 419b020ca..000000000
--- a/fast/stages/3-data-platform/dev/README.md
+++ /dev/null
@@ -1,218 +0,0 @@
-# Data Platform
-
-The Data Platform builds on top of your foundations to create and set up projects (and related resources) to be used for your data platform.
-
-
-
-
-
-
data-platform-foundations | |
-| [outputs.tf](./outputs.tf) | Output variables. | | google_storage_bucket_object · local_file |
-| [variables-fast.tf](./variables-fast.tf) | Terraform Variables. | | |
-| [variables.tf](./variables.tf) | Terraform Variables. | | |
-
-## Variables
-
-| name | description | type | required | default | producer |
-|---|---|:---:|:---:|:---:|:---:|
-| [automation](variables-fast.tf#L17) | Automation resources created by the bootstrap stage. | object({…}) | ✓ | | 0-bootstrap |
-| [billing_account](variables-fast.tf#L25) | 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#L38) | Folder to be used for the networking resources in folders/nnnn format. | object({…}) | ✓ | | 1-resman |
-| [host_project_ids](variables-fast.tf#L46) | Shared VPC project ids. | object({…}) | ✓ | | 2-networking |
-| [organization](variables-fast.tf#L54) | Organization details. | object({…}) | ✓ | | 00-globals |
-| [prefix](variables-fast.tf#L64) | Prefix used for resources that need unique names. Use a maximum of 9 chars for organizations, and 11 chars for tenants. | string | ✓ | | 0-bootstrap |
-| [composer_config](variables.tf#L17) | Cloud Composer config. | object({…}) | | {…} | |
-| [data_catalog_tags](variables.tf#L106) | List of Data Catalog Policy tags to be created with optional IAM binging configuration in {tag => {ROLE => [MEMBERS]}} format. | map(object({…})) | | {…} | |
-| [deletion_protection](variables.tf#L120) | Prevent Terraform from destroying data storage resources (storage buckets, GKE clusters, CloudSQL instances) in this blueprint. When this field is set in Terraform state, a terraform destroy or terraform apply that would delete data storage resources will fail. | bool | | true | |
-| [groups_dp](variables.tf#L127) | Data Platform groups. | map(string) | | {…} | |
-| [location](variables.tf#L137) | Location used for multi-regional resources. | string | | "eu" | |
-| [network_config_composer](variables.tf#L143) | Network configurations to use for Composer. | object({…}) | | {…} | |
-| [outputs_location](variables.tf#L159) | Path where providers, tfvars files, and lists for the following stages are written. Leave empty to disable. | string | | null | |
-| [project_config](variables.tf#L165) | Provide projects configuration. | object({…}) | | {} | |
-| [project_services](variables.tf#L185) | List of core services enabled on all projects. | list(string) | | […] | |
-| [project_suffix](variables.tf#L196) | Suffix used only for project ids. | string | | null | |
-| [region](variables.tf#L202) | Region used for regional resources. | string | | "europe-west1" | |
-| [service_encryption_keys](variables.tf#L208) | Cloud KMS to use to encrypt different services. Key location should match service region. | object({…}) | | null | |
-| [subnet_self_links](variables-fast.tf#L74) | Shared VPC subnet self links. | object({…}) | | null | 2-networking |
-| [vpc_self_links](variables-fast.tf#L83) | Shared VPC self links. | object({…}) | | null | 2-networking |
-
-## Outputs
-
-| name | description | sensitive | consumers |
-|---|---|:---:|---|
-| [bigquery_datasets](outputs.tf#L42) | BigQuery datasets. | | |
-| [demo_commands](outputs.tf#L47) | Demo commands. | | |
-| [gcs_buckets](outputs.tf#L52) | GCS buckets. | | |
-| [projects](outputs.tf#L57) | GCP Projects information. | | |
-| [vpc_network](outputs.tf#L62) | VPC network. | | |
-| [vpc_subnet](outputs.tf#L67) | VPC subnetworks. | | |
-
diff --git a/fast/stages/3-data-platform/dev/demo b/fast/stages/3-data-platform/dev/demo
deleted file mode 120000
index 7a0e7c1e3..000000000
--- a/fast/stages/3-data-platform/dev/demo
+++ /dev/null
@@ -1 +0,0 @@
-../../../../blueprints/data-solutions/data-platform-foundations/demo/
\ No newline at end of file
diff --git a/fast/stages/3-data-platform/dev/diagram.png b/fast/stages/3-data-platform/dev/diagram.png
deleted file mode 100644
index 79b46e179..000000000
Binary files a/fast/stages/3-data-platform/dev/diagram.png and /dev/null differ
diff --git a/fast/stages/3-data-platform/dev/diagram_vpcsc.png b/fast/stages/3-data-platform/dev/diagram_vpcsc.png
deleted file mode 100644
index 2bbaad0b2..000000000
Binary files a/fast/stages/3-data-platform/dev/diagram_vpcsc.png and /dev/null differ
diff --git a/fast/stages/3-data-platform/dev/main.tf b/fast/stages/3-data-platform/dev/main.tf
deleted file mode 100644
index b27a575ff..000000000
--- a/fast/stages/3-data-platform/dev/main.tf
+++ /dev/null
@@ -1,56 +0,0 @@
-/**
- * Copyright 2023 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 Data Platform.
-
-module "data-platform" {
- source = "../../../../blueprints/data-solutions/data-platform-foundations"
- composer_config = var.composer_config
- deletion_protection = var.deletion_protection
- data_catalog_tags = var.data_catalog_tags
- project_config = {
- billing_account_id = var.billing_account.id
- project_create = var.project_config.project_create
- parent = var.folder_ids.data-platform-dev
- project_ids = var.project_config.project_ids
- }
- groups = var.groups_dp
- location = var.location
- network_config = {
- host_project = var.host_project_ids.dev-spoke-0
- network_self_link = var.vpc_self_links.dev-spoke-0
- subnet_self_links = {
- load = var.subnet_self_links.dev-spoke-0["europe-west1/dev-dataplatform-ew1"]
- transformation = var.subnet_self_links.dev-spoke-0["europe-west1/dev-dataplatform-ew1"]
- orchestration = var.subnet_self_links.dev-spoke-0["europe-west1/dev-dataplatform-ew1"]
- }
- # TODO: align example variable
- composer_ip_ranges = {
- cloudsql = var.network_config_composer.cloudsql_range
- gke_master = var.network_config_composer.gke_master_range
- }
- composer_secondary_ranges = {
- pods = var.network_config_composer.gke_pods_name
- services = var.network_config_composer.gke_services_name
- }
- }
- organization_domain = var.organization.domain
- prefix = "${var.prefix}-dev-dp"
- project_services = var.project_services
- project_suffix = var.project_suffix
- region = var.region
- service_encryption_keys = var.service_encryption_keys
-}
diff --git a/fast/stages/3-data-platform/dev/outputs.tf b/fast/stages/3-data-platform/dev/outputs.tf
deleted file mode 100644
index 3f9904621..000000000
--- a/fast/stages/3-data-platform/dev/outputs.tf
+++ /dev/null
@@ -1,70 +0,0 @@
-# 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
-#
-# https://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 Output variables.
-
-locals {
- tfvars = {
- bigquery_dataset = module.data-platform.bigquery-datasets
- gcs_buckets = module.data-platform.gcs-buckets
- projects = module.data-platform.projects
- }
-}
-
-# generate tfvars file for subsequent stages
-
-resource "local_file" "tfvars" {
- for_each = var.outputs_location == null ? {} : { 1 = 1 }
- file_permission = "0644"
- filename = "${pathexpand(var.outputs_location)}/tfvars/3-data-platform-dev.auto.tfvars.json"
- content = jsonencode(local.tfvars)
-}
-
-resource "google_storage_bucket_object" "tfvars" {
- bucket = var.automation.outputs_bucket
- name = "tfvars/3-data-platform-dev.auto.tfvars.json"
- content = jsonencode(local.tfvars)
-}
-
-# outputs
-
-output "bigquery_datasets" {
- description = "BigQuery datasets."
- value = module.data-platform.bigquery-datasets
-}
-
-output "demo_commands" {
- description = "Demo commands."
- value = module.data-platform.demo_commands
-}
-
-output "gcs_buckets" {
- description = "GCS buckets."
- value = module.data-platform.gcs-buckets
-}
-
-output "projects" {
- description = "GCP Projects information."
- value = module.data-platform.projects
-}
-
-output "vpc_network" {
- description = "VPC network."
- value = module.data-platform.vpc_network
-}
-
-output "vpc_subnet" {
- description = "VPC subnetworks."
- value = module.data-platform.vpc_subnet
-}
diff --git a/fast/stages/3-data-platform/dev/variables-fast.tf b/fast/stages/3-data-platform/dev/variables-fast.tf
deleted file mode 100644
index bd6ae628d..000000000
--- a/fast/stages/3-data-platform/dev/variables-fast.tf
+++ /dev/null
@@ -1,90 +0,0 @@
-# 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
-#
-# https://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 Terraform Variables.
-
-variable "automation" {
- # tfdoc:variable:source 0-bootstrap
- description = "Automation resources created by the bootstrap stage."
- type = object({
- outputs_bucket = string
- })
-}
-
-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 = "Folder to be used for the networking resources in folders/nnnn format."
- type = object({
- data-platform-dev = string
- })
-}
-
-variable "host_project_ids" {
- # tfdoc:variable:source 2-networking
- description = "Shared VPC project ids."
- type = object({
- dev-spoke-0 = string
- })
-}
-
-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 "subnet_self_links" {
- # tfdoc:variable:source 2-networking
- description = "Shared VPC subnet self links."
- type = object({
- dev-spoke-0 = map(string)
- })
- default = null
-}
-
-variable "vpc_self_links" {
- # tfdoc:variable:source 2-networking
- description = "Shared VPC self links."
- type = object({
- dev-spoke-0 = string
- })
- default = null
-}
diff --git a/fast/stages/3-data-platform/dev/variables.tf b/fast/stages/3-data-platform/dev/variables.tf
deleted file mode 100644
index a2d8271dc..000000000
--- a/fast/stages/3-data-platform/dev/variables.tf
+++ /dev/null
@@ -1,218 +0,0 @@
-# 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
-#
-# https://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 Terraform Variables.
-
-variable "composer_config" {
- description = "Cloud Composer config."
- type = object({
- disable_deployment = optional(bool)
- environment_size = optional(string, "ENVIRONMENT_SIZE_SMALL")
- software_config = optional(
- object({
- airflow_config_overrides = optional(any)
- pypi_packages = optional(any)
- env_variables = optional(map(string))
- image_version = string
- cloud_data_lineage_integration = optional(bool, true)
- }),
- { image_version = "composer-2-airflow-2" }
- )
- workloads_config = optional(
- object({
- scheduler = optional(
- object({
- cpu = number
- memory_gb = number
- storage_gb = number
- count = number
- }),
- {
- cpu = 0.5
- memory_gb = 1.875
- storage_gb = 1
- count = 1
- }
- )
- web_server = optional(
- object({
- cpu = number
- memory_gb = number
- storage_gb = number
- }),
- {
- cpu = 0.5
- memory_gb = 1.875
- storage_gb = 1
- }
- )
- worker = optional(
- object({
- cpu = number
- memory_gb = number
- storage_gb = number
- min_count = number
- max_count = number
- }),
- {
- cpu = 0.5
- memory_gb = 1.875
- storage_gb = 1
- min_count = 1
- max_count = 3
- }
- )
- }))
- })
- default = {
- environment_size = "ENVIRONMENT_SIZE_SMALL"
- software_config = {
- image_version = "composer-2-airflow-2"
- }
- workloads_config = {
- scheduler = {
- cpu = 0.5
- memory_gb = 1.875
- storage_gb = 1
- count = 1
- }
- web_server = {
- cpu = 0.5
- memory_gb = 1.875
- storage_gb = 1
- }
- worker = {
- cpu = 0.5
- memory_gb = 1.875
- storage_gb = 1
- min_count = 1
- max_count = 3
- }
- }
- }
-}
-
-variable "data_catalog_tags" {
- description = "List of Data Catalog Policy tags to be created with optional IAM binging configuration in {tag => {ROLE => [MEMBERS]}} format."
- type = map(object({
- description = optional(string)
- iam = optional(map(list(string)), {})
- }))
- nullable = false
- default = {
- "3_Confidential" = {}
- "2_Private" = {}
- "1_Sensitive" = {}
- }
-}
-
-variable "deletion_protection" {
- description = "Prevent Terraform from destroying data storage resources (storage buckets, GKE clusters, CloudSQL instances) in this blueprint. When this field is set in Terraform state, a terraform destroy or terraform apply that would delete data storage resources will fail."
- type = bool
- default = true
- nullable = false
-}
-
-variable "groups_dp" {
- description = "Data Platform groups."
- type = map(string)
- default = {
- data-analysts = "gcp-data-analysts"
- data-engineers = "gcp-data-engineers"
- data-security = "gcp-data-security"
- }
-}
-
-variable "location" {
- description = "Location used for multi-regional resources."
- type = string
- default = "eu"
-}
-
-variable "network_config_composer" {
- description = "Network configurations to use for Composer."
- type = object({
- cloudsql_range = string
- gke_master_range = string
- gke_pods_name = string
- gke_services_name = string
- })
- default = {
- cloudsql_range = "192.168.254.0/24"
- gke_master_range = "192.168.255.0/28"
- gke_pods_name = "pods"
- gke_services_name = "services"
- }
-}
-
-variable "outputs_location" {
- description = "Path where providers, tfvars files, and lists for the following stages are written. Leave empty to disable."
- type = string
- default = null
-}
-
-variable "project_config" {
- description = "Provide projects configuration."
- type = object({
- project_create = optional(bool, true)
- project_ids = optional(object({
- drop = string
- load = string
- orc = string
- trf = string
- dwh-lnd = string
- dwh-cur = string
- dwh-conf = string
- common = string
- exp = string
- })
- )
- })
- default = {}
-}
-
-variable "project_services" {
- description = "List of core services enabled on all projects."
- type = list(string)
- default = [
- "cloudresourcemanager.googleapis.com",
- "iam.googleapis.com",
- "serviceusage.googleapis.com",
- "stackdriver.googleapis.com"
- ]
-}
-
-variable "project_suffix" {
- description = "Suffix used only for project ids."
- type = string
- default = null
-}
-
-variable "region" {
- description = "Region used for regional resources."
- type = string
- default = "europe-west1"
-}
-
-variable "service_encryption_keys" {
- description = "Cloud KMS to use to encrypt different services. Key location should match service region."
- type = object({
- bq = string
- composer = string
- dataflow = string
- storage = string
- pubsub = string
- })
- default = null
-}
diff --git a/fast/stages/3-gcve-dev/.fast-stage.env b/fast/stages/3-gcve-dev/.fast-stage.env
new file mode 100644
index 000000000..84282438d
--- /dev/null
+++ b/fast/stages/3-gcve-dev/.fast-stage.env
@@ -0,0 +1,4 @@
+FAST_STAGE_DESCRIPTION="GCVE (dev)"
+FAST_STAGE_LEVEL=3
+FAST_STAGE_NAME=gcve-dev
+FAST_STAGE_DEPS="0-globals 0-bootstrap 1-resman 2-networking"
diff --git a/fast/stages/3-gcve-dev/README.md b/fast/stages/3-gcve-dev/README.md
new file mode 100644
index 000000000..611b844f6
--- /dev/null
+++ b/fast/stages/3-gcve-dev/README.md
@@ -0,0 +1,189 @@
+# GCVE Private Cloud Minimal
+
+This stage implements a simple architecture that integrates Google VMware Engine in a FAST organization.
+
+The setup configured here is for a single environment in a single region, and is provided as a starting point for the more complex patterns [described below in this document](#architectural-patterns) which can be easily implemented by extending this stage, and/or duplicating it across environments. Some configuration examples are provided in the [GCVE module](../../../modules/gcve-private-cloud/).
+
+
+- [Stage configuration](#stage-configuration)
+ - [Project-level IAM](#project-level-iam)
+ - [Networking](#networking)
+- [Architectural patterns](#architectural-patterns)
+ - [Single-region shared GCVE deployment](#single-region-shared-gcve-deployment)
+ - [Single-region per-environment GCVE deployment](#single-region-per-environment-gcve-deployment)
+ - [Multi-regional deployments](#multi-regional-deployments)
+- [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)
+- [Files](#files)
+- [Variables](#variables)
+- [Outputs](#outputs)
+
+
+## Stage configuration
+
+### Project-level IAM
+
+Project-level IAM is controlled via the `iam` and `iam_by_principals` variables, which allow controlling authoritative bindings on the project.
+
+To manage GCVE assign the `roles/vmwareengine.vmwareengineAdmin` and `roles/vmwareengine.vmwareengineViewer` roles to suitable groups via either of the above variables.
+
+### Networking
+
+Any of the FAST networking stages can be used to provide prerequisites for this stage. The development spoke VPC is used by default to attach the GCVE Private Cloud. To adapt this stage to production (or to a custom VPC) simply change the configuration of the GCVE module in the `main.tf` file.
+
+Peerings can be configured to additional VPCs via the `network_peerings` variable, provided the service account running this stage has suitable permissions on the VPCs. When running FAST, network projects matching this stage's environment already have the suitable IAM binding via the custom `gcveNetworkAdmin` role defined in the bootstrap stage. For custom setups outside of FAST, the [VMware Engine Admin role](https://cloud.google.com/iam/docs/understanding-roles#vmwareengine-roles) can be used.
+
+## Architectural patterns
+
+The patterns shown here can be achieved by combining this stage with the relevant networking stage, and configuring network peerings to achieve the desired connectivity layout. Different patterns can of course be implemented by modifying the default configuration.
+
+### Single-region shared GCVE deployment
+
+This approach creates one GCVE deployment in a single region connected to every environment. When using a networking stage with a dedicated landing VPC as in the first two diagrams, an additional peering is created there to allow connections to the Private Cloud from on premises.
+
+
+
+
+ With hub and spoke networking stage.
+
+
+
+ With separate environments networking stage.
+
+
+
+ With hub and spoke networking stage.
+
+
+
+ With separate environments networking stage.
+
+
+
gcve-private-cloud | google_vmwareengine_network_peering |
+| [main.tf](./main.tf) | Locals and project-level resources. | project | |
+| [outputs.tf](./outputs.tf) | Output variables. | | |
+| [variables-fast.tf](./variables-fast.tf) | FAST stage interface. | | |
+| [variables.tf](./variables.tf) | Module variables. | | |
+
+## Variables
+
+| name | description | type | required | default | producer |
+|---|---|:---:|:---:|:---:|:---:|
+| [billing_account](variables-fast.tf#L19) | Billing account id. If billing account is not part of the same org set `is_org_level` to false. | object({…}) | ✓ | | 0-bootstrap |
+| [environments](variables-fast.tf#L27) | Long environment names. | object({…}) | ✓ | | 1-resman |
+| [prefix](variables-fast.tf#L44) | Prefix used for resources that need unique names. Use a maximum of 9 chars for organizations, and 11 chars for tenants. | string | ✓ | | 0-bootstrap |
+| [folder_ids](variables-fast.tf#L37) | Folders used by FAST stages in folders/nnnnnnnnnnn format. | map(string) | | {} | 1-resman |
+| [iam](variables.tf#L17) | Project-level authoritative IAM bindings for users and service accounts in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | |
+| [iam_by_principals](variables.tf#L24) | Authoritative IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid cycle errors. Merged internally with the `iam` variable. | map(list(string)) | | {} | |
+| [network_peerings](variables.tf#L31) | The network peerings between users' VPCs and the VMware Engine networks. Key is used for the peering name suffix. Network is expanded for FAST defined networks. | map(object({…})) | | {…} | |
+| [private_cloud_configs](variables.tf#L54) | The VMware private cloud configurations. Key is used for the private cloud name suffix. | map(object({…})) | | {} | |
+| [stage_config](variables.tf#L76) | FAST stage configuration used to find resource ids. Must match name defined for the stage in resource management. | object({…}) | | {…} | |
+| [vpc_self_links](variables-fast.tf#L54) | FAST host VPC self links. | map(string) | | {} | 2-networking |
+
+## Outputs
+
+| name | description | sensitive | consumers |
+|---|---|:---:|---|
+| [network](outputs.tf#L17) | VMware engine network. | | |
+| [network_peerings](outputs.tf#L21) | The peerings created towards the user VPC or other VMware engine networks. | | |
+| [private_clouds](outputs.tf#L26) | VMware engine private cloud resources. | | |
+| [project_id](outputs.tf#L31) | GCVE project id. | | |
+
diff --git a/blueprints/gcve/pc-minimal/diagram.png b/fast/stages/3-gcve-dev/diagram.png
similarity index 100%
rename from blueprints/gcve/pc-minimal/diagram.png
rename to fast/stages/3-gcve-dev/diagram.png
diff --git a/fast/stages/3-gcve-dev/diagrams/diagram-multi-net-a.png b/fast/stages/3-gcve-dev/diagrams/diagram-multi-net-a.png
new file mode 100644
index 000000000..d2142dc2f
Binary files /dev/null and b/fast/stages/3-gcve-dev/diagrams/diagram-multi-net-a.png differ
diff --git a/fast/stages/3-gcve-dev/diagrams/diagram-multi-net-b.png b/fast/stages/3-gcve-dev/diagrams/diagram-multi-net-b.png
new file mode 100644
index 000000000..58b9817d5
Binary files /dev/null and b/fast/stages/3-gcve-dev/diagrams/diagram-multi-net-b.png differ
diff --git a/fast/stages/3-gcve-dev/diagrams/diagram-multi-net-c.png b/fast/stages/3-gcve-dev/diagrams/diagram-multi-net-c.png
new file mode 100644
index 000000000..321a8b2f0
Binary files /dev/null and b/fast/stages/3-gcve-dev/diagrams/diagram-multi-net-c.png differ
diff --git a/fast/stages/3-gcve-dev/diagrams/diagram-single-net-a.png b/fast/stages/3-gcve-dev/diagrams/diagram-single-net-a.png
new file mode 100644
index 000000000..746b2d508
Binary files /dev/null and b/fast/stages/3-gcve-dev/diagrams/diagram-single-net-a.png differ
diff --git a/fast/stages/3-gcve-dev/diagrams/diagram-single-net-c.png b/fast/stages/3-gcve-dev/diagrams/diagram-single-net-c.png
new file mode 100644
index 000000000..40b36fc9b
Binary files /dev/null and b/fast/stages/3-gcve-dev/diagrams/diagram-single-net-c.png differ
diff --git a/fast/stages/3-gcve-dev/gcve-pc.tf b/fast/stages/3-gcve-dev/gcve-pc.tf
new file mode 100644
index 000000000..d60d08db6
--- /dev/null
+++ b/fast/stages/3-gcve-dev/gcve-pc.tf
@@ -0,0 +1,58 @@
+/**
+ * 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 GCVE private cloud resources.
+
+locals {
+ network_peerings = {
+ for k, v in var.network_peerings : k => merge(v, {
+ # interpolate FAST VPC ids if available
+ peer_network = lookup(var.vpc_self_links, v.peer_network, v.peer_network)
+ })
+ }
+}
+
+module "gcve-pc" {
+ source = "../../../modules/gcve-private-cloud"
+ prefix = var.prefix
+ project_id = module.gcve-project-0.id
+ vmw_network_config = {
+ create = true
+ name = "default"
+ }
+ vmw_network_peerings = local.network_peerings
+ vmw_private_cloud_configs = var.private_cloud_configs
+}
+
+# optional reverse peering configuration from the peer network projects
+
+resource "google_vmwareengine_network_peering" "vmw_engine_network_peerings" {
+ for_each = {
+ for k, v in local.network_peerings : k => v if v.configure_peer_network
+ }
+ project = regex(
+ "projects/([^/]+)/", each.value.peer_network
+ )[0]
+ name = "${var.prefix}-${each.key}"
+ description = each.value.description
+ peer_network = each.value.peer_network
+ peer_network_type = "STANDARD"
+ vmware_engine_network = module.gcve-pc.network_id
+ export_custom_routes = each.value.routes_config.import
+ export_custom_routes_with_public_ip = each.value.routes_config.public_import
+ import_custom_routes = each.value.routes_config.export
+ import_custom_routes_with_public_ip = each.value.routes_config.public_export
+}
diff --git a/fast/stages/3-gcve-dev/main.tf b/fast/stages/3-gcve-dev/main.tf
new file mode 100644
index 000000000..2772f9df3
--- /dev/null
+++ b/fast/stages/3-gcve-dev/main.tf
@@ -0,0 +1,42 @@
+/**
+ * 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 Locals and project-level resources.
+
+locals {
+ folder_id = var.folder_ids[var.stage_config.name]
+}
+
+module "gcve-project-0" {
+ source = "../../../modules/project"
+ billing_account = var.billing_account.id
+ name = "dev-gcve-core-0"
+ parent = local.folder_id
+ prefix = var.prefix
+ iam = var.iam
+ iam_by_principals = var.iam_by_principals
+ labels = {
+ environment = lower(
+ var.environments[var.stage_config.environment].name
+ )
+ }
+ services = [
+ "compute.googleapis.com",
+ "logging.googleapis.com",
+ "monitoring.googleapis.com",
+ "vmwareengine.googleapis.com"
+ ]
+}
diff --git a/blueprints/gcve/pc-minimal/output.tf b/fast/stages/3-gcve-dev/outputs.tf
similarity index 67%
rename from blueprints/gcve/pc-minimal/output.tf
rename to fast/stages/3-gcve-dev/outputs.tf
index ba6f2ebfe..5dfd9e1ec 100644
--- a/blueprints/gcve/pc-minimal/output.tf
+++ b/fast/stages/3-gcve-dev/outputs.tf
@@ -14,27 +14,22 @@
# tfdoc:file:description Output variables.
+output "network" {
+ description = "VMware engine network."
+ value = module.gcve-pc.network_id
+}
+output "network_peerings" {
+ description = "The peerings created towards the user VPC or other VMware engine networks."
+ value = module.gcve-pc.network_peerings
+}
+
+output "private_clouds" {
+ description = "VMware engine private cloud resources."
+ value = module.gcve-pc.private_clouds
+}
+
output "project_id" {
description = "GCVE project id."
value = module.gcve-project-0.project_id
-}
-
-output "vmw_engine_network_config" {
- description = "VMware engine network configuration."
- value = module.gcve-pc.vmw_engine_network_config
-}
-
-output "vmw_engine_network_peerings" {
- description = "The peerings created towards the user VPC or other VMware engine networks."
- value = module.gcve-pc.vmw_engine_network_peerings
-}
-
-output "vmw_engine_private_clouds" {
- description = "VMware engine private cloud resources."
- value = module.gcve-pc.vmw_engine_private_clouds
-}
-
-output "vmw_private_cloud_network" {
- description = "VMware engine network."
- value = module.gcve-pc.vmw_private_cloud_network
+ depends_on = [module.gcve-pc]
}
diff --git a/fast/stages/3-gcve/prod/variables-fast.tf b/fast/stages/3-gcve-dev/variables-fast.tf
similarity index 56%
rename from fast/stages/3-gcve/prod/variables-fast.tf
rename to fast/stages/3-gcve-dev/variables-fast.tf
index de32e273c..fddbf7ec1 100644
--- a/fast/stages/3-gcve/prod/variables-fast.tf
+++ b/fast/stages/3-gcve-dev/variables-fast.tf
@@ -14,51 +14,31 @@
* limitations under the License.
*/
-variable "automation" {
- # tfdoc:variable:source 0-bootstrap
- description = "Automation resources created by the bootstrap stage."
- type = object({
- outputs_bucket = string
- })
-}
+# tfdoc:file:description FAST stage interface.
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)
+ id = string
+ })
+}
+
+variable "environments" {
+ # tfdoc:variable:source 1-resman
+ description = "Long environment names."
+ type = object({
+ dev = object({
+ name = string
+ })
})
- 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({
- gcve-prod = string
- })
-}
-
-variable "host_project_ids" {
- # tfdoc:variable:source 2-networking
- description = "Host project for the shared VPC."
- type = object({
- prod-spoke-0 = string
- })
-}
-
-variable "organization" {
- # tfdoc:variable:source 00-globals
- description = "Organization details."
- type = object({
- domain = string
- id = number
- customer_id = string
- })
+ description = "Folders used by FAST stages in folders/nnnnnnnnnnn format."
+ type = map(string)
+ default = {}
}
variable "prefix" {
@@ -73,10 +53,8 @@ variable "prefix" {
variable "vpc_self_links" {
# tfdoc:variable:source 2-networking
- description = "Self link for the shared VPC."
- type = object({
- prod-spoke-0 = string
- })
+ description = "FAST host VPC self links."
+ type = map(string)
+ nullable = false
+ default = {}
}
-
-
diff --git a/blueprints/gcve/pc-minimal/variables.tf b/fast/stages/3-gcve-dev/variables.tf
similarity index 53%
rename from blueprints/gcve/pc-minimal/variables.tf
rename to fast/stages/3-gcve-dev/variables.tf
index fa0c99e69..00ac24753 100644
--- a/blueprints/gcve/pc-minimal/variables.tf
+++ b/fast/stages/3-gcve-dev/variables.tf
@@ -14,25 +14,6 @@
* limitations under the License.
*/
-variable "billing_account_id" {
- description = "Billing account ID."
- type = string
-}
-
-variable "folder_id" {
- description = "Folder used for the GCVE project in folders/nnnnnnnnnnn format."
- type = string
-}
-
-variable "groups" {
- description = "GCVE groups."
- type = object({
- gcp-gcve-admins = string
- gcp-gcve-viewers = string
- })
- nullable = false
-}
-
variable "iam" {
description = "Project-level authoritative IAM bindings for users and service accounts in {ROLE => [MEMBERS]} format."
type = map(list(string))
@@ -47,52 +28,34 @@ variable "iam_by_principals" {
nullable = false
}
-variable "labels" {
- description = "Project-level labels."
- type = map(string)
- default = {}
-}
-
variable "network_peerings" {
- description = "The network peerings between users' VPCs and the VMware Engine networks. The key is the peering name suffix."
+ description = "The network peerings between users' VPCs and the VMware Engine networks. Key is used for the peering name suffix. Network is expanded for FAST defined networks."
type = map(object({
- peer_network = string
- configure_peer_network = optional(bool, false)
- custom_routes = optional(object({
- export_to_peer = optional(bool, false)
- import_from_peer = optional(bool, false)
- export_to_ven = optional(bool, false)
- import_from_ven = optional(bool, false)
- }), {})
- custom_routes_with_public_ip = optional(object({
- export_to_peer = optional(bool, false)
- import_from_peer = optional(bool, false)
- export_to_ven = optional(bool, false)
- import_from_ven = optional(bool, false)
- }), {})
+ peer_network = string
+ configure_peer_network = optional(bool, false)
description = optional(string, "Managed by Terraform.")
- peer_project_id = optional(string)
peer_to_vmware_engine_network = optional(bool, false)
+ routes_config = optional(object({
+ export = optional(bool, false)
+ import = optional(bool, false)
+ public_export = optional(bool, false)
+ public_import = optional(bool, false)
+ }), {})
}))
nullable = false
- default = {}
-}
-
-variable "prefix" {
- description = "Prefix used for resource names."
- type = string
- validation {
- condition = var.prefix != ""
- error_message = "Prefix cannot be empty."
+ default = {
+ dev-spoke-0 = {
+ peer_network = "dev-spoke-0"
+ configure_peer_network = true
+ }
}
}
variable "private_cloud_configs" {
- description = "The VMware private cloud configurations. The key is the unique private cloud name suffix."
+ description = "The VMware private cloud configurations. Key is used for the private cloud name suffix."
type = map(object({
cidr = string
zone = string
- # The key is the unique additional cluster name suffix
additional_cluster_configs = optional(map(object({
custom_core_count = optional(number)
node_count = optional(number, 3)
@@ -107,16 +70,17 @@ variable "private_cloud_configs" {
description = optional(string, "Managed by Terraform.")
}))
nullable = false
+ default = {}
}
-variable "project_id" {
- description = "ID of the project that will contain the GCVE private cloud."
- type = string
-}
-
-variable "project_services" {
- description = "Additional project services to enable."
- type = list(string)
- default = []
- nullable = false
+variable "stage_config" {
+ description = "FAST stage configuration used to find resource ids. Must match name defined for the stage in resource management."
+ type = object({
+ environment = string
+ name = string
+ })
+ default = {
+ environment = "dev"
+ name = "gcve-dev"
+ }
}
diff --git a/fast/stages/3-gcve/README.md b/fast/stages/3-gcve/README.md
deleted file mode 100644
index 5fb0cd0b8..000000000
--- a/fast/stages/3-gcve/README.md
+++ /dev/null
@@ -1,46 +0,0 @@
-# Google Cloud VMware Engine Stage
-
-The GCVE stage builds on top of your foundations to create and set up projects and related resources, used for your Google Cloud VMware Engine (GCVE) private cloud environments.
-It is organized in folders representing environments (e.g. `dev`, `prod`), each implemented by a stand-alone Terraform setup.
-
-This directory contains a [GCVE single region private cloud for the `prod` environment](./prod/) that can be used as-is or cloned with few changes to implement further environments. Refer to the example [`prod`/README.md](./prod/README.md) for configuration details.
-
-With this stage and the [GCVE blueprints](./../../../blueprints/gcve/), you can rapidly deploy production-ready GCVE environments. These environments are fully optimized to integrate seamlessly with your Fabric FAST network topology. Explore the deployment patterns below to find the perfect fit for your use case."
-
-## Single region deployments
-### Standalone VPC for a single GCVE deployment
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
pc-minimal | |
-| [outputs.tf](./outputs.tf) | Output variables. | | google_storage_bucket_object · local_file |
-| [variables-fast.tf](./variables-fast.tf) | None | | |
-| [variables.tf](./variables.tf) | Module variables. | | |
-
-## Variables
-
-| name | description | type | required | default | producer |
-|---|---|:---:|:---:|:---:|:---:|
-| [automation](variables-fast.tf#L17) | Automation resources created by the bootstrap stage. | object({…}) | ✓ | | 0-bootstrap |
-| [billing_account](variables-fast.tf#L25) | 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#L38) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | object({…}) | ✓ | | 1-resman |
-| [host_project_ids](variables-fast.tf#L46) | Host project for the shared VPC. | object({…}) | ✓ | | 2-networking |
-| [organization](variables-fast.tf#L54) | Organization details. | object({…}) | ✓ | | 00-globals |
-| [prefix](variables-fast.tf#L64) | Prefix used for resources that need unique names. Use a maximum of 9 chars for organizations, and 11 chars for tenants. | string | ✓ | | 0-bootstrap |
-| [private_cloud_configs](variables.tf#L49) | The VMware private cloud configurations. The key is the unique private cloud name suffix. | map(object({…})) | ✓ | | |
-| [vpc_self_links](variables-fast.tf#L74) | Self link for the shared VPC. | object({…}) | ✓ | | 2-networking |
-| [groups_gcve](variables.tf#L17) | GCVE groups. | object({…}) | | {…} | |
-| [iam](variables.tf#L30) | Project-level authoritative IAM bindings for users and service accounts in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | |
-| [labels](variables.tf#L37) | Project-level labels. | map(string) | | {} | |
-| [outputs_location](variables.tf#L43) | Path where providers, tfvars files, and lists for the following stages are written. Leave empty to disable. | string | | null | |
-| [project_services](variables.tf#L71) | Additional project services to enable. | list(string) | | [] | |
-
-## Outputs
-
-| name | description | sensitive | consumers |
-|---|---|:---:|---|
-| [project_id](outputs.tf#L46) | GCVE project id. | | |
-| [vmw_engine_network_config](outputs.tf#L51) | VMware engine network configuration. | | |
-| [vmw_engine_network_peerings](outputs.tf#L56) | The peerings created towards the user VPC or other VMware engine networks. | | |
-| [vmw_engine_private_clouds](outputs.tf#L61) | VMware engine private cloud resources. | | |
-| [vmw_private_cloud_network](outputs.tf#L66) | VMware engine network. | | |
-
diff --git a/fast/stages/3-gcve/prod/main.tf b/fast/stages/3-gcve/prod/main.tf
deleted file mode 100644
index 985314939..000000000
--- a/fast/stages/3-gcve/prod/main.tf
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * 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 GCVE private cloud for development environment.
-locals {
- groups_gcve = {
- for k, v in var.groups_gcve : k => (
- can(regex("^[a-zA-Z]+:", v))
- ? v
- : "group:${v}@${var.organization.domain}"
- )
- }
- peer_network = {
- for k, v in var.vpc_self_links : k => (
- trimprefix(v, "https://www.googleapis.com/compute/v1/")
- )
- }
-}
-
-module "gcve-pc" {
- source = "../../../../blueprints/gcve/pc-minimal"
- billing_account_id = var.billing_account.id
- folder_id = var.folder_ids.gcve-prod
- project_id = "gcve-0"
- groups = local.groups_gcve
- iam = var.iam
- labels = merge(var.labels, { environment = "prod" })
- prefix = "${var.prefix}-prod"
- project_services = var.project_services
-
- network_peerings = {
- prod-spoke-ven = {
- peer_network = local.peer_network.prod-spoke-0
- peer_project_id = var.host_project_ids.prod-spoke-0
- configure_peer_network = true
- custom_routes = {
- export_to_peer = true
- import_from_peer = true
- export_to_ven = true
- import_from_ven = true
- }
- }
- }
-
- private_cloud_configs = var.private_cloud_configs
-}
diff --git a/fast/stages/3-gcve/prod/outputs.tf b/fast/stages/3-gcve/prod/outputs.tf
deleted file mode 100644
index 5c97be028..000000000
--- a/fast/stages/3-gcve/prod/outputs.tf
+++ /dev/null
@@ -1,70 +0,0 @@
-# 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
-#
-# https://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 Output variables.
-
-locals {
- tfvars = {
- project_ids = {
- gcve-dev = module.gcve-pc.project_id
- }
- vmw_engine_network_config = module.gcve-pc.vmw_engine_network_config
- vmw_engine_network_peerings = module.gcve-pc.vmw_engine_network_peerings
- vmw_engine_private_clouds = module.gcve-pc.vmw_engine_private_clouds
- vmw_private_cloud_network = module.gcve-pc.vmw_private_cloud_network
- }
-}
-
-# generate tfvars file for subsequent stages
-
-resource "local_file" "tfvars" {
- for_each = var.outputs_location == null ? {} : { 1 = 1 }
- file_permission = "0644"
- filename = "${pathexpand(var.outputs_location)}/tfvars/3-gcve-dev.auto.tfvars.json"
- content = jsonencode(local.tfvars)
-}
-
-resource "google_storage_bucket_object" "tfvars" {
- bucket = var.automation.outputs_bucket
- name = "tfvars/3-gcve-dev.auto.tfvars.json"
- content = jsonencode(local.tfvars)
-}
-
-# outputs
-
-output "project_id" {
- description = "GCVE project id."
- value = module.gcve-pc.project_id
-}
-
-output "vmw_engine_network_config" {
- description = "VMware engine network configuration."
- value = module.gcve-pc.vmw_engine_network_config
-}
-
-output "vmw_engine_network_peerings" {
- description = "The peerings created towards the user VPC or other VMware engine networks."
- value = module.gcve-pc.vmw_engine_network_peerings
-}
-
-output "vmw_engine_private_clouds" {
- description = "VMware engine private cloud resources."
- value = module.gcve-pc.vmw_engine_private_clouds
-}
-
-output "vmw_private_cloud_network" {
- description = "VMware engine network."
- value = module.gcve-pc.vmw_private_cloud_network
-}
-
diff --git a/fast/stages/3-gcve/prod/variables.tf b/fast/stages/3-gcve/prod/variables.tf
deleted file mode 100644
index 451485c3d..000000000
--- a/fast/stages/3-gcve/prod/variables.tf
+++ /dev/null
@@ -1,76 +0,0 @@
-/**
- * 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 "groups_gcve" {
- description = "GCVE groups."
- type = object({
- gcp-gcve-admins = string
- gcp-gcve-viewers = string
- })
- default = {
- gcp-gcve-admins = "gcp-gcve-admins"
- gcp-gcve-viewers = "gcp-gcve-viewers"
- }
- nullable = false
-}
-
-variable "iam" {
- description = "Project-level authoritative IAM bindings for users and service accounts in {ROLE => [MEMBERS]} format."
- type = map(list(string))
- default = {}
- nullable = false
-}
-
-variable "labels" {
- description = "Project-level labels."
- type = map(string)
- default = {}
-}
-
-variable "outputs_location" {
- description = "Path where providers, tfvars files, and lists for the following stages are written. Leave empty to disable."
- type = string
- default = null
-}
-
-variable "private_cloud_configs" {
- description = "The VMware private cloud configurations. The key is the unique private cloud name suffix."
- type = map(object({
- cidr = string
- zone = string
- # The key is the unique additional cluster name suffix
- additional_cluster_configs = optional(map(object({
- custom_core_count = optional(number)
- node_count = optional(number, 3)
- node_type_id = optional(string, "standard-72")
- })), {})
- management_cluster_config = optional(object({
- custom_core_count = optional(number)
- name = optional(string, "mgmt-cluster")
- node_count = optional(number, 3)
- node_type_id = optional(string, "standard-72")
- }), {})
- description = optional(string, "Managed by Terraform.")
- }))
- nullable = false
-}
-
-variable "project_services" {
- description = "Additional project services to enable."
- type = list(string)
- default = []
- nullable = false
-}
diff --git a/fast/stages/3-gke-dev/.fast-stage.env b/fast/stages/3-gke-dev/.fast-stage.env
new file mode 100644
index 000000000..c16e68d5b
--- /dev/null
+++ b/fast/stages/3-gke-dev/.fast-stage.env
@@ -0,0 +1,4 @@
+FAST_STAGE_DESCRIPTION="GKE (dev)"
+FAST_STAGE_LEVEL=3
+FAST_STAGE_NAME=gke-dev
+FAST_STAGE_DEPS="0-globals 0-bootstrap 1-resman 2-networking"
diff --git a/fast/stages/3-gke-dev/README.md b/fast/stages/3-gke-dev/README.md
new file mode 100644
index 000000000..2fb479da6
--- /dev/null
+++ b/fast/stages/3-gke-dev/README.md
@@ -0,0 +1,216 @@
+# GKE Multitenant
+
+This stage allows creation and management of a fleet of GKE multitenant clusters for a single environment, optionally leveraging GKE Hub to configure additional features.
+
+The following diagram illustrates the high-level design of created resources, which can be adapted to specific requirements via variables:
+
+
+
+
gke-cluster-standard · gke-nodepool |
+| [gke-hub.tf](./gke-hub.tf) | GKE hub configuration. | gke-hub |
+| [main.tf](./main.tf) | Project and usage dataset. | bigquery-dataset · iam-service-account · project |
+| [outputs.tf](./outputs.tf) | Module outputs. | |
+| [variables-fast.tf](./variables-fast.tf) | None | |
+| [variables-fleet.tf](./variables-fleet.tf) | GKE fleet configurations. | |
+| [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 |
+| [environments](variables-fast.tf#L25) | Long environment names. | object({…}) | ✓ | | 1-resman |
+| [prefix](variables-fast.tf#L51) | Prefix used for resources that need unique names. Use a maximum of 9 chars for organizations, and 11 chars for tenants. | string | ✓ | | 0-bootstrap |
+| [clusters](variables.tf#L17) | Clusters configuration. Refer to the gke-cluster module for type details. | map(object({…})) | | {} | |
+| [deletion_protection](variables.tf#L88) | Prevent Terraform from destroying data resources. | bool | | false | |
+| [fleet_config](variables-fleet.tf#L19) | Fleet configuration. | object({…}) | | null | |
+| [fleet_configmanagement_templates](variables-fleet.tf#L35) | Sets of fleet configurations that can be applied to member clusters, in config name => {options} format. | map(object({…})) | | {} | |
+| [folder_ids](variables-fast.tf#L35) | Folder name => id mappings. | map(string) | | {} | 1-resman |
+| [host_project_ids](variables-fast.tf#L43) | Shared VPC host project name => id mappings. | map(string) | | {} | 2-networking |
+| [iam](variables.tf#L95) | Project-level authoritative IAM bindings for users and service accounts in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | |
+| [iam_by_principals](variables.tf#L102) | Authoritative IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid cycle errors. Merged internally with the `iam` variable. | map(list(string)) | | {} | |
+| [nodepools](variables.tf#L109) | Nodepools configuration. Refer to the gke-nodepool module for type details. | map(map(object({…}))) | | {} | |
+| [stage_config](variables.tf#L142) | FAST stage configuration used to find resource ids. Must match name defined for the stage in resource management. | object({…}) | | {…} | |
+| [subnet_self_links](variables-fast.tf#L61) | Subnet VPC name => { name => self link } mappings. | map(map(string)) | | {} | 2-networking |
+| [vpc_config](variables.tf#L154) | VPC-level configuration for project and clusters. | object({…}) | | {…} | |
+| [vpc_self_links](variables-fast.tf#L69) | Shared VPC name => self link mappings. | map(string) | | {} | 2-networking |
+
+## Outputs
+
+| name | description | sensitive | consumers |
+|---|---|:---:|---|
+| [cluster_ids](outputs.tf#L15) | Cluster ids. | | |
+| [clusters](outputs.tf#L22) | Cluster resources. | ✓ | |
+| [project_id](outputs.tf#L28) | GKE project id. | | |
+
diff --git a/blueprints/gke/multitenant-fleet/diagram.png b/fast/stages/3-gke-dev/diagram.png
similarity index 100%
rename from blueprints/gke/multitenant-fleet/diagram.png
rename to fast/stages/3-gke-dev/diagram.png
diff --git a/blueprints/gke/multitenant-fleet/gke-nodepools.tf b/fast/stages/3-gke-dev/gke-clusters.tf
similarity index 52%
rename from blueprints/gke/multitenant-fleet/gke-nodepools.tf
rename to fast/stages/3-gke-dev/gke-clusters.tf
index 46c9cae33..d88171167 100644
--- a/blueprints/gke/multitenant-fleet/gke-nodepools.tf
+++ b/fast/stages/3-gke-dev/gke-clusters.tf
@@ -1,5 +1,5 @@
/**
- * Copyright 2024 Google LLC
+ * Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-# tfdoc:file:description GKE nodepools.
+# tfdoc:file:description GKE clusters.
locals {
nodepools = merge([
@@ -26,6 +26,49 @@ locals {
})
}
]...)
+ subnet_self_links = try(
+ var.subnet_self_links[var.vpc_config.vpc_self_link], {}
+ )
+ vpc_self_link = lookup(
+ var.vpc_self_links,
+ var.vpc_config.vpc_self_link,
+ var.vpc_config.vpc_self_link
+ )
+}
+
+module "gke-cluster" {
+ source = "../../../modules/gke-cluster-standard"
+ for_each = var.clusters
+ name = each.key
+ project_id = module.gke-project-0.project_id
+ cluster_autoscaling = each.value.cluster_autoscaling
+ description = each.value.description
+ enable_features = each.value.enable_features
+ enable_addons = each.value.enable_addons
+ issue_client_certificate = each.value.issue_client_certificate
+ labels = each.value.labels
+ location = each.value.location
+ logging_config = each.value.logging_config
+ maintenance_config = each.value.maintenance_config
+ max_pods_per_node = each.value.max_pods_per_node
+ min_master_version = each.value.min_master_version
+ monitoring_config = each.value.monitoring_config
+ node_locations = each.value.node_locations
+ private_cluster_config = each.value.private_cluster_config
+ release_channel = each.value.release_channel
+ vpc_config = merge(each.value.vpc_config, {
+ network = try(
+ var.vpc_self_links[each.value.vpc_config.network],
+ each.value.vpc_config.network,
+ local.vpc_self_link
+ )
+ subnetwork = try(
+ local.subnet_self_links[each.value.vpc_config.subnetwork],
+ each.value.vpc_config.subnetwork,
+ null
+ )
+ })
+ deletion_protection = var.deletion_protection
}
module "gke-nodepool" {
diff --git a/blueprints/gke/multitenant-fleet/gke-hub.tf b/fast/stages/3-gke-dev/gke-hub.tf
similarity index 61%
rename from blueprints/gke/multitenant-fleet/gke-hub.tf
rename to fast/stages/3-gke-dev/gke-hub.tf
index 270704622..7ca8e4945 100644
--- a/blueprints/gke/multitenant-fleet/gke-hub.tf
+++ b/fast/stages/3-gke-dev/gke-hub.tf
@@ -17,29 +17,32 @@
# tfdoc:file:description GKE hub configuration.
locals {
- fleet_enabled = (
- var.fleet_features != null || var.fleet_workload_identity
- )
+ fleet_clusters = var.fleet_config == null ? {} : {
+ for k, v in var.clusters : k => v.configmanagement_template
+ if v.fleet_config.register == true
+ }
fleet_mcs_enabled = (
- try(var.fleet_features.multiclusterservicediscovery, false) == true
+ try(
+ var.fleet_config.enable_features.multiclusterservicediscovery, false
+ ) == true
)
}
module "gke-hub" {
source = "../../../modules/gke-hub"
- count = local.fleet_enabled ? 1 : 0
+ count = var.fleet_config != null ? 1 : 0
project_id = module.gke-project-0.project_id
clusters = {
- for cluster_id in keys(var.clusters) :
- cluster_id => module.gke-cluster[cluster_id].id
+ for k, v in local.fleet_clusters : k => module.gke-cluster[k].id
}
- features = var.fleet_features
+ features = var.fleet_config.enable_features
configmanagement_templates = var.fleet_configmanagement_templates
- configmanagement_clusters = var.fleet_configmanagement_clusters
+ configmanagement_clusters = {
+ for k, v in local.fleet_clusters : v => k...
+ }
workload_identity_clusters = (
- var.fleet_workload_identity ? keys(var.clusters) : []
+ var.fleet_config.use_workload_identity ? keys(local.fleet_clusters) : []
)
-
depends_on = [
module.gke-nodepool
]
diff --git a/blueprints/gke/multitenant-fleet/main.tf b/fast/stages/3-gke-dev/main.tf
similarity index 65%
rename from blueprints/gke/multitenant-fleet/main.tf
rename to fast/stages/3-gke-dev/main.tf
index 97fe5e538..5c8b9b331 100644
--- a/blueprints/gke/multitenant-fleet/main.tf
+++ b/fast/stages/3-gke-dev/main.tf
@@ -17,6 +17,7 @@
# tfdoc:file:description Project and usage dataset.
locals {
+ folder_id = var.folder_ids[var.stage_config.name]
gke_nodes_sa_roles = [
"autoscaling.metricsWriter",
"logging.logWriter",
@@ -24,47 +25,51 @@ locals {
"monitoring.metricWriter",
"stackdriver.resourceMetadata.writer"
]
+ project_name = "${var.stage_config.environment}-gke-core-0"
}
module "gke-project-0" {
- source = "../../../modules/project"
- billing_account = var.billing_account_id
- name = var.project_id
- parent = var.folder_id
- prefix = var.prefix
- iam_by_principals = var.iam_by_principals
- labels = var.labels
+ source = "../../../modules/project"
+ billing_account = var.billing_account.id
+ name = local.project_name
+ parent = local.folder_id
+ prefix = var.prefix
iam = merge(var.iam, {
"roles/gkehub.serviceAgent" = [
module.gke-project-0.service_agents.fleet.iam_email
] }
)
+ iam_by_principals = var.iam_by_principals
iam_bindings_additive = {
for r in local.gke_nodes_sa_roles : "gke-nodes-sa-${r}" => {
member = module.gke-nodes-service-account.iam_email
role = "roles/${r}"
}
}
- services = concat(
- [
- "anthos.googleapis.com",
- "anthosconfigmanagement.googleapis.com",
- "cloudresourcemanager.googleapis.com",
- "container.googleapis.com",
- "dns.googleapis.com",
- "gkeconnect.googleapis.com",
- "gkehub.googleapis.com",
- "iam.googleapis.com",
- "multiclusteringress.googleapis.com",
- "multiclusterservicediscovery.googleapis.com",
- "stackdriver.googleapis.com",
- "trafficdirector.googleapis.com"
- ],
- var.project_services
- )
+ labels = {
+ environment = lower(var.environments[var.stage_config.environment].name)
+ }
+ services = [
+ "anthos.googleapis.com",
+ "anthosconfigmanagement.googleapis.com",
+ "cloudresourcemanager.googleapis.com",
+ "container.googleapis.com",
+ "dns.googleapis.com",
+ "gkeconnect.googleapis.com",
+ "gkehub.googleapis.com",
+ "iam.googleapis.com",
+ "multiclusteringress.googleapis.com",
+ "multiclusterservicediscovery.googleapis.com",
+ "stackdriver.googleapis.com",
+ "trafficdirector.googleapis.com"
+ ]
shared_vpc_service_config = {
- attach = true
- host_project = var.vpc_config.host_project_id
+ attach = true
+ host_project = lookup(
+ var.host_project_ids,
+ var.vpc_config.host_project_id,
+ var.vpc_config.host_project_id
+ )
service_agent_iam = merge({
"roles/compute.networkUser" = [
"cloudservices", "container-engine"
@@ -76,7 +81,7 @@ module "gke-project-0" {
!local.fleet_mcs_enabled ? {} : {
"roles/multiclusterservicediscovery.serviceAgent" = ["mcsd"]
"roles/compute.networkViewer" = [
- "serviceAccount:${var.prefix}-${var.project_id}.svc.id.goog[gke-mcs/gke-mcs-importer]"
+ "serviceAccount:${var.prefix}-${local.project_name}.svc.id.goog[gke-mcs/gke-mcs-importer]"
]
})
}
diff --git a/blueprints/gke/multitenant-fleet/outputs.tf b/fast/stages/3-gke-dev/outputs.tf
similarity index 95%
rename from blueprints/gke/multitenant-fleet/outputs.tf
rename to fast/stages/3-gke-dev/outputs.tf
index 11d9d217a..1b7f7fcac 100644
--- a/blueprints/gke/multitenant-fleet/outputs.tf
+++ b/fast/stages/3-gke-dev/outputs.tf
@@ -12,8 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# tfdoc:file:description Output variables.
-
output "cluster_ids" {
description = "Cluster ids."
value = {
@@ -23,6 +21,7 @@ output "cluster_ids" {
output "clusters" {
description = "Cluster resources."
+ sensitive = true
value = module.gke-cluster
}
diff --git a/fast/stages/3-gke-multitenant/dev/variables-fast.tf b/fast/stages/3-gke-dev/variables-fast.tf
similarity index 65%
rename from fast/stages/3-gke-multitenant/dev/variables-fast.tf
rename to fast/stages/3-gke-dev/variables-fast.tf
index 8c8251aef..dfa1916f7 100644
--- a/fast/stages/3-gke-multitenant/dev/variables-fast.tf
+++ b/fast/stages/3-gke-dev/variables-fast.tf
@@ -14,41 +14,38 @@
* limitations under the License.
*/
-variable "automation" {
- # tfdoc:variable:source 0-bootstrap
- description = "Automation resources created by the bootstrap stage."
- type = object({
- outputs_bucket = string
- })
-}
-
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)
+ id = string
+ })
+}
+
+variable "environments" {
+ # tfdoc:variable:source 1-resman
+ description = "Long environment names."
+ type = object({
+ dev = object({
+ name = string
+ })
})
- 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({
- gke-dev = string
- })
+ description = "Folder name => id mappings."
+ type = map(string)
+ nullable = false
+ default = {}
}
variable "host_project_ids" {
# tfdoc:variable:source 2-networking
- description = "Host project for the shared VPC."
- type = object({
- dev-spoke-0 = string
- })
+ description = "Shared VPC host project name => id mappings."
+ type = map(string)
+ nullable = false
+ default = {}
}
variable "prefix" {
@@ -61,10 +58,18 @@ variable "prefix" {
}
}
+variable "subnet_self_links" {
+ # tfdoc:variable:source 2-networking
+ description = "Subnet VPC name => { name => self link } mappings."
+ type = map(map(string))
+ nullable = false
+ default = {}
+}
+
variable "vpc_self_links" {
# tfdoc:variable:source 2-networking
- description = "Self link for the shared VPC."
- type = object({
- dev-spoke-0 = string
- })
+ description = "Shared VPC name => self link mappings."
+ type = map(string)
+ nullable = false
+ default = {}
}
diff --git a/fast/stages/3-gke-dev/variables-fleet.tf b/fast/stages/3-gke-dev/variables-fleet.tf
new file mode 100644
index 000000000..4d71600e2
--- /dev/null
+++ b/fast/stages/3-gke-dev/variables-fleet.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 GKE fleet configurations.
+
+variable "fleet_config" {
+ description = "Fleet configuration."
+ type = object({
+ enable_features = optional(object({
+ appdevexperience = optional(bool, false)
+ configmanagement = optional(bool, false)
+ identityservice = optional(bool, false)
+ multiclusteringress = optional(string, null)
+ multiclusterservicediscovery = optional(bool, false)
+ servicemesh = optional(bool, false)
+ }), {})
+ use_workload_identity = optional(bool, false)
+ })
+ default = null
+}
+
+variable "fleet_configmanagement_templates" {
+ description = "Sets of fleet configurations that can be applied to member clusters, in config name => {options} format."
+ type = map(object({
+ binauthz = optional(bool)
+ version = optional(string)
+ config_sync = object({
+ git = optional(object({
+ sync_repo = string
+ policy_dir = string
+ gcp_service_account_email = optional(string)
+ https_proxy = optional(string)
+ secret_type = optional(string, "none")
+ sync_branch = optional(string)
+ sync_rev = optional(string)
+ sync_wait_secs = optional(number)
+ }))
+ prevent_drift = optional(bool)
+ source_format = optional(string, "hierarchy")
+ })
+ hierarchy_controller = optional(object({
+ enable_hierarchical_resource_quota = optional(bool)
+ enable_pod_tree_labels = optional(bool)
+ }))
+ policy_controller = object({
+ audit_interval_seconds = optional(number)
+ exemptable_namespaces = optional(list(string))
+ log_denies_enabled = optional(bool)
+ referential_rules_enabled = optional(bool)
+ template_library_installed = optional(bool)
+ })
+ }))
+ default = {}
+ nullable = false
+}
diff --git a/blueprints/gke/multitenant-fleet/variables.tf b/fast/stages/3-gke-dev/variables.tf
similarity index 67%
rename from blueprints/gke/multitenant-fleet/variables.tf
rename to fast/stages/3-gke-dev/variables.tf
index 96ed616c9..496bb954b 100644
--- a/blueprints/gke/multitenant-fleet/variables.tf
+++ b/fast/stages/3-gke-dev/variables.tf
@@ -14,11 +14,6 @@
* limitations under the License.
*/
-variable "billing_account_id" {
- description = "Billing account ID."
- type = string
-}
-
variable "clusters" {
description = "Clusters configuration. Refer to the gke-cluster module for type details."
type = map(object({
@@ -31,6 +26,10 @@ variable "clusters" {
shielded_nodes = true
workload_identity = true
})
+ fleet_config = optional(object({
+ register = optional(bool, true)
+ configmanagement_template = optional(string)
+ }), {})
issue_client_certificate = optional(bool, false)
labels = optional(map(string))
location = string
@@ -87,52 +86,12 @@ variable "clusters" {
}
variable "deletion_protection" {
- description = "Prevent Terraform from destroying data storage resources (storage buckets, GKE clusters, CloudSQL instances) in this blueprint. When this field is set in Terraform state, a terraform destroy or terraform apply that would delete data storage resources will fail."
+ description = "Prevent Terraform from destroying data resources."
type = bool
default = false
nullable = false
}
-variable "fleet_configmanagement_clusters" {
- description = "Config management features enabled on specific sets of member clusters, in config name => [cluster name] format."
- type = map(list(string))
- default = {}
- nullable = false
-}
-
-variable "fleet_configmanagement_templates" {
- description = "Sets of config management configurations that can be applied to member clusters, in config name => {options} format."
- # refer to the gke-hub module for the full type
- type = map(any)
- default = {}
- nullable = false
-}
-
-variable "fleet_features" {
- description = "Enable and configure fleet features. Set to null to disable GKE Hub if fleet workload identity is not used."
- type = object({
- appdevexperience = optional(bool, false)
- configmanagement = optional(bool, false)
- identityservice = optional(bool, false)
- multiclusteringress = optional(string, null)
- multiclusterservicediscovery = optional(bool, false)
- servicemesh = optional(bool, false)
- })
- default = null
-}
-
-variable "fleet_workload_identity" {
- description = "Use Fleet Workload Identity for clusters. Enables GKE Hub if set to true."
- type = bool
- default = false
- nullable = false
-}
-
-variable "folder_id" {
- description = "Folder used for the GKE project in folders/nnnnnnnnnnn format."
- type = string
-}
-
variable "iam" {
description = "Project-level authoritative IAM bindings for users and service accounts in {ROLE => [MEMBERS]} format."
type = map(list(string))
@@ -147,12 +106,6 @@ variable "iam_by_principals" {
nullable = false
}
-variable "labels" {
- description = "Project-level labels."
- type = map(string)
- default = {}
-}
-
variable "nodepools" {
description = "Nodepools configuration. Refer to the gke-nodepool module for type details."
type = map(map(object({
@@ -186,31 +139,27 @@ variable "nodepools" {
nullable = false
}
-variable "prefix" {
- description = "Prefix used for resource names."
- type = string
- validation {
- condition = var.prefix != ""
- error_message = "Prefix cannot be empty."
+variable "stage_config" {
+ description = "FAST stage configuration used to find resource ids. Must match name defined for the stage in resource management."
+ type = object({
+ environment = string
+ name = string
+ })
+ default = {
+ environment = "dev"
+ name = "gke-dev"
}
}
-variable "project_id" {
- description = "ID of the project that will contain all the clusters."
- type = string
-}
-
-variable "project_services" {
- description = "Additional project services to enable."
- type = list(string)
- default = []
- nullable = false
-}
-
variable "vpc_config" {
- description = "Shared VPC project and VPC details."
+ description = "VPC-level configuration for project and clusters."
type = object({
host_project_id = string
vpc_self_link = string
})
+ nullable = false
+ default = {
+ host_project_id = "dev-spoke-0"
+ vpc_self_link = "dev-spoke-0"
+ }
}
diff --git a/fast/stages/3-gke-multitenant/README.md b/fast/stages/3-gke-multitenant/README.md
deleted file mode 100644
index f5d73a490..000000000
--- a/fast/stages/3-gke-multitenant/README.md
+++ /dev/null
@@ -1,9 +0,0 @@
-# GKE Multitenant stage
-
-This directory contains a stage that can be used to centralize management of GKE multinenant clusters.
-
-The Terraform code follows the same general approach used for the [project factory](../2-project-factory/) and [data platform](../3-data-platform/) stages, where a "fat module" contains the stage code and is used by thin code wrappers that localize it for each environment or specialized configuration:
-
-The [`dev` folder](./dev/) contains an example setup for a generic development environment, and can be used as-is or cloned to implement other environments, or more specialized setups
-
-Refer to [the `dev` documentation](./dev/README.md) configuration details, and to [the `gke-serverless` documentation](../../../blueprints/gke/multitenant-fleet) for the architectural design and decisions taken.
diff --git a/fast/stages/3-gke-multitenant/dev/README.md b/fast/stages/3-gke-multitenant/dev/README.md
deleted file mode 100644
index 9247d5569..000000000
--- a/fast/stages/3-gke-multitenant/dev/README.md
+++ /dev/null
@@ -1,243 +0,0 @@
-# GKE Multitenant
-
-This stage allows creation and management of a fleet of GKE multitenant clusters, optionally leveraging GKE Hub to configure additional features. It's designed to be replicated once for every homogeneous set of clusters, either per environment or with more granularity as needed (e.g. teams or sets of teams sharing similar requirements).
-
-The following diagram illustrates the high-level design of created resources, which can be adapted to specific requirements via variables:
-
-
-
-
multitenant-fleet | |
-| [outputs.tf](./outputs.tf) | Output variables. | | google_storage_bucket_object · local_file |
-| [variables-fast.tf](./variables-fast.tf) | None | | |
-| [variables.tf](./variables.tf) | Module variables. | | |
-
-## Variables
-
-| name | description | type | required | default | producer |
-|---|---|:---:|:---:|:---:|:---:|
-| [automation](variables-fast.tf#L17) | Automation resources created by the bootstrap stage. | object({…}) | ✓ | | 0-bootstrap |
-| [billing_account](variables-fast.tf#L25) | 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#L38) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | object({…}) | ✓ | | 1-resman |
-| [host_project_ids](variables-fast.tf#L46) | Host project for the shared VPC. | object({…}) | ✓ | | 2-networking |
-| [prefix](variables-fast.tf#L54) | 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#L64) | Self link for the shared VPC. | object({…}) | ✓ | | 2-networking |
-| [clusters](variables.tf#L17) | Clusters configuration. Refer to the gke-cluster-standard module for type details. | map(object({…})) | | {} | |
-| [fleet_configmanagement_clusters](variables.tf#L87) | Config management features enabled on specific sets of member clusters, in config name => [cluster name] format. | map(list(string)) | | {} | |
-| [fleet_configmanagement_templates](variables.tf#L94) | Sets of config management configurations that can be applied to member clusters, in config name => {options} format. | map(object({…})) | | {} | |
-| [fleet_features](variables.tf#L129) | Enable and configure fleet features. Set to null to disable GKE Hub if fleet workload identity is not used. | object({…}) | | null | |
-| [fleet_workload_identity](variables.tf#L142) | Use Fleet Workload Identity for clusters. Enables GKE Hub if set to true. | bool | | false | |
-| [iam](variables.tf#L149) | Project-level authoritative IAM bindings for users and service accounts in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | |
-| [iam_by_principals](variables.tf#L156) | Authoritative IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid cycle errors. Merged internally with the `iam` variable. | map(list(string)) | | {} | |
-| [labels](variables.tf#L163) | Project-level labels. | map(string) | | {} | |
-| [nodepools](variables.tf#L169) | Nodepools configuration. Refer to the gke-nodepool module for type details. | map(map(object({…}))) | | {} | |
-| [outputs_location](variables.tf#L202) | Path where providers, tfvars files, and lists for the following stages are written. Leave empty to disable. | string | | null | |
-| [project_services](variables.tf#L208) | Additional project services to enable. | list(string) | | [] | |
-
-## Outputs
-
-| name | description | sensitive | consumers |
-|---|---|:---:|---|
-| [cluster_ids](outputs.tf#L57) | Cluster ids. | | |
-| [clusters](outputs.tf#L62) | Cluster resources. | ✓ | |
-| [project_id](outputs.tf#L68) | GKE project id. | | |
-
diff --git a/fast/stages/3-gke-multitenant/dev/diagram.png b/fast/stages/3-gke-multitenant/dev/diagram.png
deleted file mode 100644
index a282e7d5e..000000000
Binary files a/fast/stages/3-gke-multitenant/dev/diagram.png and /dev/null differ
diff --git a/fast/stages/3-gke-multitenant/dev/main.tf b/fast/stages/3-gke-multitenant/dev/main.tf
deleted file mode 100644
index 261b2477c..000000000
--- a/fast/stages/3-gke-multitenant/dev/main.tf
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * 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 GKE multitenant for development environment.
-
-module "gke-multitenant" {
- source = "../../../../blueprints/gke/multitenant-fleet"
- billing_account_id = var.billing_account.id
- folder_id = var.folder_ids.gke-dev
- project_id = "gke-0"
- iam_by_principals = var.iam_by_principals
- iam = var.iam
- labels = merge(var.labels, { environment = "dev" })
- prefix = "${var.prefix}-dev"
- project_services = var.project_services
- vpc_config = {
- host_project_id = var.host_project_ids.dev-spoke-0
- vpc_self_link = var.vpc_self_links.dev-spoke-0
- }
- clusters = var.clusters
- nodepools = var.nodepools
- fleet_configmanagement_clusters = var.fleet_configmanagement_clusters
- fleet_configmanagement_templates = var.fleet_configmanagement_templates
- fleet_features = var.fleet_features
- fleet_workload_identity = var.fleet_workload_identity
-}
diff --git a/fast/stages/3-gke-multitenant/dev/outputs.tf b/fast/stages/3-gke-multitenant/dev/outputs.tf
deleted file mode 100644
index a3f7165db..000000000
--- a/fast/stages/3-gke-multitenant/dev/outputs.tf
+++ /dev/null
@@ -1,71 +0,0 @@
-# Copyright 2023 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
-#
-# https://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.
-
-# Copyright 2023 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
-#
-# https://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 Output variables.
-
-locals {
- tfvars = {
- clusters = module.gke-multitenant.cluster_ids
- project_ids = {
- gke-dev = module.gke-multitenant.project_id
- }
- }
-}
-
-# generate tfvars file for subsequent stages
-
-resource "local_file" "tfvars" {
- for_each = var.outputs_location == null ? {} : { 1 = 1 }
- file_permission = "0644"
- filename = "${pathexpand(var.outputs_location)}/tfvars/3-gke-dev.auto.tfvars.json"
- content = jsonencode(local.tfvars)
-}
-
-resource "google_storage_bucket_object" "tfvars" {
- bucket = var.automation.outputs_bucket
- name = "tfvars/3-gke-dev.auto.tfvars.json"
- content = jsonencode(local.tfvars)
-}
-
-# outputs
-
-output "cluster_ids" {
- description = "Cluster ids."
- value = module.gke-multitenant.cluster_ids
-}
-
-output "clusters" {
- description = "Cluster resources."
- value = module.gke-multitenant.clusters
- sensitive = true
-}
-
-output "project_id" {
- description = "GKE project id."
- value = module.gke-multitenant.project_id
-}
diff --git a/fast/stages/3-gke-multitenant/dev/variables.tf b/fast/stages/3-gke-multitenant/dev/variables.tf
deleted file mode 100644
index 80feb23a7..000000000
--- a/fast/stages/3-gke-multitenant/dev/variables.tf
+++ /dev/null
@@ -1,213 +0,0 @@
-/**
- * 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 "clusters" {
- description = "Clusters configuration. Refer to the gke-cluster-standard module for type details."
- type = map(object({
- cluster_autoscaling = optional(any)
- description = optional(string)
- enable_addons = optional(any, {
- horizontal_pod_autoscaling = true, http_load_balancing = true
- })
- enable_features = optional(any, {
- shielded_nodes = true
- workload_identity = true
- })
- issue_client_certificate = optional(bool, false)
- labels = optional(map(string))
- location = string
- logging_config = optional(object({
- enable_system_logs = optional(bool, true)
- enable_workloads_logs = optional(bool, true)
- enable_api_server_logs = optional(bool, false)
- enable_scheduler_logs = optional(bool, false)
- enable_controller_manager_logs = optional(bool, false)
- }), {})
- maintenance_config = optional(any, {
- daily_window_start_time = "03:00"
- recurring_window = null
- maintenance_exclusion = []
- })
- max_pods_per_node = optional(number, 110)
- min_master_version = optional(string)
- monitoring_config = optional(object({
- enable_system_metrics = optional(bool, true)
-
- # (Optional) control plane metrics
- enable_api_server_metrics = optional(bool, false)
- enable_controller_manager_metrics = optional(bool, false)
- enable_scheduler_metrics = optional(bool, false)
-
- # (Optional) kube state metrics
- enable_daemonset_metrics = optional(bool, false)
- enable_deployment_metrics = optional(bool, false)
- enable_hpa_metrics = optional(bool, false)
- enable_pod_metrics = optional(bool, false)
- enable_statefulset_metrics = optional(bool, false)
- enable_storage_metrics = optional(bool, false)
-
- # Google Cloud Managed Service for Prometheus
- enable_managed_prometheus = optional(bool, true)
- }), {})
- node_locations = optional(list(string))
- private_cluster_config = optional(any)
- release_channel = optional(string)
- vpc_config = object({
- subnetwork = string
- network = optional(string)
- secondary_range_blocks = optional(object({
- pods = string
- services = string
- }))
- secondary_range_names = optional(object({
- pods = optional(string, "pods")
- services = optional(string, "services")
- }))
- master_authorized_ranges = optional(map(string))
- master_ipv4_cidr_block = optional(string)
- })
- }))
- default = {}
- nullable = false
-}
-
-variable "fleet_configmanagement_clusters" {
- description = "Config management features enabled on specific sets of member clusters, in config name => [cluster name] format."
- type = map(list(string))
- default = {}
- nullable = false
-}
-
-variable "fleet_configmanagement_templates" {
- description = "Sets of config management configurations that can be applied to member clusters, in config name => {options} format."
- type = map(object({
- binauthz = bool
- config_sync = object({
- git = object({
- gcp_service_account_email = string
- https_proxy = string
- policy_dir = string
- secret_type = string
- sync_branch = string
- sync_repo = string
- sync_rev = string
- sync_wait_secs = number
- })
- prevent_drift = string
- source_format = string
- })
- hierarchy_controller = object({
- enable_hierarchical_resource_quota = bool
- enable_pod_tree_labels = bool
- })
- policy_controller = object({
- audit_interval_seconds = number
- exemptable_namespaces = list(string)
- log_denies_enabled = bool
- referential_rules_enabled = bool
- template_library_installed = bool
- })
- version = string
- }))
- default = {}
- nullable = false
-}
-
-variable "fleet_features" {
- description = "Enable and configure fleet features. Set to null to disable GKE Hub if fleet workload identity is not used."
- type = object({
- appdevexperience = bool
- configmanagement = bool
- identityservice = bool
- multiclusteringress = string
- multiclusterservicediscovery = bool
- servicemesh = bool
- })
- default = null
-}
-
-variable "fleet_workload_identity" {
- description = "Use Fleet Workload Identity for clusters. Enables GKE Hub if set to true."
- type = bool
- default = false
- nullable = false
-}
-
-variable "iam" {
- description = "Project-level authoritative IAM bindings for users and service accounts in {ROLE => [MEMBERS]} format."
- type = map(list(string))
- default = {}
- nullable = false
-}
-
-variable "iam_by_principals" {
- description = "Authoritative IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid cycle errors. Merged internally with the `iam` variable."
- type = map(list(string))
- default = {}
- nullable = false
-}
-
-variable "labels" {
- description = "Project-level labels."
- type = map(string)
- default = {}
-}
-
-variable "nodepools" {
- description = "Nodepools configuration. Refer to the gke-nodepool module for type details."
- type = map(map(object({
- gke_version = optional(string)
- k8s_labels = optional(map(string), {})
- max_pods_per_node = optional(number)
- name = optional(string)
- node_config = optional(any, {
- disk_type = "pd-balanced"
- shielded_instance_config = {
- enable_integrity_monitoring = true
- enable_secure_boot = true
- }
- })
- node_count = optional(map(number), {
- initial = 1
- })
- node_locations = optional(list(string))
- nodepool_config = optional(any)
- pod_range = optional(any)
- reservation_affinity = optional(any)
- service_account = optional(any)
- sole_tenant_nodegroup = optional(string)
- tags = optional(list(string))
- taints = optional(map(object({
- value = string
- effect = string
- })))
- })))
- default = {}
- nullable = false
-}
-
-variable "outputs_location" {
- description = "Path where providers, tfvars files, and lists for the following stages are written. Leave empty to disable."
- type = string
- default = null
-}
-
-variable "project_services" {
- description = "Additional project services to enable."
- type = list(string)
- default = []
- nullable = false
-}
diff --git a/fast/stages/3-network-security/net-dev.tf b/fast/stages/3-network-security/net-dev.tf
deleted file mode 100644
index 461cd8db0..000000000
--- a/fast/stages/3-network-security/net-dev.tf
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * 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)
- # If TLS inspection is enabled, link the regional TLS inspection policy
- tls_inspection_policy = (
- var.ngfw_tls_configs.tls_enabled
- ? try(var.ngfw_tls_configs.tls_ip_ids_by_region.dev[substr(each.value, 0, length(each.value) - 2)], null)
- : 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
deleted file mode 100644
index d69638033..000000000
--- a/fast/stages/3-network-security/net-prod.tf
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * 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)
- # If TLS inspection is enabled, link the regional TLS inspection policy
- tls_inspection_policy = (
- var.ngfw_tls_configs.tls_enabled
- ? try(var.ngfw_tls_configs.tls_ip_ids_by_region.prod[substr(each.value, 0, length(each.value) - 2)], null)
- : 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
deleted file mode 100644
index ce93d8e51..000000000
--- a/fast/stages/3-network-security/outputs.tf
+++ /dev/null
@@ -1,28 +0,0 @@
-/**
- * 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/README.md b/fast/stages/README.md
index f50e8237e..6a30dcb01 100644
--- a/fast/stages/README.md
+++ b/fast/stages/README.md
@@ -4,16 +4,16 @@ Each of the folders contained here is a separate "stage", or Terraform root modu
Each stage can be run in isolation (for example to only bring up a hub and spoke VPC in an existing environment), but when combined together they form a modular setup that allows top-down configuration of a whole GCP organization.
-When combined together, each stage is designed to leverage the previous stage's resources and to provide outputs to the following stages via predefined contracts, that regulate what is exchanged.
+When deploying as part of a whole organization setup, each stage provides information on its resources to the following stages via predefined contracts, and each stage can pick and choose what to leverage from the preceding ones.
-This has two important consequences
+This has two important consequences:
-- any stage can be swapped out and replaced by different code as long as it respects the contract by providing a predefined set of outputs and optionally accepting a predefined set of variables
+- any stage can be swapped out and replaced by different code as long as it respects the contract, by providing a predefined set of outputs and optionally accepting a predefined set of variables
- data flow between stages can be partially automated (see [stage 0 documentation on output files](./0-bootstrap/README.md#output-files-and-cross-stage-variables)), reducing the effort and pain required to compile variables by hand
-One important assumption is that the flow of data is always forward looking, so no stage needs to depend on outputs generated further down the chain. This greatly simplifies both the logic and the implementation, and allows stages to be effectively independent.
+One important assumption is that the flow of data is always forward looking (or sideways for optional components), so no stage needs to depend on outputs generated further down the chain. This greatly simplifies both the logic and the implementation, and allows stages to be effectively independent.
-To achieve this, we rely on specific GCP functionality like [delegated role grants](https://medium.com/google-cloud/managing-gcp-service-usage-through-delegated-role-grants-a843610f2226) that allow controlled delegation of responsibilities, for example to allow managing IAM bindings at the organization level in different stages only for specific roles.
+To achieve this, we rely on specific GCP functionality like [delegated role grants](https://medium.com/google-cloud/managing-gcp-service-usage-through-delegated-role-grants-a843610f2226) to allow controlled delegation of responsibilities, and [conditional access via tags](https://cloud.google.com/iam/docs/tags-access-control) to constrain scope for organization-level roles or when specific resources are managed lower in the chain than IAM bindings.
Refer to each stage's documentation for a detailed description of its purpose, the architectural choices made in its design, and how it can be configured and wired together to terraform a whole GCP organization. The following is a brief overview of each stage.
@@ -44,10 +44,9 @@ Implemented as an [add-on stage 1](./1-tenant-factory/), with optional FAST comp
Exports: host project ids and numbers, vpc self links
- [Project Factory](./2-project-factory/)
YAML-based factory to create and configure application or team-level projects. Configuration includes VPC-level settings for Shared VPC, service-level configuration for CMEK encryption via centralized keys, and service account creation for workloads and applications. This stage can be cloned if an org-wide or dedicated per-environment factories are needed.
+- [Network Security](./2-network-security/) Optional stage that integrates with security and networking stages to manage a centralized [NGFW Enterprise](https://cloud.google.com/firewall/docs/about-firewalls) deployment.
## Environment-level resources (3)
-- [Networking Security](./3-network-security/) Manages NGFW Enterprise deployment for the production and development environments.
-- [Data Platform](3-data-platform/dev/)
-- [GKE Multitenant](3-gke-multitenant/dev/)
-- [Google Cloud VMware Engine](3-gcve/)
+- [GKE Multitenant](3-gke-dev/)
+- [Google Cloud VMware Engine](3-gcve-dev/)
diff --git a/fast/stages/UPGRADING.md b/fast/stages/UPGRADING.md
new file mode 100644
index 000000000..5a56c2689
--- /dev/null
+++ b/fast/stages/UPGRADING.md
@@ -0,0 +1,86 @@
+# FAST release upgrading notes
+
+This file only mentions changes that require changes to Terraform variables, or replace existing resources. "Soft" additions like new features or optional attributes are non-breaking and not considered here.
+
+We do an effort at covering most stages, but don't typically cover multitenant and stage 3s as there's too much variance in use cases and potential configurations.
+
+As usual, consider this a guideline with no guarantees. Migrations between FAST releases are actively doscouraged for production, and mostly make sense only when developing or testing new features.
+
+
+
+
+- [v35.1.0 to v36.0.0](#v3510-to-v3600)
+ - [Bootstrap stage](#bootstrap-stage)
+ - [Resource Management stage](#resource-management-stage)
+ - [Networking stages](#networking-stages)
+ - [Security stage](#security-stage)
+- [v34.0.0 to v35.1.0](#v3400-to-v3510)
+ - [Bootstrap stage](#bootstrap-stage)
+ - [Resource management stage](#resource-management-stage)
+ - [Networking](#networking)
+
+
+## v35.1.0 to v36.0.0
+
+### Bootstrap stage
+
+**Breaking changes:**
+
+- the `factories_config.org_policy` variable attribute has been renamed to `factories_config.org_policies`
+
+**Non-breaking changes:**
+
+- two new custom roles have been added: `gcveNetworkViewer` and `projectIAMViewer`
+- organization policies for the IaC project have been moved to a factory, default policies are in `data/org-policies-iac`
+- new `compute.setNewProjectDefaultToZonalDNSOnly` organization policy constraint has been added to mirror default configuration on new organizations
+
+### Resource Management stage
+
+The Resource Management stage has been largely refactored, adopting factories to simplify the creation of multiple environments and the creation and deployment of new "Stage 3" stages. Before upgrading it's highly recommended to familiarize yourself with the documentation, to assess whether your specific configurations need to be migrated to the new variables.
+
+The [file containing moved blocks](./1-resman/moved/v35.1.0-v36.0.0.tf) for this release can be used to preserve most of the important resources which changed from the previous release. Just link it in the stage and plan/apply to see the remaining changes.
+
+The moved blocks are not exhaustive and do not include resources that can be dropped and recreated with limited impact like IAM and tag bindings. As usual, proceed with care as we provide no guarantee, just a starting point.
+
+Given the amount of resource changes at the IAM level, we suggest applying twice in a row to make sure there are no inconsistencies left in IAM policies.
+
+**Breaking changes:**
+
+- variables controlling stage 2s and 3s have changed and are now explicit, check their configuration to make sure it matches your current layout
+ - the `fast_features` variable has been removed
+ - the `fast_stage_2` and `fast_stage_2` variables control now control stage activation and configuration
+- a new factory has been added for stage 3s, with an initial default configuration that matches enabling everything in the old fast features variable
+- the "Data Platform" stage 3 has been removed in preparation of a completely revised state, any associated resource (service accounts, folders, buckets, etc.) will be destroyed
+- billing IAM bindings will be destroyed and recreated as they are now driven by a loop and their names have changed
+- GCVE network IAM bindings will be destroyed and recreated as they are now segregated by environment
+
+**Non-breaking changes:**
+
+- GCS and local output files will be recreated
+
+### Networking stages
+
+IAM bindings for stage 3 service accounts change and will be dropped and recreated.
+
+### Security stage
+
+IAM bindings for stage 3 service accounts change and will be dropped and recreated.
+
+## v34.0.0 to v35.1.0
+
+### Bootstrap stage
+
+**Non-breaking changes:**
+
+- new `essentialcontacts.allowedContactDomains` organization policy constraint and `org-policies/allowed-essential-contacts-domains-all` tag; if the policy already exists in your organization, import it via state or delete it using `gcloud org-policy delete essentialcontacts.allowedContactDomains --organization ORGANIZATION_ID`
+
+### Resource management stage
+
+**Non-breaking changes:**
+
+- output files update
+- resource attribute updates following provider version change
+
+### Networking
+
+- additional DNS response policy for the `gke.goog` domain
diff --git a/fast/stages/diagrams.excalidraw.gz b/fast/stages/diagrams.excalidraw.gz
index ff33e9255..08138c507 100644
Binary files a/fast/stages/diagrams.excalidraw.gz and b/fast/stages/diagrams.excalidraw.gz differ
diff --git a/fast/stages/fast-links.sh b/fast/stages/fast-links.sh
new file mode 100755
index 000000000..eaa620691
--- /dev/null
+++ b/fast/stages/fast-links.sh
@@ -0,0 +1,82 @@
+#!/bin/bash
+# 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.
+
+if [ $# -eq 0 ]; then
+ echo "Error: no folder or GCS bucket specified. Use -h or --help for usage."
+ exit 1
+fi
+
+if [[ "$1" == "-h" || "$1" == "--help" ]]; then
+ cat <string | ✓ | |
+| [prefix](variables.tf#L17) | Prefix used in resource names. | string | ✓ | |
| [project_id](variables.tf#L22) | Project id. | string | ✓ | |
| [vmw_network_config](variables.tf#L27) | VMware Engine network configuration. | object({…}) | | {} |
-| [vmw_network_peerings](variables.tf#L44) | The network peerings towards users' VPCs or other VMware Engine networks. The key is the peering name suffix. | map(object({…})) | | {} |
-| [vmw_private_cloud_configs](variables.tf#L58) | The VMware private cloud configurations. The key is the unique private cloud name suffix. | map(object({…})) | | {…} |
+| [vmw_network_peerings](variables.tf#L44) | The network peerings towards users' VPCs or other VMware Engine networks. The key is the peering name suffix. | map(object({…})) | | {} |
+| [vmw_private_cloud_configs](variables.tf#L60) | The VMware private cloud configurations. The key is the unique private cloud name suffix. | map(object({…})) | | {…} |
## Outputs
| name | description | sensitive |
|---|---|:---:|
-| [vmw_engine_network_config](outputs.tf#L17) | VMware engine network configuration. | |
-| [vmw_engine_network_peerings](outputs.tf#L22) | The peerings created towards the user VPC or other VMware engine networks. | |
-| [vmw_engine_network_policies](outputs.tf#L27) | The network policies associated to the VMware engine network. | |
-| [vmw_engine_private_clouds](outputs.tf#L32) | VMware engine private cloud resources. | |
-| [vmw_private_cloud_network](outputs.tf#L37) | VMware engine network. | |
+| [network](outputs.tf#L17) | VMware engine network. | |
+| [network_id](outputs.tf#L22) | VMware engine network id. | |
+| [network_peerings](outputs.tf#L27) | The peerings created towards the user VPC or other VMware engine networks. | |
+| [network_policies](outputs.tf#L32) | The network policies associated to the VMware engine network. | |
+| [private_clouds](outputs.tf#L37) | VMware engine private cloud resources. | |
diff --git a/modules/gcve-private-cloud/main.tf b/modules/gcve-private-cloud/main.tf
index 4c7e9bd94..08e4eca7b 100644
--- a/modules/gcve-private-cloud/main.tf
+++ b/modules/gcve-private-cloud/main.tf
@@ -15,25 +15,33 @@
*/
locals {
- # Creates a map of additional clusters objects, including their parent private cloud
- additional_cluster_configs = merge(
- [for pcc_name, pcc in var.vmw_private_cloud_configs
- : { for cluster_name, cluster in pcc.additional_cluster_configs
- : (cluster_name) => merge(
- cluster,
- { parent = try(google_vmwareengine_private_cloud.vmw_engine_private_clouds[pcc_name].id, null) }
+ # aggregate clusters into a single map and add their parent private cloud
+ additional_cluster_configs = merge([
+ for pcc_name, pcc in var.vmw_private_cloud_configs : {
+ for cluster_name, cluster in pcc.additional_cluster_configs :
+ (cluster_name) => merge(cluster, {
+ parent = try(
+ google_vmwareengine_private_cloud.default[pcc_name].id,
+ null
)
- }
+ })
+ }
]...)
vmw_network = (
var.vmw_network_config.create
- ? try(google_vmwareengine_network.private_cloud_network[0], null)
- : try(data.google_vmwareengine_network.private_cloud_network[0], null)
+ ? try(google_vmwareengine_network.default[0], null)
+ : try(data.google_vmwareengine_network.default[0], null)
)
}
-resource "google_vmwareengine_network" "private_cloud_network" {
- provider = google-beta
+moved {
+ from = google_vmwareengine_network.private_cloud_network
+ to = google_vmwareengine_network.default
+}
+
+# network
+
+resource "google_vmwareengine_network" "default" {
count = var.vmw_network_config.create ? 1 : 0
project = var.project_id
name = "${var.prefix}-${var.vmw_network_config.name}"
@@ -42,7 +50,7 @@ resource "google_vmwareengine_network" "private_cloud_network" {
type = "STANDARD"
}
-data "google_vmwareengine_network" "private_cloud_network" {
+data "google_vmwareengine_network" "default" {
provider = google-beta
count = var.vmw_network_config.create ? 0 : 1
project = var.project_id
@@ -50,7 +58,14 @@ data "google_vmwareengine_network" "private_cloud_network" {
location = "global"
}
-resource "google_vmwareengine_network_policy" "vmw_engine_network_policies" {
+moved {
+ from = google_vmwareengine_network_policy.vmw_engine_network_policies
+ to = google_vmwareengine_network_policy.default
+}
+
+# network policy
+
+resource "google_vmwareengine_network_policy" "default" {
provider = google-beta
for_each = var.vmw_network_config.network_policies
project = var.project_id
@@ -59,48 +74,69 @@ resource "google_vmwareengine_network_policy" "vmw_engine_network_policies" {
edge_services_cidr = each.value.edge_services_cidr
location = each.value.region
vmware_engine_network = local.vmw_network.id
-
external_ip {
enabled = each.value.expose_on_internet
}
-
internet_access {
enabled = each.value.outbound_internet_access
}
}
-resource "google_vmwareengine_network_peering" "vmw_engine_network_peerings" {
+moved {
+ from = google_vmwareengine_network_peering.vmw_engine_network_peerings
+ to = google_vmwareengine_network_peering.default
+}
+
+# network peerings
+
+resource "google_vmwareengine_network_peering" "default" {
provider = google-beta
for_each = var.vmw_network_peerings
project = var.project_id
name = "${var.prefix}-${each.key}"
description = each.value.description
- export_custom_routes = each.value.export_custom_routes
- export_custom_routes_with_public_ip = each.value.export_custom_routes_with_public_ip
- import_custom_routes = each.value.import_custom_routes
- import_custom_routes_with_public_ip = each.value.import_custom_routes_with_public_ip
- peer_network = each.value.peer_network
- peer_network_type = each.value.peer_to_vmware_engine_network ? "VMWARE_ENGINE_NETWORK" : "STANDARD"
- vmware_engine_network = local.vmw_network.id
+ export_custom_routes = each.value.routes_config.export
+ export_custom_routes_with_public_ip = each.value.routes_config.public_export
+ import_custom_routes = each.value.routes_config.import
+ import_custom_routes_with_public_ip = each.value.routes_config.public_import
+ peer_network = trimprefix(
+ each.value.peer_network,
+ "https://www.googleapis.com/compute/v1/"
+ )
+ peer_network_type = (
+ each.value.peer_to_vmware_engine_network
+ ? "VMWARE_ENGINE_NETWORK"
+ : "STANDARD"
+ )
+ vmware_engine_network = local.vmw_network.id
}
-resource "google_vmwareengine_private_cloud" "vmw_engine_private_clouds" {
- provider = google-beta
+moved {
+ from = google_vmwareengine_private_cloud.vmw_engine_private_clouds
+ to = google_vmwareengine_private_cloud.default
+}
+
+# private cloud
+
+resource "google_vmwareengine_private_cloud" "default" {
for_each = var.vmw_private_cloud_configs
project = var.project_id
location = each.value.zone
name = "${var.prefix}-${each.key}"
description = each.value.description
-
- type = each.value.management_cluster_config.node_count == 1 ? "TIME_LIMITED" : "STANDARD"
-
+ type = (
+ each.value.management_cluster_config.node_count == 1
+ ? "TIME_LIMITED"
+ : "STANDARD"
+ )
network_config {
management_cidr = each.value.cidr
vmware_engine_network = local.vmw_network.id
}
-
management_cluster {
- cluster_id = "${var.prefix}-${each.key}-${each.value.management_cluster_config.name}"
+ cluster_id = (
+ "${var.prefix}-${each.key}-${each.value.management_cluster_config.name}"
+ )
node_type_configs {
node_type_id = each.value.management_cluster_config.node_type_id
node_count = each.value.management_cluster_config.node_count
@@ -109,7 +145,14 @@ resource "google_vmwareengine_private_cloud" "vmw_engine_private_clouds" {
}
}
-resource "google_vmwareengine_cluster" "vmw_engine_additional_clusters" {
+moved {
+ from = google_vmwareengine_cluster.vmw_engine_additional_clusters
+ to = google_vmwareengine_cluster.default
+}
+
+# cluster
+
+resource "google_vmwareengine_cluster" "default" {
provider = google-beta
for_each = local.additional_cluster_configs
name = "${var.prefix}-${each.key}"
diff --git a/modules/gcve-private-cloud/outputs.tf b/modules/gcve-private-cloud/outputs.tf
index f37883005..e42d98ce1 100644
--- a/modules/gcve-private-cloud/outputs.tf
+++ b/modules/gcve-private-cloud/outputs.tf
@@ -14,27 +14,27 @@
* limitations under the License.
*/
-output "vmw_engine_network_config" {
- description = "VMware engine network configuration."
+output "network" {
+ description = "VMware engine network."
value = local.vmw_network
}
-output "vmw_engine_network_peerings" {
+output "network_id" {
+ description = "VMware engine network id."
+ value = local.vmw_network.id
+}
+
+output "network_peerings" {
description = "The peerings created towards the user VPC or other VMware engine networks."
- value = google_vmwareengine_network_peering.vmw_engine_network_peerings
+ value = google_vmwareengine_network_peering.default
}
-output "vmw_engine_network_policies" {
+output "network_policies" {
description = "The network policies associated to the VMware engine network."
- value = google_vmwareengine_network_policy.vmw_engine_network_policies
+ value = google_vmwareengine_network_policy.default
}
-output "vmw_engine_private_clouds" {
+output "private_clouds" {
description = "VMware engine private cloud resources."
- value = google_vmwareengine_private_cloud.vmw_engine_private_clouds
-}
-
-output "vmw_private_cloud_network" {
- description = "VMware engine network."
- value = google_vmwareengine_network.private_cloud_network[0]
+ value = google_vmwareengine_private_cloud.default
}
diff --git a/modules/gcve-private-cloud/variables.tf b/modules/gcve-private-cloud/variables.tf
index 4ba680249..cc184a82b 100644
--- a/modules/gcve-private-cloud/variables.tf
+++ b/modules/gcve-private-cloud/variables.tf
@@ -15,7 +15,7 @@
*/
variable "prefix" {
- description = "Resources name prefix."
+ description = "Prefix used in resource names."
type = string
}
@@ -44,13 +44,15 @@ variable "vmw_network_config" {
variable "vmw_network_peerings" {
description = "The network peerings towards users' VPCs or other VMware Engine networks. The key is the peering name suffix."
type = map(object({
- peer_network = string
- description = optional(string, "Managed by Terraform.")
- export_custom_routes = optional(bool, false)
- export_custom_routes_with_public_ip = optional(bool, false)
- import_custom_routes = optional(bool, false)
- import_custom_routes_with_public_ip = optional(bool, false)
- peer_to_vmware_engine_network = optional(bool, false)
+ peer_network = string
+ description = optional(string, "Managed by Terraform.")
+ peer_to_vmware_engine_network = optional(bool, false)
+ routes_config = optional(object({
+ export = optional(bool, false)
+ import = optional(bool, false)
+ public_export = optional(bool, false)
+ public_import = optional(bool, false)
+ }), {})
}))
default = {}
}
@@ -58,8 +60,9 @@ variable "vmw_network_peerings" {
variable "vmw_private_cloud_configs" {
description = "The VMware private cloud configurations. The key is the unique private cloud name suffix."
type = map(object({
- cidr = string
- zone = string
+ cidr = string
+ zone = string
+ description = optional(string, "Managed by Terraform.")
# The key is the unique additional cluster name suffix
additional_cluster_configs = optional(map(object({
custom_core_count = optional(number)
@@ -72,7 +75,6 @@ variable "vmw_private_cloud_configs" {
node_count = optional(number, 3)
node_type_id = optional(string, "standard-72")
}), {})
- description = optional(string, "Managed by Terraform.")
}))
default = {
pcc_one = {
diff --git a/modules/gcve-private-cloud/versions.tf b/modules/gcve-private-cloud/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/gcve-private-cloud/versions.tf
+++ b/modules/gcve-private-cloud/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/gke-cluster-autopilot/versions.tf b/modules/gke-cluster-autopilot/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/gke-cluster-autopilot/versions.tf
+++ b/modules/gke-cluster-autopilot/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/gke-cluster-standard/versions.tf b/modules/gke-cluster-standard/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/gke-cluster-standard/versions.tf
+++ b/modules/gke-cluster-standard/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/gke-hub/versions.tf b/modules/gke-hub/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/gke-hub/versions.tf
+++ b/modules/gke-hub/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/gke-nodepool/versions.tf b/modules/gke-nodepool/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/gke-nodepool/versions.tf
+++ b/modules/gke-nodepool/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/iam-service-account/versions.tf b/modules/iam-service-account/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/iam-service-account/versions.tf
+++ b/modules/iam-service-account/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/kms/versions.tf b/modules/kms/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/kms/versions.tf
+++ b/modules/kms/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/logging-bucket/versions.tf b/modules/logging-bucket/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/logging-bucket/versions.tf
+++ b/modules/logging-bucket/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/looker-core/versions.tf b/modules/looker-core/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/looker-core/versions.tf
+++ b/modules/looker-core/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/ncc-spoke-ra/versions.tf b/modules/ncc-spoke-ra/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/ncc-spoke-ra/versions.tf
+++ b/modules/ncc-spoke-ra/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/net-address/versions.tf b/modules/net-address/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/net-address/versions.tf
+++ b/modules/net-address/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/net-cloudnat/versions.tf b/modules/net-cloudnat/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/net-cloudnat/versions.tf
+++ b/modules/net-cloudnat/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/net-firewall-policy/versions.tf b/modules/net-firewall-policy/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/net-firewall-policy/versions.tf
+++ b/modules/net-firewall-policy/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/net-ipsec-over-interconnect/versions.tf b/modules/net-ipsec-over-interconnect/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/net-ipsec-over-interconnect/versions.tf
+++ b/modules/net-ipsec-over-interconnect/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/net-lb-app-ext-regional/versions.tf b/modules/net-lb-app-ext-regional/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/net-lb-app-ext-regional/versions.tf
+++ b/modules/net-lb-app-ext-regional/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/net-lb-app-ext/versions.tf b/modules/net-lb-app-ext/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/net-lb-app-ext/versions.tf
+++ b/modules/net-lb-app-ext/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/net-lb-app-int-cross-region/versions.tf b/modules/net-lb-app-int-cross-region/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/net-lb-app-int-cross-region/versions.tf
+++ b/modules/net-lb-app-int-cross-region/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/net-lb-app-int/versions.tf b/modules/net-lb-app-int/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/net-lb-app-int/versions.tf
+++ b/modules/net-lb-app-int/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/net-lb-ext/versions.tf b/modules/net-lb-ext/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/net-lb-ext/versions.tf
+++ b/modules/net-lb-ext/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/net-lb-int/versions.tf b/modules/net-lb-int/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/net-lb-int/versions.tf
+++ b/modules/net-lb-int/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/net-lb-proxy-int/versions.tf b/modules/net-lb-proxy-int/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/net-lb-proxy-int/versions.tf
+++ b/modules/net-lb-proxy-int/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/net-swp/versions.tf b/modules/net-swp/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/net-swp/versions.tf
+++ b/modules/net-swp/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/net-vlan-attachment/versions.tf b/modules/net-vlan-attachment/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/net-vlan-attachment/versions.tf
+++ b/modules/net-vlan-attachment/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/net-vpc-firewall/versions.tf b/modules/net-vpc-firewall/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/net-vpc-firewall/versions.tf
+++ b/modules/net-vpc-firewall/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/net-vpc-peering/versions.tf b/modules/net-vpc-peering/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/net-vpc-peering/versions.tf
+++ b/modules/net-vpc-peering/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/net-vpc/versions.tf b/modules/net-vpc/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/net-vpc/versions.tf
+++ b/modules/net-vpc/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/net-vpn-dynamic/versions.tf b/modules/net-vpn-dynamic/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/net-vpn-dynamic/versions.tf
+++ b/modules/net-vpn-dynamic/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/net-vpn-ha/versions.tf b/modules/net-vpn-ha/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/net-vpn-ha/versions.tf
+++ b/modules/net-vpn-ha/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/net-vpn-static/versions.tf b/modules/net-vpn-static/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/net-vpn-static/versions.tf
+++ b/modules/net-vpn-static/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/organization/organization-policies.tf b/modules/organization/organization-policies.tf
index 55e3fc995..53ae794a7 100644
--- a/modules/organization/organization-policies.tf
+++ b/modules/organization/organization-policies.tf
@@ -17,9 +17,10 @@
# tfdoc:file:description Organization-level organization policies.
locals {
+ _factory_data_path = pathexpand(coalesce(var.factories_config.org_policies, "-"))
_factory_data_raw = merge([
- for f in try(fileset(var.factories_config.org_policies, "*.yaml"), []) :
- yamldecode(file("${var.factories_config.org_policies}/${f}"))
+ for f in try(fileset(local._factory_data_path, "*.yaml"), []) :
+ yamldecode(file("${local._factory_data_path}/${f}"))
]...)
# simulate applying defaults to data coming from yaml files
_factory_data = {
diff --git a/modules/organization/versions.tf b/modules/organization/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/organization/versions.tf
+++ b/modules/organization/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/project/organization-policies.tf b/modules/project/organization-policies.tf
index ef6dfb887..5c269af04 100644
--- a/modules/project/organization-policies.tf
+++ b/modules/project/organization-policies.tf
@@ -17,9 +17,10 @@
# tfdoc:file:description Project-level organization policies.
locals {
+ _factory_data_path = pathexpand(coalesce(var.factories_config.org_policies, "-"))
_factory_data_raw = merge([
- for f in try(fileset(var.factories_config.org_policies, "*.yaml"), []) :
- yamldecode(file("${var.factories_config.org_policies}/${f}"))
+ for f in try(fileset(local._factory_data_path, "*.yaml"), []) :
+ yamldecode(file("${local._factory_data_path}/${f}"))
]...)
# simulate applying defaults to data coming from yaml files
_factory_data = {
diff --git a/modules/project/versions.tf b/modules/project/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/project/versions.tf
+++ b/modules/project/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/projects-data-source/versions.tf b/modules/projects-data-source/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/projects-data-source/versions.tf
+++ b/modules/projects-data-source/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/pubsub/versions.tf b/modules/pubsub/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/pubsub/versions.tf
+++ b/modules/pubsub/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/secret-manager/versions.tf b/modules/secret-manager/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/secret-manager/versions.tf
+++ b/modules/secret-manager/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/secure-source-manager-instance/versions.tf b/modules/secure-source-manager-instance/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/secure-source-manager-instance/versions.tf
+++ b/modules/secure-source-manager-instance/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/service-directory/versions.tf b/modules/service-directory/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/service-directory/versions.tf
+++ b/modules/service-directory/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/source-repository/versions.tf b/modules/source-repository/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/source-repository/versions.tf
+++ b/modules/source-repository/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/spanner-instance/versions.tf b/modules/spanner-instance/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/spanner-instance/versions.tf
+++ b/modules/spanner-instance/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/vpc-sc/versions.tf b/modules/vpc-sc/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/vpc-sc/versions.tf
+++ b/modules/vpc-sc/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/modules/workstation-cluster/versions.tf b/modules/workstation-cluster/versions.tf
index 08cda2815..d498075b0 100644
--- a/modules/workstation-cluster/versions.tf
+++ b/modules/workstation-cluster/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/tests/examples_e2e/setup_module/versions.tf b/tests/examples_e2e/setup_module/versions.tf
index 08cda2815..d498075b0 100644
--- a/tests/examples_e2e/setup_module/versions.tf
+++ b/tests/examples_e2e/setup_module/versions.tf
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+<<<<<<< HEAD
# Fabric release: v35.1.0
+=======
+# Fabric release: v36.0.0
+>>>>>>> fast-dev
terraform {
required_version = ">= 1.7.4"
diff --git a/tests/fast/stages/s0_bootstrap/checklist.tfvars b/tests/fast/stages/s0_bootstrap/checklist.tfvars
deleted file mode 100644
index 5b97f548a..000000000
--- a/tests/fast/stages/s0_bootstrap/checklist.tfvars
+++ /dev/null
@@ -1,17 +0,0 @@
-organization = {
- domain = "fast.example.com"
- id = 123456789012
- customer_id = "C00000000"
-}
-billing_account = {
- id = "000000-111111-222222"
-}
-essential_contacts = "gcp-organization-admins@fast.example.com"
-factories_config = {
- checklist_data = "checklist-data.json"
- checklist_org_iam = "checklist-org-iam.json"
-}
-org_policies_config = {
- import_defaults = false
-}
-prefix = "fast"
diff --git a/tests/fast/stages/s0_bootstrap/checklist.yaml b/tests/fast/stages/s0_bootstrap/checklist.yaml
deleted file mode 100644
index 58f1751f1..000000000
--- a/tests/fast/stages/s0_bootstrap/checklist.yaml
+++ /dev/null
@@ -1,1967 +0,0 @@
-# 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.
-
-values:
- google_storage_bucket_object.checklist_data[0]:
- bucket: fast-prod-iac-core-checklist-0
- cache_control: null
- content_disposition: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
- name: checklist/data.tfvars.json
- retention: []
- source: checklist-data.json
- temporary_hold: null
- timeouts: null
- google_storage_bucket_object.checklist_org_iam[0]:
- bucket: fast-prod-iac-core-checklist-0
- cache_control: null
- content_disposition: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
- name: checklist/org-iam.tfvars.json
- retention: []
- source: checklist-org-iam.json
- temporary_hold: null
- timeouts: null
- google_storage_bucket_object.providers["0-bootstrap"]:
- bucket: fast-prod-iac-core-outputs-0
- cache_control: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
- name: providers/0-bootstrap-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
- google_storage_bucket_object.providers["0-bootstrap-r"]:
- bucket: fast-prod-iac-core-outputs-0
- cache_control: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
- name: providers/0-bootstrap-r-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
- google_storage_bucket_object.providers["1-resman"]:
- bucket: fast-prod-iac-core-outputs-0
- cache_control: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
- name: providers/1-resman-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
- google_storage_bucket_object.providers["1-resman-r"]:
- bucket: fast-prod-iac-core-outputs-0
- cache_control: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
- name: providers/1-resman-r-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
- google_storage_bucket_object.providers["1-tenant-factory"]:
- bucket: fast-prod-iac-core-outputs-0
- cache_control: null
- content_disposition: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
- name: providers/1-tenant-factory-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
- google_storage_bucket_object.providers["1-tenant-factory-r"]:
- bucket: fast-prod-iac-core-outputs-0
- cache_control: null
- content_disposition: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
- name: providers/1-tenant-factory-r-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
- google_storage_bucket_object.providers["1-vpcsc"]:
- bucket: fast-prod-iac-core-outputs-0
- cache_control: null
- content_disposition: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
- name: providers/1-vpcsc-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
- google_storage_bucket_object.providers["1-vpcsc-r"]:
- bucket: fast-prod-iac-core-outputs-0
- cache_control: null
- content_disposition: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
- name: providers/1-vpcsc-r-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
- google_storage_bucket_object.tfvars:
- bucket: fast-prod-iac-core-outputs-0
- cache_control: null
- content_disposition: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
- name: tfvars/0-bootstrap.auto.tfvars.json
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
- google_storage_bucket_object.tfvars_globals:
- bucket: fast-prod-iac-core-outputs-0
- cache_control: null
- content: '{"billing_account":{"id":"000000-111111-222222","is_org_level":true,"no_iam":false},"environments":{"dev":{"is_default":false,"name":"Development"},"prod":{"is_default":true,"name":"Production"}},"groups":{"gcp-billing-admins":"group:gcp-billing-admins@fast.example.com","gcp-devops":"group:gcp-devops@fast.example.com","gcp-network-admins":"group:gcp-vpc-network-admins@fast.example.com","gcp-organization-admins":"group:gcp-organization-admins@fast.example.com","gcp-security-admins":"group:gcp-security-admins@fast.example.com","gcp-support":"group:gcp-devops@fast.example.com"},"locations":{"bq":"EU","gcs":"EU","logging":"europe-west1","pubsub":[]},"organization":{"customer_id":"C00000000","domain":"fast.example.com","id":123456789012},"prefix":"fast"}'
- content_disposition: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
- name: tfvars/0-globals.auto.tfvars.json
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
- module.automation-project.data.google_bigquery_default_service_account.bq_sa[0]:
- project: fast-prod-iac-core-0
- module.automation-project.data.google_storage_project_service_account.gcs_sa[0]:
- project: fast-prod-iac-core-0
- user_project: null
- module.automation-project.google_essential_contacts_contact.contact["gcp-organization-admins@fast.example.com"]:
- email: gcp-organization-admins@fast.example.com
- language_tag: en
- notification_category_subscriptions:
- - ALL
- parent: projects/fast-prod-iac-core-0
- timeouts: null
- module.automation-project.google_org_policy_policy.default["compute.skipDefaultNetworkCreation"]:
- dry_run_spec: []
- name: projects/fast-prod-iac-core-0/policies/compute.skipDefaultNetworkCreation
- parent: projects/fast-prod-iac-core-0
- spec:
- - inherit_from_parent: null
- reset: null
- rules:
- - allow_all: null
- condition: []
- deny_all: null
- enforce: 'TRUE'
- values: []
- timeouts: null
- module.automation-project.google_org_policy_policy.default["iam.automaticIamGrantsForDefaultServiceAccounts"]:
- dry_run_spec: []
- name: projects/fast-prod-iac-core-0/policies/iam.automaticIamGrantsForDefaultServiceAccounts
- parent: projects/fast-prod-iac-core-0
- spec:
- - inherit_from_parent: null
- reset: null
- rules:
- - allow_all: null
- condition: []
- deny_all: null
- enforce: 'TRUE'
- values: []
- timeouts: null
- module.automation-project.google_org_policy_policy.default["iam.disableServiceAccountKeyCreation"]:
- dry_run_spec: []
- name: projects/fast-prod-iac-core-0/policies/iam.disableServiceAccountKeyCreation
- parent: projects/fast-prod-iac-core-0
- spec:
- - inherit_from_parent: null
- reset: null
- rules:
- - allow_all: null
- condition: []
- deny_all: null
- enforce: 'TRUE'
- values: []
- timeouts: null
- module.automation-project.google_project.project[0]:
- auto_create_network: false
- billing_account: 000000-111111-222222
- deletion_policy: DELETE
- folder_id: null
- labels: null
- name: fast-prod-iac-core-0
- org_id: '123456789012'
- project_id: fast-prod-iac-core-0
- timeouts: null
- module.automation-project.google_project_iam_audit_config.default["iam.googleapis.com"]:
- audit_log_config:
- - exempted_members: []
- log_type: ADMIN_READ
- project: fast-prod-iac-core-0
- service: iam.googleapis.com
- module.automation-project.google_project_iam_binding.authoritative["organizations/123456789012/roles/storageViewer"]:
- condition: []
- members:
- - serviceAccount:fast-prod-bootstrap-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- - serviceAccount:fast-prod-resman-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- project: fast-prod-iac-core-0
- role: organizations/123456789012/roles/storageViewer
- module.automation-project.google_project_iam_binding.authoritative["roles/browser"]:
- condition: []
- members:
- - serviceAccount:fast-prod-resman-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- project: fast-prod-iac-core-0
- role: roles/browser
- module.automation-project.google_project_iam_binding.authoritative["roles/cloudbuild.builds.editor"]:
- condition: []
- members:
- - serviceAccount:fast-prod-resman-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- project: fast-prod-iac-core-0
- role: roles/cloudbuild.builds.editor
- module.automation-project.google_project_iam_binding.authoritative["roles/cloudbuild.builds.viewer"]:
- condition: []
- members:
- - serviceAccount:fast-prod-resman-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- project: fast-prod-iac-core-0
- role: roles/cloudbuild.builds.viewer
- module.automation-project.google_project_iam_binding.authoritative["roles/iam.serviceAccountAdmin"]:
- condition: []
- members:
- - group:gcp-devops@fast.example.com
- - serviceAccount:fast-prod-resman-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- project: fast-prod-iac-core-0
- role: roles/iam.serviceAccountAdmin
- module.automation-project.google_project_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
- condition: []
- members:
- - group:gcp-devops@fast.example.com
- - group:gcp-organization-admins@fast.example.com
- project: fast-prod-iac-core-0
- role: roles/iam.serviceAccountTokenCreator
- module.automation-project.google_project_iam_binding.authoritative["roles/iam.serviceAccountViewer"]:
- condition: []
- members:
- - serviceAccount:fast-prod-resman-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- project: fast-prod-iac-core-0
- role: roles/iam.serviceAccountViewer
- module.automation-project.google_project_iam_binding.authoritative["roles/iam.workloadIdentityPoolAdmin"]:
- condition: []
- members:
- - group:gcp-organization-admins@fast.example.com
- - serviceAccount:fast-prod-resman-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- project: fast-prod-iac-core-0
- role: roles/iam.workloadIdentityPoolAdmin
- module.automation-project.google_project_iam_binding.authoritative["roles/iam.workloadIdentityPoolViewer"]:
- condition: []
- members:
- - serviceAccount:fast-prod-resman-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- project: fast-prod-iac-core-0
- role: roles/iam.workloadIdentityPoolViewer
- module.automation-project.google_project_iam_binding.authoritative["roles/owner"]:
- condition: []
- members:
- - serviceAccount:fast-prod-bootstrap-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- project: fast-prod-iac-core-0
- role: roles/owner
- module.automation-project.google_project_iam_binding.authoritative["roles/source.admin"]:
- condition: []
- members:
- - serviceAccount:fast-prod-resman-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- project: fast-prod-iac-core-0
- role: roles/source.admin
- module.automation-project.google_project_iam_binding.authoritative["roles/source.reader"]:
- condition: []
- members:
- - serviceAccount:fast-prod-resman-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- project: fast-prod-iac-core-0
- role: roles/source.reader
- module.automation-project.google_project_iam_binding.authoritative["roles/storage.admin"]:
- condition: []
- members:
- - serviceAccount:fast-prod-resman-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- project: fast-prod-iac-core-0
- role: roles/storage.admin
- module.automation-project.google_project_iam_binding.authoritative["roles/viewer"]:
- condition: []
- members:
- - serviceAccount:fast-prod-bootstrap-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- - serviceAccount:fast-prod-resman-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- project: fast-prod-iac-core-0
- role: roles/viewer
- module.automation-project.google_project_iam_binding.bindings["delegated_grants_resman"]:
- condition:
- - description: Resource manager service account delegated grant.
- expression: api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly(['roles/serviceusage.serviceUsageConsumer'])
- title: resman_delegated_grant
- members:
- - serviceAccount:fast-prod-resman-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- project: fast-prod-iac-core-0
- role: roles/resourcemanager.projectIamAdmin
- module.automation-project.google_project_iam_member.bindings["serviceusage_resman"]:
- condition: []
- member: serviceAccount:fast-prod-resman-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- project: fast-prod-iac-core-0
- role: roles/serviceusage.serviceUsageConsumer
- module.automation-project.google_project_iam_member.bindings["serviceusage_resman_r"]:
- condition: []
- member: serviceAccount:fast-prod-resman-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- project: fast-prod-iac-core-0
- role: roles/serviceusage.serviceUsageViewer
- module.automation-project.google_project_iam_member.service_agents["cloudasset"]:
- condition: []
- project: fast-prod-iac-core-0
- role: roles/cloudasset.serviceAgent
- module.automation-project.google_project_iam_member.service_agents["cloudbuild"]:
- condition: []
- project: fast-prod-iac-core-0
- role: roles/cloudbuild.serviceAgent
- module.automation-project.google_project_iam_member.service_agents["cloudbuild-sa"]:
- condition: []
- project: fast-prod-iac-core-0
- role: roles/cloudbuild.builds.builder
- module.automation-project.google_project_iam_member.service_agents["cloudkms"]:
- condition: []
- project: fast-prod-iac-core-0
- role: roles/cloudkms.serviceAgent
- module.automation-project.google_project_iam_member.service_agents["compute-system"]:
- condition: []
- project: fast-prod-iac-core-0
- role: roles/compute.serviceAgent
- module.automation-project.google_project_iam_member.service_agents["container-engine-robot"]:
- condition: []
- project: fast-prod-iac-core-0
- role: roles/container.serviceAgent
- module.automation-project.google_project_iam_member.service_agents["gkenode"]:
- condition: []
- project: fast-prod-iac-core-0
- role: roles/container.nodeServiceAgent
- module.automation-project.google_project_iam_member.service_agents["pubsub"]:
- condition: []
- project: fast-prod-iac-core-0
- role: roles/pubsub.serviceAgent
- module.automation-project.google_project_iam_member.service_agents["service-networking"]:
- condition: []
- project: fast-prod-iac-core-0
- role: roles/servicenetworking.serviceAgent
- module.automation-project.google_project_service.project_services["accesscontextmanager.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-iac-core-0
- service: accesscontextmanager.googleapis.com
- timeouts: null
- module.automation-project.google_project_service.project_services["bigquery.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-iac-core-0
- service: bigquery.googleapis.com
- timeouts: null
- module.automation-project.google_project_service.project_services["bigqueryreservation.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-iac-core-0
- service: bigqueryreservation.googleapis.com
- timeouts: null
- module.automation-project.google_project_service.project_services["bigquerystorage.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-iac-core-0
- service: bigquerystorage.googleapis.com
- timeouts: null
- module.automation-project.google_project_service.project_services["billingbudgets.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-iac-core-0
- service: billingbudgets.googleapis.com
- timeouts: null
- module.automation-project.google_project_service.project_services["cloudasset.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-iac-core-0
- service: cloudasset.googleapis.com
- timeouts: null
- module.automation-project.google_project_service.project_services["cloudbilling.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-iac-core-0
- service: cloudbilling.googleapis.com
- timeouts: null
- module.automation-project.google_project_service.project_services["cloudbuild.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-iac-core-0
- service: cloudbuild.googleapis.com
- timeouts: null
- module.automation-project.google_project_service.project_services["cloudkms.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-iac-core-0
- service: cloudkms.googleapis.com
- timeouts: null
- module.automation-project.google_project_service.project_services["cloudquotas.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-iac-core-0
- service: cloudquotas.googleapis.com
- timeouts: null
- module.automation-project.google_project_service.project_services["cloudresourcemanager.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-iac-core-0
- service: cloudresourcemanager.googleapis.com
- timeouts: null
- module.automation-project.google_project_service.project_services["compute.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-iac-core-0
- service: compute.googleapis.com
- timeouts: null
- module.automation-project.google_project_service.project_services["container.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-iac-core-0
- service: container.googleapis.com
- timeouts: null
- module.automation-project.google_project_service.project_services["essentialcontacts.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-iac-core-0
- service: essentialcontacts.googleapis.com
- timeouts: null
- module.automation-project.google_project_service.project_services["iam.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-iac-core-0
- service: iam.googleapis.com
- timeouts: null
- module.automation-project.google_project_service.project_services["iamcredentials.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-iac-core-0
- service: iamcredentials.googleapis.com
- timeouts: null
- module.automation-project.google_project_service.project_services["networksecurity.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-iac-core-0
- service: networksecurity.googleapis.com
- timeouts: null
- module.automation-project.google_project_service.project_services["orgpolicy.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-iac-core-0
- service: orgpolicy.googleapis.com
- timeouts: null
- module.automation-project.google_project_service.project_services["pubsub.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-iac-core-0
- service: pubsub.googleapis.com
- timeouts: null
- module.automation-project.google_project_service.project_services["servicenetworking.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-iac-core-0
- service: servicenetworking.googleapis.com
- timeouts: null
- module.automation-project.google_project_service.project_services["serviceusage.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-iac-core-0
- service: serviceusage.googleapis.com
- timeouts: null
- module.automation-project.google_project_service.project_services["stackdriver.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-iac-core-0
- service: stackdriver.googleapis.com
- timeouts: null
- module.automation-project.google_project_service.project_services["storage-component.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-iac-core-0
- service: storage-component.googleapis.com
- timeouts: null
- module.automation-project.google_project_service.project_services["storage.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-iac-core-0
- service: storage.googleapis.com
- timeouts: null
- module.automation-project.google_project_service.project_services["sts.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-iac-core-0
- service: sts.googleapis.com
- timeouts: null
- module.automation-project.google_project_service_identity.default["cloudasset.googleapis.com"]:
- project: fast-prod-iac-core-0
- service: cloudasset.googleapis.com
- timeouts: null
- module.automation-project.google_project_service_identity.default["cloudkms.googleapis.com"]:
- project: fast-prod-iac-core-0
- service: cloudkms.googleapis.com
- timeouts: null
- module.automation-project.google_project_service_identity.default["container.googleapis.com"]:
- project: fast-prod-iac-core-0
- service: container.googleapis.com
- timeouts: null
- module.automation-project.google_project_service_identity.default["networksecurity.googleapis.com"]:
- project: fast-prod-iac-core-0
- service: networksecurity.googleapis.com
- timeouts: null
- module.automation-project.google_project_service_identity.default["pubsub.googleapis.com"]:
- project: fast-prod-iac-core-0
- service: pubsub.googleapis.com
- timeouts: null
- module.automation-project.google_project_service_identity.default["servicenetworking.googleapis.com"]:
- project: fast-prod-iac-core-0
- service: servicenetworking.googleapis.com
- timeouts: null
- module.automation-tf-bootstrap-gcs.google_storage_bucket.bucket:
- autoclass: []
- cors: []
- custom_placement_config: []
- default_event_based_hold: null
- enable_object_retention: null
- encryption: []
- force_destroy: false
- labels: null
- lifecycle_rule: []
- location: EU
- logging: []
- name: fast-prod-iac-core-bootstrap-0
- project: fast-prod-iac-core-0
- requester_pays: null
- retention_policy: []
- storage_class: STANDARD
- timeouts: null
- uniform_bucket_level_access: true
- versioning:
- - enabled: true
- ? module.automation-tf-bootstrap-r-sa.google_organization_iam_member.organization-roles["123456789012-organizations/123456789012/roles/organizationAdminViewer"]
- : condition: []
- org_id: '123456789012'
- role: organizations/123456789012/roles/organizationAdminViewer
- ? module.automation-tf-bootstrap-r-sa.google_organization_iam_member.organization-roles["123456789012-organizations/123456789012/roles/tagViewer"]
- : condition: []
- org_id: '123456789012'
- role: organizations/123456789012/roles/tagViewer
- module.automation-tf-bootstrap-r-sa.google_service_account.service_account[0]:
- account_id: fast-prod-bootstrap-0r
- create_ignore_already_exists: null
- description: null
- disabled: false
- display_name: Terraform organization bootstrap service account (read-only).
- project: fast-prod-iac-core-0
- timeouts: null
- ? module.automation-tf-bootstrap-r-sa.google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]
- : condition: []
- members: null
- role: roles/iam.serviceAccountTokenCreator
- ? module.automation-tf-bootstrap-r-sa.google_storage_bucket_iam_member.bucket-roles["fast-prod-iac-core-outputs-0-organizations/123456789012/roles/storageViewer"]
- : bucket: fast-prod-iac-core-outputs-0
- condition: []
- role: organizations/123456789012/roles/storageViewer
- module.automation-tf-bootstrap-sa.google_service_account.service_account[0]:
- account_id: fast-prod-bootstrap-0
- create_ignore_already_exists: null
- description: null
- disabled: false
- display_name: Terraform organization bootstrap service account.
- project: fast-prod-iac-core-0
- timeouts: null
- module.automation-tf-bootstrap-sa.google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
- condition: []
- members: null
- role: roles/iam.serviceAccountTokenCreator
- ? module.automation-tf-bootstrap-sa.google_storage_bucket_iam_member.bucket-roles["fast-prod-iac-core-outputs-0-roles/storage.admin"]
- : bucket: fast-prod-iac-core-outputs-0
- condition: []
- role: roles/storage.admin
- module.automation-tf-checklist-gcs[0].google_storage_bucket.bucket:
- autoclass: []
- cors: []
- custom_placement_config: []
- default_event_based_hold: null
- enable_object_retention: null
- encryption: []
- force_destroy: false
- labels: null
- lifecycle_rule: []
- location: EU
- logging: []
- name: fast-prod-iac-core-checklist-0
- project: fast-prod-iac-core-0
- requester_pays: null
- retention_policy: []
- storage_class: STANDARD
- timeouts: null
- uniform_bucket_level_access: true
- versioning:
- - enabled: true
- module.automation-tf-output-gcs.google_storage_bucket.bucket:
- autoclass: []
- cors: []
- custom_placement_config: []
- default_event_based_hold: null
- enable_object_retention: null
- encryption: []
- force_destroy: false
- labels: null
- lifecycle_rule: []
- location: EU
- logging: []
- name: fast-prod-iac-core-outputs-0
- project: fast-prod-iac-core-0
- requester_pays: null
- retention_policy: []
- storage_class: STANDARD
- timeouts: null
- uniform_bucket_level_access: true
- versioning:
- - enabled: true
- module.automation-tf-resman-gcs.google_storage_bucket.bucket:
- autoclass: []
- cors: []
- custom_placement_config: []
- default_event_based_hold: null
- enable_object_retention: null
- encryption: []
- force_destroy: false
- labels: null
- lifecycle_rule: []
- location: EU
- logging: []
- name: fast-prod-iac-core-resman-0
- project: fast-prod-iac-core-0
- requester_pays: null
- retention_policy: []
- storage_class: STANDARD
- timeouts: null
- uniform_bucket_level_access: true
- versioning:
- - enabled: true
- module.automation-tf-resman-gcs.google_storage_bucket_iam_binding.authoritative["roles/storage.objectAdmin"]:
- bucket: fast-prod-iac-core-resman-0
- condition: []
- members:
- - serviceAccount:fast-prod-resman-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- role: roles/storage.objectAdmin
- module.automation-tf-resman-gcs.google_storage_bucket_iam_binding.authoritative["roles/storage.objectViewer"]:
- bucket: fast-prod-iac-core-resman-0
- condition: []
- members:
- - serviceAccount:fast-prod-resman-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- role: roles/storage.objectViewer
- ? module.automation-tf-resman-r-sa.google_organization_iam_member.organization-roles["123456789012-organizations/123456789012/roles/organizationAdminViewer"]
- : condition: []
- org_id: '123456789012'
- role: organizations/123456789012/roles/organizationAdminViewer
- ? module.automation-tf-resman-r-sa.google_organization_iam_member.organization-roles["123456789012-organizations/123456789012/roles/tagViewer"]
- : condition: []
- org_id: '123456789012'
- role: organizations/123456789012/roles/tagViewer
- module.automation-tf-resman-r-sa.google_service_account.service_account[0]:
- account_id: fast-prod-resman-0r
- create_ignore_already_exists: null
- description: null
- disabled: false
- display_name: Terraform stage 1 resman service account (read-only).
- project: fast-prod-iac-core-0
- timeouts: null
- ? module.automation-tf-resman-r-sa.google_storage_bucket_iam_member.bucket-roles["fast-prod-iac-core-outputs-0-organizations/123456789012/roles/storageViewer"]
- : bucket: fast-prod-iac-core-outputs-0
- condition: []
- role: organizations/123456789012/roles/storageViewer
- module.automation-tf-resman-sa.google_service_account.service_account[0]:
- account_id: fast-prod-resman-0
- create_ignore_already_exists: null
- description: null
- disabled: false
- display_name: Terraform stage 1 resman service account.
- project: fast-prod-iac-core-0
- timeouts: null
- ? module.automation-tf-resman-sa.google_storage_bucket_iam_member.bucket-roles["fast-prod-iac-core-outputs-0-roles/storage.admin"]
- : bucket: fast-prod-iac-core-outputs-0
- condition: []
- role: roles/storage.admin
- module.automation-tf-vpcsc-gcs.google_storage_bucket.bucket:
- autoclass: []
- cors: []
- custom_placement_config: []
- default_event_based_hold: null
- enable_object_retention: null
- encryption: []
- force_destroy: false
- labels: null
- lifecycle_rule: []
- location: EU
- logging: []
- name: fast-prod-iac-core-vpcsc-0
- project: fast-prod-iac-core-0
- requester_pays: null
- retention_policy: []
- storage_class: STANDARD
- timeouts: null
- uniform_bucket_level_access: true
- versioning:
- - enabled: true
- module.automation-tf-vpcsc-gcs.google_storage_bucket_iam_binding.authoritative["roles/storage.objectAdmin"]:
- bucket: fast-prod-iac-core-vpcsc-0
- condition: []
- members:
- - serviceAccount:fast-prod-vpcsc-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- role: roles/storage.objectAdmin
- module.automation-tf-vpcsc-gcs.google_storage_bucket_iam_binding.authoritative["roles/storage.objectViewer"]:
- bucket: fast-prod-iac-core-vpcsc-0
- condition: []
- members:
- - serviceAccount:fast-prod-vpcsc-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- role: roles/storage.objectViewer
- module.automation-tf-vpcsc-r-sa.google_service_account.service_account[0]:
- account_id: fast-prod-vpcsc-0r
- create_ignore_already_exists: null
- description: null
- disabled: false
- display_name: Terraform stage 1 vpcsc service account (read-only).
- project: fast-prod-iac-core-0
- timeouts: null
- ? module.automation-tf-vpcsc-r-sa.google_storage_bucket_iam_member.bucket-roles["fast-prod-iac-core-outputs-0-organizations/123456789012/roles/storageViewer"]
- : bucket: fast-prod-iac-core-outputs-0
- condition: []
- role: organizations/123456789012/roles/storageViewer
- module.automation-tf-vpcsc-sa.google_service_account.service_account[0]:
- account_id: fast-prod-vpcsc-0
- create_ignore_already_exists: null
- description: null
- disabled: false
- display_name: Terraform stage 1 vpcsc service account.
- project: fast-prod-iac-core-0
- timeouts: null
- module.automation-tf-vpcsc-sa.google_service_account_iam_member.bindings["security_admins"]:
- condition: []
- member: group:gcp-security-admins@fast.example.com
- role: roles/iam.serviceAccountTokenCreator
- ? module.automation-tf-vpcsc-sa.google_storage_bucket_iam_member.bucket-roles["fast-prod-iac-core-outputs-0-roles/storage.admin"]
- : bucket: fast-prod-iac-core-outputs-0
- condition: []
- role: roles/storage.admin
- module.billing-export-dataset[0].google_bigquery_dataset.default:
- dataset_id: billing_export
- default_encryption_configuration: []
- default_partition_expiration_ms: null
- default_table_expiration_ms: null
- delete_contents_on_destroy: false
- description: Terraform managed.
- external_dataset_reference: []
- friendly_name: Billing export.
- labels: null
- location: EU
- max_time_travel_hours: '168'
- project: fast-prod-billing-exp-0
- resource_tags: null
- timeouts: null
- module.billing-export-project[0].data.google_bigquery_default_service_account.bq_sa[0]:
- project: fast-prod-billing-exp-0
- module.billing-export-project[0].data.google_storage_project_service_account.gcs_sa[0]:
- project: fast-prod-billing-exp-0
- user_project: null
- module.billing-export-project[0].google_essential_contacts_contact.contact["gcp-organization-admins@fast.example.com"]:
- email: gcp-organization-admins@fast.example.com
- language_tag: en
- notification_category_subscriptions:
- - ALL
- parent: projects/fast-prod-billing-exp-0
- timeouts: null
- module.billing-export-project[0].google_project.project[0]:
- auto_create_network: false
- billing_account: 000000-111111-222222
- deletion_policy: DELETE
- folder_id: null
- labels: null
- name: fast-prod-billing-exp-0
- org_id: '123456789012'
- project_id: fast-prod-billing-exp-0
- timeouts: null
- module.billing-export-project[0].google_project_iam_binding.authoritative["roles/owner"]:
- condition: []
- members:
- - serviceAccount:fast-prod-bootstrap-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- project: fast-prod-billing-exp-0
- role: roles/owner
- module.billing-export-project[0].google_project_iam_binding.authoritative["roles/viewer"]:
- condition: []
- members:
- - serviceAccount:fast-prod-bootstrap-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- project: fast-prod-billing-exp-0
- role: roles/viewer
- module.billing-export-project[0].google_project_iam_member.service_agents["bigquerydatatransfer"]:
- condition: []
- project: fast-prod-billing-exp-0
- role: roles/bigquerydatatransfer.serviceAgent
- module.billing-export-project[0].google_project_service.project_services["bigquery.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-billing-exp-0
- service: bigquery.googleapis.com
- timeouts: null
- module.billing-export-project[0].google_project_service.project_services["bigquerydatatransfer.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-billing-exp-0
- service: bigquerydatatransfer.googleapis.com
- timeouts: null
- module.billing-export-project[0].google_project_service.project_services["storage.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-billing-exp-0
- service: storage.googleapis.com
- timeouts: null
- module.billing-export-project[0].google_project_service_identity.default["bigquerydatatransfer.googleapis.com"]:
- project: fast-prod-billing-exp-0
- service: bigquerydatatransfer.googleapis.com
- timeouts: null
- module.log-export-logbucket["audit-logs"].google_logging_project_bucket_config.bucket[0]:
- bucket_id: audit-logs
- cmek_settings: []
- enable_analytics: true
- index_configs: []
- location: europe-west1
- locked: null
- project: fast-prod-audit-logs-0
- retention_days: 30
- module.log-export-logbucket["iam"].google_logging_project_bucket_config.bucket[0]:
- bucket_id: iam
- cmek_settings: []
- enable_analytics: true
- index_configs: []
- location: europe-west1
- locked: null
- project: fast-prod-audit-logs-0
- retention_days: 30
- module.log-export-logbucket["vpc-sc"].google_logging_project_bucket_config.bucket[0]:
- bucket_id: vpc-sc
- cmek_settings: []
- enable_analytics: true
- index_configs: []
- location: europe-west1
- locked: null
- project: fast-prod-audit-logs-0
- retention_days: 30
- module.log-export-logbucket["workspace-audit-logs"].google_logging_project_bucket_config.bucket[0]:
- bucket_id: workspace-audit-logs
- cmek_settings: []
- enable_analytics: true
- index_configs: []
- location: europe-west1
- locked: null
- project: fast-prod-audit-logs-0
- retention_days: 30
- module.log-export-project.data.google_bigquery_default_service_account.bq_sa[0]:
- project: fast-prod-audit-logs-0
- module.log-export-project.data.google_storage_project_service_account.gcs_sa[0]:
- project: fast-prod-audit-logs-0
- user_project: null
- module.log-export-project.google_essential_contacts_contact.contact["gcp-organization-admins@fast.example.com"]:
- email: gcp-organization-admins@fast.example.com
- language_tag: en
- notification_category_subscriptions:
- - ALL
- parent: projects/fast-prod-audit-logs-0
- timeouts: null
- module.log-export-project.google_project.project[0]:
- auto_create_network: false
- billing_account: 000000-111111-222222
- deletion_policy: DELETE
- folder_id: null
- labels: null
- name: fast-prod-audit-logs-0
- org_id: '123456789012'
- project_id: fast-prod-audit-logs-0
- timeouts: null
- module.log-export-project.google_project_iam_binding.authoritative["roles/owner"]:
- condition: []
- members:
- - serviceAccount:fast-prod-bootstrap-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- project: fast-prod-audit-logs-0
- role: roles/owner
- module.log-export-project.google_project_iam_binding.authoritative["roles/viewer"]:
- condition: []
- members:
- - serviceAccount:fast-prod-bootstrap-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- project: fast-prod-audit-logs-0
- role: roles/viewer
- module.log-export-project.google_project_service.project_services["bigquery.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-audit-logs-0
- service: bigquery.googleapis.com
- timeouts: null
- module.log-export-project.google_project_service.project_services["stackdriver.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-audit-logs-0
- service: stackdriver.googleapis.com
- timeouts: null
- module.log-export-project.google_project_service.project_services["storage.googleapis.com"]:
- disable_dependent_services: false
- disable_on_destroy: false
- project: fast-prod-audit-logs-0
- service: storage.googleapis.com
- timeouts: null
- module.organization-logging.google_logging_organization_settings.default[0]:
- organization: '123456789012'
- storage_location: global
- timeouts: null
- module.organization.google_logging_organization_sink.sink["audit-logs"]:
- description: audit-logs (Terraform-managed).
- disabled: false
- exclusions: []
- filter: 'log_id("cloudaudit.googleapis.com/activity") OR
-
- log_id("cloudaudit.googleapis.com/system_event") OR
-
- log_id("cloudaudit.googleapis.com/policy") OR
-
- log_id("cloudaudit.googleapis.com/access_transparency")
-
- '
- include_children: true
- intercept_children: false
- name: audit-logs
- org_id: '123456789012'
- module.organization.google_logging_organization_sink.sink["iam"]:
- description: iam (Terraform-managed).
- disabled: false
- exclusions: []
- filter: 'protoPayload.serviceName="iamcredentials.googleapis.com" OR
-
- protoPayload.serviceName="iam.googleapis.com" OR
-
- protoPayload.serviceName="sts.googleapis.com"
-
- '
- include_children: true
- intercept_children: false
- name: iam
- org_id: '123456789012'
- module.organization.google_logging_organization_sink.sink["vpc-sc"]:
- description: vpc-sc (Terraform-managed).
- disabled: false
- exclusions: []
- filter: 'protoPayload.metadata.@type="type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
-
- '
- include_children: true
- intercept_children: false
- name: vpc-sc
- org_id: '123456789012'
- module.organization.google_logging_organization_sink.sink["workspace-audit-logs"]:
- description: workspace-audit-logs (Terraform-managed).
- disabled: false
- exclusions: []
- filter: 'log_id("cloudaudit.googleapis.com/data_access") AND
-
- protoPayload.serviceName="login.googleapis.com"
-
- '
- include_children: true
- intercept_children: false
- name: workspace-audit-logs
- org_id: '123456789012'
- module.organization.google_org_policy_policy.default["compute.disableGuestAttributesAccess"]:
- dry_run_spec: []
- name: organizations/123456789012/policies/compute.disableGuestAttributesAccess
- parent: organizations/123456789012
- spec:
- - inherit_from_parent: null
- reset: null
- rules:
- - allow_all: null
- condition: []
- deny_all: null
- enforce: 'TRUE'
- values: []
- timeouts: null
- module.organization.google_org_policy_policy.default["compute.disableNestedVirtualization"]:
- dry_run_spec: []
- name: organizations/123456789012/policies/compute.disableNestedVirtualization
- parent: organizations/123456789012
- spec:
- - inherit_from_parent: null
- reset: null
- rules:
- - allow_all: null
- condition: []
- deny_all: null
- enforce: 'TRUE'
- values: []
- timeouts: null
- module.organization.google_org_policy_policy.default["compute.disableSerialPortAccess"]:
- dry_run_spec: []
- name: organizations/123456789012/policies/compute.disableSerialPortAccess
- parent: organizations/123456789012
- spec:
- - inherit_from_parent: null
- reset: null
- rules:
- - allow_all: null
- condition: []
- deny_all: null
- enforce: 'TRUE'
- values: []
- timeouts: null
- module.organization.google_org_policy_policy.default["compute.requireOsLogin"]:
- dry_run_spec: []
- name: organizations/123456789012/policies/compute.requireOsLogin
- parent: organizations/123456789012
- spec:
- - inherit_from_parent: null
- reset: null
- rules:
- - allow_all: null
- condition: []
- deny_all: null
- enforce: 'TRUE'
- values: []
- timeouts: null
- module.organization.google_org_policy_policy.default["compute.restrictLoadBalancerCreationForTypes"]:
- dry_run_spec: []
- name: organizations/123456789012/policies/compute.restrictLoadBalancerCreationForTypes
- parent: organizations/123456789012
- spec:
- - inherit_from_parent: null
- reset: null
- rules:
- - allow_all: null
- condition: []
- deny_all: null
- enforce: null
- values:
- - allowed_values:
- - in:INTERNAL
- denied_values: null
- timeouts: null
- module.organization.google_org_policy_policy.default["compute.skipDefaultNetworkCreation"]:
- dry_run_spec: []
- name: organizations/123456789012/policies/compute.skipDefaultNetworkCreation
- parent: organizations/123456789012
- spec:
- - inherit_from_parent: null
- reset: null
- rules:
- - allow_all: null
- condition: []
- deny_all: null
- enforce: 'TRUE'
- values: []
- timeouts: null
- module.organization.google_org_policy_policy.default["compute.trustedImageProjects"]:
- dry_run_spec: []
- name: organizations/123456789012/policies/compute.trustedImageProjects
- parent: organizations/123456789012
- spec:
- - inherit_from_parent: null
- reset: null
- rules:
- - allow_all: null
- condition: []
- deny_all: null
- enforce: null
- values:
- - allowed_values:
- - is:projects/centos-cloud
- - is:projects/cos-cloud
- - is:projects/debian-cloud
- - is:projects/fedora-cloud
- - is:projects/fedora-coreos-cloud
- - is:projects/opensuse-cloud
- - is:projects/rhel-cloud
- - is:projects/rhel-sap-cloud
- - is:projects/rocky-linux-cloud
- - is:projects/suse-cloud
- - is:projects/suse-sap-cloud
- - is:projects/ubuntu-os-cloud
- - is:projects/ubuntu-os-pro-cloud
- - is:projects/windows-cloud
- - is:projects/windows-sql-cloud
- - is:projects/confidential-vm-images
- - is:projects/backupdr-images
- - is:projects/deeplearning-platform-release
- - is:projects/serverless-vpc-access-images
- denied_values: null
- timeouts: null
- module.organization.google_org_policy_policy.default["compute.vmExternalIpAccess"]:
- dry_run_spec: []
- name: organizations/123456789012/policies/compute.vmExternalIpAccess
- parent: organizations/123456789012
- spec:
- - inherit_from_parent: null
- reset: null
- rules:
- - allow_all: null
- condition: []
- deny_all: 'TRUE'
- enforce: null
- values: []
- timeouts: null
- module.organization.google_org_policy_policy.default["iam.allowedPolicyMemberDomains"]:
- dry_run_spec: []
- name: organizations/123456789012/policies/iam.allowedPolicyMemberDomains
- parent: organizations/123456789012
- spec:
- - inherit_from_parent: null
- reset: null
- rules:
- - allow_all: null
- condition:
- - description: null
- expression: '!resource.matchTag(''123456789012/org-policies'', ''allowed-policy-member-domains-all'')'
- location: null
- title: null
- deny_all: null
- enforce: null
- values:
- - allowed_values:
- - C00000000
- denied_values: null
- - allow_all: 'TRUE'
- condition:
- - description: null
- expression: resource.matchTag('123456789012/org-policies', 'allowed-policy-member-domains-all')
- location: null
- title: allow-all
- deny_all: null
- enforce: null
- values: []
- timeouts: null
- module.organization.google_org_policy_policy.default["iam.automaticIamGrantsForDefaultServiceAccounts"]:
- dry_run_spec: []
- name: organizations/123456789012/policies/iam.automaticIamGrantsForDefaultServiceAccounts
- parent: organizations/123456789012
- spec:
- - inherit_from_parent: null
- reset: null
- rules:
- - allow_all: null
- condition: []
- deny_all: null
- enforce: 'TRUE'
- values: []
- timeouts: null
- module.organization.google_org_policy_policy.default["iam.disableServiceAccountKeyCreation"]:
- dry_run_spec: []
- name: organizations/123456789012/policies/iam.disableServiceAccountKeyCreation
- parent: organizations/123456789012
- spec:
- - inherit_from_parent: null
- reset: null
- rules:
- - allow_all: null
- condition: []
- deny_all: null
- enforce: 'TRUE'
- values: []
- timeouts: null
- module.organization.google_org_policy_policy.default["iam.disableServiceAccountKeyUpload"]:
- dry_run_spec: []
- name: organizations/123456789012/policies/iam.disableServiceAccountKeyUpload
- parent: organizations/123456789012
- spec:
- - inherit_from_parent: null
- reset: null
- rules:
- - allow_all: null
- condition: []
- deny_all: null
- enforce: 'TRUE'
- values: []
- timeouts: null
- module.organization.google_org_policy_policy.default["iam.serviceAccountKeyExposureResponse"]:
- dry_run_spec: []
- name: organizations/123456789012/policies/iam.serviceAccountKeyExposureResponse
- parent: organizations/123456789012
- spec:
- - inherit_from_parent: null
- reset: null
- rules:
- - allow_all: null
- condition: []
- deny_all: null
- enforce: null
- values:
- - allowed_values:
- - DISABLE_KEY
- denied_values: null
- timeouts: null
- module.organization.google_org_policy_policy.default["run.allowedIngress"]:
- dry_run_spec: []
- name: organizations/123456789012/policies/run.allowedIngress
- parent: organizations/123456789012
- spec:
- - inherit_from_parent: null
- reset: null
- rules:
- - allow_all: null
- condition: []
- deny_all: null
- enforce: null
- values:
- - allowed_values:
- - is:internal-and-cloud-load-balancing
- denied_values: null
- timeouts: null
- module.organization.google_org_policy_policy.default["sql.restrictAuthorizedNetworks"]:
- dry_run_spec: []
- name: organizations/123456789012/policies/sql.restrictAuthorizedNetworks
- parent: organizations/123456789012
- spec:
- - inherit_from_parent: null
- reset: null
- rules:
- - allow_all: null
- condition: []
- deny_all: null
- enforce: 'TRUE'
- values: []
- timeouts: null
- module.organization.google_org_policy_policy.default["sql.restrictPublicIp"]:
- dry_run_spec: []
- name: organizations/123456789012/policies/sql.restrictPublicIp
- parent: organizations/123456789012
- spec:
- - inherit_from_parent: null
- reset: null
- rules:
- - allow_all: null
- condition: []
- deny_all: null
- enforce: 'TRUE'
- values: []
- timeouts: null
- module.organization.google_org_policy_policy.default["storage.publicAccessPrevention"]:
- dry_run_spec: []
- name: organizations/123456789012/policies/storage.publicAccessPrevention
- parent: organizations/123456789012
- spec:
- - inherit_from_parent: null
- reset: null
- rules:
- - allow_all: null
- condition: []
- deny_all: null
- enforce: 'TRUE'
- values: []
- timeouts: null
- module.organization.google_org_policy_policy.default["storage.secureHttpTransport"]:
- dry_run_spec: []
- name: organizations/123456789012/policies/storage.secureHttpTransport
- parent: organizations/123456789012
- spec:
- - inherit_from_parent: null
- reset: null
- rules:
- - allow_all: null
- condition: []
- deny_all: null
- enforce: 'TRUE'
- values: []
- timeouts: null
- module.organization.google_org_policy_policy.default["storage.uniformBucketLevelAccess"]:
- dry_run_spec: []
- name: organizations/123456789012/policies/storage.uniformBucketLevelAccess
- parent: organizations/123456789012
- spec:
- - inherit_from_parent: null
- reset: null
- rules:
- - allow_all: null
- condition: []
- deny_all: null
- enforce: 'TRUE'
- values: []
- timeouts: null
- module.organization.google_organization_iam_binding.authoritative["roles/billing.creator"]:
- condition: []
- members:
- - group:gcp-billing-admins@fast.example.com
- org_id: '123456789012'
- role: roles/billing.creator
- module.organization.google_organization_iam_binding.authoritative["roles/browser"]:
- condition: []
- members:
- - domain:fast.example.com
- org_id: '123456789012'
- role: roles/browser
- module.organization.google_organization_iam_binding.authoritative["roles/cloudasset.owner"]:
- condition: []
- members:
- - group:gcp-organization-admins@fast.example.com
- - group:gcp-security-admins@fast.example.com
- - group:gcp-vpc-network-admins@fast.example.com
- org_id: '123456789012'
- role: roles/cloudasset.owner
- module.organization.google_organization_iam_binding.authoritative["roles/cloudsupport.admin"]:
- condition: []
- members:
- - group:gcp-organization-admins@fast.example.com
- org_id: '123456789012'
- role: roles/cloudsupport.admin
- module.organization.google_organization_iam_binding.authoritative["roles/cloudsupport.techSupportEditor"]:
- condition: []
- members:
- - group:gcp-devops@fast.example.com
- - group:gcp-security-admins@fast.example.com
- - group:gcp-vpc-network-admins@fast.example.com
- org_id: '123456789012'
- role: roles/cloudsupport.techSupportEditor
- module.organization.google_organization_iam_binding.authoritative["roles/compute.osAdminLogin"]:
- condition: []
- members:
- - group:gcp-organization-admins@fast.example.com
- org_id: '123456789012'
- role: roles/compute.osAdminLogin
- module.organization.google_organization_iam_binding.authoritative["roles/compute.osLoginExternalUser"]:
- condition: []
- members:
- - group:gcp-organization-admins@fast.example.com
- org_id: '123456789012'
- role: roles/compute.osLoginExternalUser
- module.organization.google_organization_iam_binding.authoritative["roles/essentialcontacts.admin"]:
- condition: []
- members:
- - serviceAccount:fast-prod-bootstrap-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- - serviceAccount:fast-prod-resman-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/essentialcontacts.admin
- module.organization.google_organization_iam_binding.authoritative["roles/essentialcontacts.viewer"]:
- condition: []
- members:
- - serviceAccount:fast-prod-bootstrap-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- - serviceAccount:fast-prod-resman-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/essentialcontacts.viewer
- module.organization.google_organization_iam_binding.authoritative["roles/iam.securityReviewer"]:
- condition: []
- members:
- - group:gcp-security-admins@fast.example.com
- org_id: '123456789012'
- role: roles/iam.securityReviewer
- module.organization.google_organization_iam_binding.authoritative["roles/iam.workforcePoolAdmin"]:
- condition: []
- members:
- - group:gcp-organization-admins@fast.example.com
- - serviceAccount:fast-prod-bootstrap-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/iam.workforcePoolAdmin
- module.organization.google_organization_iam_binding.authoritative["roles/logging.admin"]:
- condition: []
- members:
- - group:gcp-security-admins@fast.example.com
- - serviceAccount:fast-prod-bootstrap-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- - serviceAccount:fast-prod-resman-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/logging.admin
- module.organization.google_organization_iam_binding.authoritative["roles/logging.viewer"]:
- condition: []
- members:
- - group:gcp-devops@fast.example.com
- - serviceAccount:fast-prod-bootstrap-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- - serviceAccount:fast-prod-resman-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/logging.viewer
- module.organization.google_organization_iam_binding.authoritative["roles/monitoring.viewer"]:
- condition: []
- members:
- - group:gcp-devops@fast.example.com
- org_id: '123456789012'
- role: roles/monitoring.viewer
- module.organization.google_organization_iam_binding.authoritative["roles/owner"]:
- condition: []
- members:
- - group:gcp-organization-admins@fast.example.com
- org_id: '123456789012'
- role: roles/owner
- module.organization.google_organization_iam_binding.authoritative["roles/resourcemanager.folderAdmin"]:
- condition: []
- members:
- - group:gcp-organization-admins@fast.example.com
- - serviceAccount:fast-prod-resman-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/resourcemanager.folderAdmin
- module.organization.google_organization_iam_binding.authoritative["roles/resourcemanager.folderViewer"]:
- condition: []
- members:
- - group:gcp-devops@fast.example.com
- - group:gcp-vpc-network-admins@fast.example.com
- - serviceAccount:fast-prod-bootstrap-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- - serviceAccount:fast-prod-resman-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/resourcemanager.folderViewer
- module.organization.google_organization_iam_binding.authoritative["roles/resourcemanager.organizationAdmin"]:
- condition: []
- members:
- - group:gcp-organization-admins@fast.example.com
- - serviceAccount:fast-prod-bootstrap-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/resourcemanager.organizationAdmin
- module.organization.google_organization_iam_binding.authoritative["roles/resourcemanager.projectCreator"]:
- condition: []
- members:
- - group:gcp-organization-admins@fast.example.com
- - serviceAccount:fast-prod-bootstrap-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- - serviceAccount:fast-prod-resman-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/resourcemanager.projectCreator
- module.organization.google_organization_iam_binding.authoritative["roles/resourcemanager.projectMover"]:
- condition: []
- members:
- - serviceAccount:fast-prod-bootstrap-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/resourcemanager.projectMover
- module.organization.google_organization_iam_binding.authoritative["roles/resourcemanager.tagAdmin"]:
- condition: []
- members:
- - group:gcp-organization-admins@fast.example.com
- - serviceAccount:fast-prod-bootstrap-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- - serviceAccount:fast-prod-resman-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/resourcemanager.tagAdmin
- module.organization.google_organization_iam_binding.authoritative["roles/resourcemanager.tagUser"]:
- condition: []
- members:
- - serviceAccount:fast-prod-resman-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/resourcemanager.tagUser
- module.organization.google_organization_iam_binding.authoritative["roles/resourcemanager.tagViewer"]:
- condition: []
- members:
- - serviceAccount:fast-prod-bootstrap-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- - serviceAccount:fast-prod-resman-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/resourcemanager.tagViewer
- module.organization.google_organization_iam_binding.authoritative["roles/securitycenter.admin"]:
- condition: []
- members:
- - group:gcp-organization-admins@fast.example.com
- - group:gcp-security-admins@fast.example.com
- org_id: '123456789012'
- role: roles/securitycenter.admin
- module.organization.google_organization_iam_binding.authoritative["roles/serviceusage.serviceUsageViewer"]:
- condition: []
- members:
- - serviceAccount:fast-prod-resman-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/serviceusage.serviceUsageViewer
- module.organization.google_organization_iam_binding.bindings["organization_billing_conditional"]:
- condition:
- - description: Automation service account delegated grants.
- expression: api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly(['roles/billing.admin','roles/billing.costsManager','roles/billing.user'])
- title: automation_sa_delegated_grants
- members:
- - serviceAccount:fast-prod-resman-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: organizations/123456789012/roles/organizationIamAdmin
- 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.orgFirewallPolicyUser'',''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/ngfwEnterpriseViewer'',''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
- org_id: '123456789012'
- role: organizations/123456789012/roles/organizationIamAdmin
- module.organization.google_organization_iam_binding.bindings["organization_ngfw_enterprise_admin"]:
- condition: []
- members:
- - group:gcp-vpc-network-admins@fast.example.com
- org_id: '123456789012'
- role: organizations/123456789012/roles/ngfwEnterpriseAdmin
- module.organization.google_organization_iam_custom_role.roles["gcve_network_admin"]:
- description: Terraform-managed.
- org_id: '123456789012'
- permissions:
- - vmwareengine.networkPeerings.create
- - vmwareengine.networkPeerings.delete
- - vmwareengine.networkPeerings.get
- - vmwareengine.networkPeerings.list
- - vmwareengine.operations.get
- role_id: gcveNetworkAdmin
- stage: GA
- title: Custom role gcveNetworkAdmin
- module.organization.google_organization_iam_custom_role.roles["network_firewall_policies_admin"]:
- description: Terraform-managed.
- org_id: '123456789012'
- permissions:
- - compute.networks.setFirewallPolicy
- - networksecurity.firewallEndpointAssociations.create
- - networksecurity.firewallEndpointAssociations.delete
- - networksecurity.firewallEndpointAssociations.get
- - networksecurity.firewallEndpointAssociations.list
- - networksecurity.firewallEndpointAssociations.update
- role_id: networkFirewallPoliciesAdmin
- stage: GA
- title: Custom role networkFirewallPoliciesAdmin
- module.organization.google_organization_iam_custom_role.roles["ngfw_enterprise_admin"]:
- description: Terraform-managed.
- org_id: '123456789012'
- permissions:
- - 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
- - networksecurity.tlsInspectionPolicies.create
- - networksecurity.tlsInspectionPolicies.get
- - networksecurity.tlsInspectionPolicies.list
- - networksecurity.tlsInspectionPolicies.update
- - networksecurity.tlsInspectionPolicies.use
- role_id: ngfwEnterpriseAdmin
- stage: GA
- title: Custom role ngfwEnterpriseAdmin
- module.organization.google_organization_iam_custom_role.roles["ngfw_enterprise_viewer"]:
- description: Terraform-managed.
- org_id: '123456789012'
- permissions:
- - networksecurity.firewallEndpoints.get
- - networksecurity.firewallEndpoints.list
- - networksecurity.firewallEndpoints.use
- - networksecurity.locations.get
- - networksecurity.locations.list
- - networksecurity.operations.get
- - networksecurity.operations.list
- - networksecurity.securityProfileGroups.get
- - networksecurity.securityProfileGroups.list
- - networksecurity.securityProfileGroups.use
- - networksecurity.securityProfiles.get
- - networksecurity.securityProfiles.list
- - networksecurity.securityProfiles.use
- - networksecurity.tlsInspectionPolicies.get
- - networksecurity.tlsInspectionPolicies.list
- - networksecurity.tlsInspectionPolicies.use
- role_id: ngfwEnterpriseViewer
- stage: GA
- title: Custom role ngfwEnterpriseViewer
- module.organization.google_organization_iam_custom_role.roles["organization_admin_viewer"]:
- description: Terraform-managed.
- org_id: '123456789012'
- permissions:
- - essentialcontacts.contacts.get
- - essentialcontacts.contacts.list
- - logging.settings.get
- - orgpolicy.constraints.list
- - orgpolicy.policies.list
- - orgpolicy.policy.get
- - resourcemanager.folders.get
- - resourcemanager.folders.getIamPolicy
- - resourcemanager.folders.list
- - resourcemanager.organizations.get
- - resourcemanager.organizations.getIamPolicy
- - resourcemanager.projects.get
- - resourcemanager.projects.getIamPolicy
- - resourcemanager.projects.list
- role_id: organizationAdminViewer
- stage: GA
- title: Custom role organizationAdminViewer
- module.organization.google_organization_iam_custom_role.roles["organization_iam_admin"]:
- description: Terraform-managed.
- org_id: '123456789012'
- permissions:
- - resourcemanager.organizations.get
- - resourcemanager.organizations.getIamPolicy
- - resourcemanager.organizations.setIamPolicy
- role_id: organizationIamAdmin
- stage: GA
- title: Custom role organizationIamAdmin
- module.organization.google_organization_iam_custom_role.roles["service_project_network_admin"]:
- description: Terraform-managed.
- org_id: '123456789012'
- permissions:
- - compute.globalOperations.get
- - compute.networks.get
- - compute.networks.updatePeering
- - compute.organizations.disableXpnResource
- - compute.organizations.enableXpnResource
- - compute.projects.get
- - compute.subnetworks.getIamPolicy
- - compute.subnetworks.setIamPolicy
- - dns.networks.bindPrivateDNSZone
- - resourcemanager.projects.get
- role_id: serviceProjectNetworkAdmin
- stage: GA
- title: Custom role serviceProjectNetworkAdmin
- module.organization.google_organization_iam_custom_role.roles["storage_viewer"]:
- description: Terraform-managed.
- org_id: '123456789012'
- permissions:
- - storage.buckets.get
- - storage.buckets.getIamPolicy
- - storage.buckets.getObjectInsights
- - storage.buckets.list
- - storage.buckets.listEffectiveTags
- - storage.buckets.listTagBindings
- - storage.managedFolders.get
- - storage.managedFolders.getIamPolicy
- - storage.managedFolders.list
- - storage.multipartUploads.list
- - storage.multipartUploads.listParts
- - storage.objects.create
- - storage.objects.get
- - storage.objects.getIamPolicy
- - storage.objects.list
- role_id: storageViewer
- stage: GA
- title: Custom role storageViewer
- module.organization.google_organization_iam_custom_role.roles["tag_viewer"]:
- description: Terraform-managed.
- org_id: '123456789012'
- permissions:
- - resourcemanager.tagHolds.list
- - resourcemanager.tagKeys.get
- - resourcemanager.tagKeys.getIamPolicy
- - resourcemanager.tagKeys.list
- - resourcemanager.tagValues.get
- - resourcemanager.tagValues.getIamPolicy
- - resourcemanager.tagValues.list
- role_id: tagViewer
- stage: GA
- title: Custom role tagViewer
- module.organization.google_organization_iam_custom_role.roles["tenant_network_admin"]:
- description: Terraform-managed.
- org_id: '123456789012'
- permissions:
- - compute.globalOperations.get
- role_id: tenantNetworkAdmin
- stage: GA
- title: Custom role tenantNetworkAdmin
- ? module.organization.google_organization_iam_member.bindings["roles/accesscontextmanager.policyAdmin-group:gcp-security-admins@fast.example.com"]
- : condition: []
- member: group:gcp-security-admins@fast.example.com
- org_id: '123456789012'
- role: roles/accesscontextmanager.policyAdmin
- ? module.organization.google_organization_iam_member.bindings["roles/accesscontextmanager.policyAdmin-serviceAccount:fast-prod-resman-0@fast-prod-iac-core-0.iam.gserviceaccount.com"]
- : condition: []
- member: serviceAccount:fast-prod-resman-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/accesscontextmanager.policyAdmin
- ? module.organization.google_organization_iam_member.bindings["roles/accesscontextmanager.policyAdmin-serviceAccount:fast-prod-vpcsc-0@fast-prod-iac-core-0.iam.gserviceaccount.com"]
- : condition: []
- member: serviceAccount:fast-prod-vpcsc-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/accesscontextmanager.policyAdmin
- ? module.organization.google_organization_iam_member.bindings["roles/accesscontextmanager.policyReader-serviceAccount:fast-prod-resman-0r@fast-prod-iac-core-0.iam.gserviceaccount.com"]
- : condition: []
- member: serviceAccount:fast-prod-resman-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/accesscontextmanager.policyReader
- ? module.organization.google_organization_iam_member.bindings["roles/accesscontextmanager.policyReader-serviceAccount:fast-prod-vpcsc-0r@fast-prod-iac-core-0.iam.gserviceaccount.com"]
- : condition: []
- member: serviceAccount:fast-prod-vpcsc-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/accesscontextmanager.policyReader
- ? module.organization.google_organization_iam_member.bindings["roles/billing.admin-group:gcp-billing-admins@fast.example.com"]
- : condition: []
- member: group:gcp-billing-admins@fast.example.com
- org_id: '123456789012'
- role: roles/billing.admin
- ? module.organization.google_organization_iam_member.bindings["roles/billing.admin-group:gcp-organization-admins@fast.example.com"]
- : condition: []
- member: group:gcp-organization-admins@fast.example.com
- org_id: '123456789012'
- role: roles/billing.admin
- ? module.organization.google_organization_iam_member.bindings["roles/billing.admin-serviceAccount:fast-prod-bootstrap-0@fast-prod-iac-core-0.iam.gserviceaccount.com"]
- : condition: []
- member: serviceAccount:fast-prod-bootstrap-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/billing.admin
- ? module.organization.google_organization_iam_member.bindings["roles/billing.admin-serviceAccount:fast-prod-resman-0@fast-prod-iac-core-0.iam.gserviceaccount.com"]
- : condition: []
- member: serviceAccount:fast-prod-resman-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/billing.admin
- ? module.organization.google_organization_iam_member.bindings["roles/billing.user-group:gcp-organization-admins@fast.example.com"]
- : condition: []
- member: group:gcp-organization-admins@fast.example.com
- org_id: '123456789012'
- role: roles/billing.user
- ? module.organization.google_organization_iam_member.bindings["roles/billing.viewer-serviceAccount:fast-prod-bootstrap-0r@fast-prod-iac-core-0.iam.gserviceaccount.com"]
- : condition: []
- member: serviceAccount:fast-prod-bootstrap-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/billing.viewer
- ? module.organization.google_organization_iam_member.bindings["roles/billing.viewer-serviceAccount:fast-prod-resman-0r@fast-prod-iac-core-0.iam.gserviceaccount.com"]
- : condition: []
- member: serviceAccount:fast-prod-resman-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/billing.viewer
- ? module.organization.google_organization_iam_member.bindings["roles/cloudasset.viewer-serviceAccount:fast-prod-vpcsc-0@fast-prod-iac-core-0.iam.gserviceaccount.com"]
- : condition: []
- member: serviceAccount:fast-prod-vpcsc-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/cloudasset.viewer
- ? module.organization.google_organization_iam_member.bindings["roles/cloudasset.viewer-serviceAccount:fast-prod-vpcsc-0r@fast-prod-iac-core-0.iam.gserviceaccount.com"]
- : condition: []
- member: serviceAccount:fast-prod-vpcsc-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/cloudasset.viewer
- ? module.organization.google_organization_iam_member.bindings["roles/compute.networkAdmin-group:gcp-vpc-network-admins@fast.example.com"]
- : condition: []
- member: group:gcp-vpc-network-admins@fast.example.com
- org_id: '123456789012'
- role: roles/compute.networkAdmin
- ? module.organization.google_organization_iam_member.bindings["roles/compute.orgFirewallPolicyAdmin-group:gcp-vpc-network-admins@fast.example.com"]
- : condition: []
- member: group:gcp-vpc-network-admins@fast.example.com
- org_id: '123456789012'
- role: roles/compute.orgFirewallPolicyAdmin
- ? module.organization.google_organization_iam_member.bindings["roles/compute.securityAdmin-group:gcp-vpc-network-admins@fast.example.com"]
- : condition: []
- member: group:gcp-vpc-network-admins@fast.example.com
- org_id: '123456789012'
- role: roles/compute.securityAdmin
- ? module.organization.google_organization_iam_member.bindings["roles/compute.viewer-group:gcp-security-admins@fast.example.com"]
- : condition: []
- member: group:gcp-security-admins@fast.example.com
- org_id: '123456789012'
- role: roles/compute.viewer
- ? module.organization.google_organization_iam_member.bindings["roles/compute.xpnAdmin-group:gcp-vpc-network-admins@fast.example.com"]
- : condition: []
- member: group:gcp-vpc-network-admins@fast.example.com
- org_id: '123456789012'
- role: roles/compute.xpnAdmin
- ? module.organization.google_organization_iam_member.bindings["roles/container.viewer-group:gcp-security-admins@fast.example.com"]
- : condition: []
- member: group:gcp-security-admins@fast.example.com
- org_id: '123456789012'
- role: roles/container.viewer
- ? module.organization.google_organization_iam_member.bindings["roles/iam.organizationRoleAdmin-group:gcp-organization-admins@fast.example.com"]
- : condition: []
- member: group:gcp-organization-admins@fast.example.com
- org_id: '123456789012'
- role: roles/iam.organizationRoleAdmin
- ? module.organization.google_organization_iam_member.bindings["roles/iam.organizationRoleAdmin-group:gcp-security-admins@fast.example.com"]
- : condition: []
- member: group:gcp-security-admins@fast.example.com
- org_id: '123456789012'
- role: roles/iam.organizationRoleAdmin
- ? module.organization.google_organization_iam_member.bindings["roles/iam.organizationRoleAdmin-serviceAccount:fast-prod-bootstrap-0@fast-prod-iac-core-0.iam.gserviceaccount.com"]
- : condition: []
- member: serviceAccount:fast-prod-bootstrap-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/iam.organizationRoleAdmin
- ? module.organization.google_organization_iam_member.bindings["roles/iam.organizationRoleViewer-group:gcp-security-admins@fast.example.com"]
- : condition: []
- member: group:gcp-security-admins@fast.example.com
- org_id: '123456789012'
- role: roles/iam.organizationRoleViewer
- ? module.organization.google_organization_iam_member.bindings["roles/iam.organizationRoleViewer-serviceAccount:fast-prod-bootstrap-0r@fast-prod-iac-core-0.iam.gserviceaccount.com"]
- : condition: []
- member: serviceAccount:fast-prod-bootstrap-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/iam.organizationRoleViewer
- ? module.organization.google_organization_iam_member.bindings["roles/iam.workforcePoolViewer-serviceAccount:fast-prod-bootstrap-0r@fast-prod-iac-core-0.iam.gserviceaccount.com"]
- : condition: []
- member: serviceAccount:fast-prod-bootstrap-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/iam.workforcePoolViewer
- ? module.organization.google_organization_iam_member.bindings["roles/logging.configWriter-group:gcp-security-admins@fast.example.com"]
- : condition: []
- member: group:gcp-security-admins@fast.example.com
- org_id: '123456789012'
- role: roles/logging.configWriter
- ? module.organization.google_organization_iam_member.bindings["roles/logging.privateLogViewer-group:gcp-security-admins@fast.example.com"]
- : condition: []
- member: group:gcp-security-admins@fast.example.com
- org_id: '123456789012'
- role: roles/logging.privateLogViewer
- ? module.organization.google_organization_iam_member.bindings["roles/monitoring.admin-group:gcp-monitoring-admins@fast.example.com"]
- : condition: []
- member: group:gcp-monitoring-admins@fast.example.com
- org_id: '123456789012'
- role: roles/monitoring.admin
- ? module.organization.google_organization_iam_member.bindings["roles/orgpolicy.policyAdmin-group:gcp-organization-admins@fast.example.com"]
- : condition: []
- member: group:gcp-organization-admins@fast.example.com
- org_id: '123456789012'
- role: roles/orgpolicy.policyAdmin
- ? module.organization.google_organization_iam_member.bindings["roles/orgpolicy.policyAdmin-group:gcp-security-admins@fast.example.com"]
- : condition: []
- member: group:gcp-security-admins@fast.example.com
- org_id: '123456789012'
- role: roles/orgpolicy.policyAdmin
- ? module.organization.google_organization_iam_member.bindings["roles/orgpolicy.policyAdmin-serviceAccount:fast-prod-bootstrap-0@fast-prod-iac-core-0.iam.gserviceaccount.com"]
- : condition: []
- member: serviceAccount:fast-prod-bootstrap-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/orgpolicy.policyAdmin
- ? module.organization.google_organization_iam_member.bindings["roles/orgpolicy.policyAdmin-serviceAccount:fast-prod-resman-0@fast-prod-iac-core-0.iam.gserviceaccount.com"]
- : condition: []
- member: serviceAccount:fast-prod-resman-0@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/orgpolicy.policyAdmin
- ? module.organization.google_organization_iam_member.bindings["roles/orgpolicy.policyViewer-serviceAccount:fast-prod-bootstrap-0r@fast-prod-iac-core-0.iam.gserviceaccount.com"]
- : condition: []
- member: serviceAccount:fast-prod-bootstrap-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/orgpolicy.policyViewer
- ? module.organization.google_organization_iam_member.bindings["roles/orgpolicy.policyViewer-serviceAccount:fast-prod-resman-0r@fast-prod-iac-core-0.iam.gserviceaccount.com"]
- : condition: []
- member: serviceAccount:fast-prod-resman-0r@fast-prod-iac-core-0.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/orgpolicy.policyViewer
- ? module.organization.google_organization_iam_member.bindings["roles/resourcemanager.folderIamAdmin-group:gcp-security-admins@fast.example.com"]
- : condition: []
- member: group:gcp-security-admins@fast.example.com
- org_id: '123456789012'
- role: roles/resourcemanager.folderIamAdmin
- ? module.organization.google_organization_iam_member.bindings["roles/resourcemanager.organizationViewer-group:gcp-billing-admins@fast.example.com"]
- : condition: []
- member: group:gcp-billing-admins@fast.example.com
- org_id: '123456789012'
- role: roles/resourcemanager.organizationViewer
- ? module.organization.google_organization_iam_member.bindings["roles/storage.objectAdmin-group:gcp-organization-admins@fast.example.com"]
- : condition: []
- member: group:gcp-organization-admins@fast.example.com
- org_id: '123456789012'
- role: roles/storage.objectAdmin
- module.organization.google_project_iam_member.bucket-sinks-binding["audit-logs"]:
- condition:
- - title: audit-logs bucket writer
- role: roles/logging.bucketWriter
- module.organization.google_project_iam_member.bucket-sinks-binding["iam"]:
- condition:
- - title: iam bucket writer
- role: roles/logging.bucketWriter
- module.organization.google_project_iam_member.bucket-sinks-binding["vpc-sc"]:
- condition:
- - title: vpc-sc bucket writer
- role: roles/logging.bucketWriter
- module.organization.google_project_iam_member.bucket-sinks-binding["workspace-audit-logs"]:
- condition:
- - title: workspace-audit-logs bucket writer
- role: roles/logging.bucketWriter
- module.organization.google_tags_tag_key.default["org-policies"]:
- description: Organization policy conditions.
- parent: organizations/123456789012
- purpose: null
- purpose_data: null
- short_name: org-policies
- timeouts: null
- module.organization.google_tags_tag_value.default["org-policies/allowed-policy-member-domains-all"]:
- description: Managed by the Terraform organization module.
- short_name: allowed-policy-member-domains-all
- timeouts: null
-
-counts:
- google_bigquery_dataset: 1
- google_bigquery_default_service_account: 3
- google_essential_contacts_contact: 3
- google_logging_organization_settings: 1
- google_logging_organization_sink: 4
- google_logging_project_bucket_config: 4
- google_org_policy_policy: 24
- google_organization_iam_binding: 28
- google_organization_iam_custom_role: 10
- google_organization_iam_member: 42
- google_project: 3
- google_project_iam_audit_config: 1
- google_project_iam_binding: 19
- google_project_iam_member: 16
- 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
- google_storage_bucket: 5
- google_storage_bucket_iam_binding: 4
- google_storage_bucket_iam_member: 6
- google_storage_bucket_object: 12
- google_storage_project_service_account: 3
- google_tags_tag_key: 1
- google_tags_tag_value: 2
- modules: 21
- resources: 239
diff --git a/tests/fast/stages/s0_bootstrap/simple.yaml b/tests/fast/stages/s0_bootstrap/simple.yaml
index 0186f3862..259d2e38b 100644
--- a/tests/fast/stages/s0_bootstrap/simple.yaml
+++ b/tests/fast/stages/s0_bootstrap/simple.yaml
@@ -20,8 +20,8 @@ counts:
google_logging_organization_sink: 4
google_logging_project_bucket_config: 4
google_org_policy_policy: 24
- google_organization_iam_binding: 28
- google_organization_iam_custom_role: 10
+ google_organization_iam_binding: 27
+ google_organization_iam_custom_role: 13
google_organization_iam_member: 29
google_project: 3
google_project_iam_audit_config: 1
@@ -41,19 +41,22 @@ counts:
google_tags_tag_value: 2
local_file: 10
modules: 20
- resources: 233
+ resources: 235
outputs:
automation: __missing__
billing_dataset: __missing__
cicd_repositories: {}
custom_roles:
+ billing_viewer: organizations/123456789012/roles/billingViewer
gcve_network_admin: organizations/123456789012/roles/gcveNetworkAdmin
+ gcve_network_viewer: organizations/123456789012/roles/gcveNetworkViewer
network_firewall_policies_admin: organizations/123456789012/roles/networkFirewallPoliciesAdmin
ngfw_enterprise_admin: organizations/123456789012/roles/ngfwEnterpriseAdmin
ngfw_enterprise_viewer: organizations/123456789012/roles/ngfwEnterpriseViewer
organization_admin_viewer: organizations/123456789012/roles/organizationAdminViewer
organization_iam_admin: organizations/123456789012/roles/organizationIamAdmin
+ project_iam_viewer: organizations/123456789012/roles/projectIamViewer
service_project_network_admin: organizations/123456789012/roles/serviceProjectNetworkAdmin
storage_viewer: organizations/123456789012/roles/storageViewer
tag_viewer: organizations/123456789012/roles/tagViewer
@@ -71,4 +74,4 @@ outputs:
pool: null
workload_identity_pool:
pool: null
- providers: {}
\ No newline at end of file
+ providers: {}
diff --git a/tests/fast/stages/s0_bootstrap/tftest.yaml b/tests/fast/stages/s0_bootstrap/tftest.yaml
index 2643714eb..dd8319456 100644
--- a/tests/fast/stages/s0_bootstrap/tftest.yaml
+++ b/tests/fast/stages/s0_bootstrap/tftest.yaml
@@ -16,14 +16,10 @@
module: fast/stages/0-bootstrap
tests:
- checklist:
- extra_files:
- - ../../../tests/fast/stages/s0_bootstrap/data/checklist-data.json
- - ../../../tests/fast/stages/s0_bootstrap/data/checklist-org-iam.json
simple:
inventory:
- simple.yaml
- simple_projects.yaml
- simple_sas.yaml
-
+
iam_by_principals:
diff --git a/tests/fast/stages/s1_resman/checklist.tfvars b/tests/fast/stages/s1_resman/checklist.tfvars
deleted file mode 100644
index 2f998e54b..000000000
--- a/tests/fast/stages/s1_resman/checklist.tfvars
+++ /dev/null
@@ -1,45 +0,0 @@
-automation = {
- cicd_backends = null
- federated_identity_pool = null
- federated_identity_providers = null
- project_id = "fast-prod-automation"
- project_number = 123456
- outputs_bucket = "test"
- service_accounts = {
- resman-r = "ldj-prod-resman-0r@fast2-prod-iac-core-0.iam.gserviceaccount.com"
- }
-}
-billing_account = {
- id = "000000-111111-222222"
-}
-custom_roles = {
- # organization_iam_admin = "organizations/123456789012/roles/organizationIamAdmin",
- gcve_network_admin = "organizations/123456789012/roles/gcveNetworkAdmin"
- network_firewall_policies_admin = "organizations/123456789012/roles/networkFirewallPoliciesAdmin"
- network_firewall_policies_viewer = "organizations/123456789012/roles/networkFirewallPoliciesViewer"
- ngfw_enterprise_admin = "organizations/123456789012/roles/ngfwEnterpriseAdmin"
- ngfw_enterprise_viewer = "organizations/123456789012/roles/ngfwEnterpriseViewer"
- 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"
-}
-groups = {
- gcp-billing-admins = "gcp-billing-admins",
- gcp-devops = "gcp-devops",
- gcp-network-admins = "gcp-vpc-network-admins",
- gcp-organization-admins = "gcp-organization-admins",
- gcp-security-admins = "gcp-security-admins",
- gcp-support = "gcp-support"
-}
-logging = {
- project_id = "fast-prod-log-audit-0"
-}
-organization = {
- domain = "fast.example.com"
- id = 123456789012
- customer_id = "C00000000"
-}
-prefix = "fast2"
diff --git a/tests/fast/stages/s1_resman/checklist.yaml b/tests/fast/stages/s1_resman/checklist.yaml
deleted file mode 100644
index 4fe2b0647..000000000
--- a/tests/fast/stages/s1_resman/checklist.yaml
+++ /dev/null
@@ -1,1282 +0,0 @@
-# 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.
-
-values:
- google_storage_bucket_object.providers["2-networking"]:
- bucket: test
- cache_control: null
- content_disposition: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
- name: providers/2-networking-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
- google_storage_bucket_object.providers["2-networking-r"]:
- bucket: test
- cache_control: null
- content_disposition: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
- name: providers/2-networking-r-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
- google_storage_bucket_object.providers["2-project-factory"]:
- bucket: test
- cache_control: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
- name: providers/2-project-factory-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
- google_storage_bucket_object.providers["2-project-factory-dev"]:
- bucket: test
- cache_control: null
- content_disposition: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
- name: providers/2-project-factory-dev-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
- google_storage_bucket_object.providers["2-project-factory-dev-r"]:
- bucket: test
- cache_control: null
- content_disposition: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
- name: providers/2-project-factory-dev-r-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
- google_storage_bucket_object.providers["2-project-factory-prod"]:
- bucket: test
- cache_control: null
- content_disposition: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
- name: providers/2-project-factory-prod-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
- google_storage_bucket_object.providers["2-project-factory-prod-r"]:
- bucket: test
- cache_control: null
- content_disposition: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
- name: providers/2-project-factory-prod-r-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
- google_storage_bucket_object.providers["2-project-factory-r"]:
- bucket: test
- cache_control: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
- name: providers/2-project-factory-r-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
- google_storage_bucket_object.providers["2-security"]:
- bucket: test
- cache_control: null
- content_disposition: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
- name: providers/2-security-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
- google_storage_bucket_object.providers["2-security-r"]:
- bucket: test
- cache_control: null
- content_disposition: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
- name: providers/2-security-r-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
- google_storage_bucket_object.tfvars:
- bucket: test
- cache_control: null
- content_disposition: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
- name: tfvars/1-resman.auto.tfvars.json
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
- module.branch-network-dev-folder.google_folder.folder[0]:
- display_name: Development
- timeouts: null
- ? module.branch-network-dev-folder.google_folder_iam_binding.authoritative["organizations/123456789012/roles/gcveNetworkAdmin"]
- : condition: []
- members: null
- role: organizations/123456789012/roles/gcveNetworkAdmin
- ? module.branch-network-dev-folder.google_folder_iam_binding.authoritative["organizations/123456789012/roles/xpnServiceAdmin"]
- : condition: []
- members:
- - serviceAccount:fast2-dev-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- - serviceAccount:fast2-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- role: organizations/123456789012/roles/xpnServiceAdmin
- module.branch-network-dev-folder.google_folder_iam_binding.authoritative["roles/compute.networkViewer"]:
- condition: []
- members:
- - serviceAccount:fast2-dev-resman-pf-0r@fast-prod-automation.iam.gserviceaccount.com
- - serviceAccount:fast2-resman-pf-0r@fast-prod-automation.iam.gserviceaccount.com
- role: roles/compute.networkViewer
- module.branch-network-dev-folder.google_tags_tag_binding.binding["environment"]:
- timeouts: null
- module.branch-network-folder.google_folder.folder[0]:
- display_name: Networking
- parent: organizations/123456789012
- timeouts: null
- module.branch-network-folder.google_folder_iam_binding.authoritative["roles/compute.xpnAdmin"]:
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-net-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/compute.xpnAdmin
- module.branch-network-folder.google_folder_iam_binding.authoritative["roles/editor"]:
- condition: []
- members:
- - group:gcp-vpc-network-admins@fast.example.com
- role: roles/editor
- module.branch-network-folder.google_folder_iam_binding.authoritative["roles/logging.admin"]:
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-net-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/logging.admin
- module.branch-network-folder.google_folder_iam_binding.authoritative["roles/owner"]:
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-net-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/owner
- module.branch-network-folder.google_folder_iam_binding.authoritative["roles/resourcemanager.folderAdmin"]:
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-net-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/resourcemanager.folderAdmin
- module.branch-network-folder.google_folder_iam_binding.authoritative["roles/resourcemanager.folderViewer"]:
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-net-0r@fast-prod-automation.iam.gserviceaccount.com
- role: roles/resourcemanager.folderViewer
- module.branch-network-folder.google_folder_iam_binding.authoritative["roles/resourcemanager.projectCreator"]:
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-net-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/resourcemanager.projectCreator
- module.branch-network-folder.google_folder_iam_binding.authoritative["roles/viewer"]:
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-net-0r@fast-prod-automation.iam.gserviceaccount.com
- role: roles/viewer
- module.branch-network-folder.google_tags_tag_binding.binding["context"]:
- timeouts: null
- module.branch-network-gcs.google_storage_bucket.bucket:
- autoclass: []
- cors: []
- custom_placement_config: []
- default_event_based_hold: null
- enable_object_retention: null
- encryption: []
- force_destroy: false
- labels: null
- lifecycle_rule: []
- location: EU
- logging: []
- name: fast2-prod-resman-net-0
- project: fast-prod-automation
- requester_pays: null
- retention_policy: []
- storage_class: STANDARD
- timeouts: null
- uniform_bucket_level_access: true
- versioning:
- - enabled: true
- module.branch-network-gcs.google_storage_bucket_iam_binding.authoritative["roles/storage.objectAdmin"]:
- bucket: fast2-prod-resman-net-0
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-net-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/storage.objectAdmin
- module.branch-network-gcs.google_storage_bucket_iam_binding.authoritative["roles/storage.objectViewer"]:
- bucket: fast2-prod-resman-net-0
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-net-0r@fast-prod-automation.iam.gserviceaccount.com
- role: roles/storage.objectViewer
- module.branch-network-prod-folder.google_folder.folder[0]:
- display_name: Production
- timeouts: null
- ? module.branch-network-prod-folder.google_folder_iam_binding.authoritative["organizations/123456789012/roles/gcveNetworkAdmin"]
- : condition: []
- members: null
- role: organizations/123456789012/roles/gcveNetworkAdmin
- ? module.branch-network-prod-folder.google_folder_iam_binding.authoritative["organizations/123456789012/roles/xpnServiceAdmin"]
- : condition: []
- members:
- - serviceAccount:fast2-prod-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- - serviceAccount:fast2-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- role: organizations/123456789012/roles/xpnServiceAdmin
- module.branch-network-prod-folder.google_folder_iam_binding.authoritative["roles/compute.networkViewer"]:
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-pf-0r@fast-prod-automation.iam.gserviceaccount.com
- - serviceAccount:fast2-resman-pf-0r@fast-prod-automation.iam.gserviceaccount.com
- role: roles/compute.networkViewer
- module.branch-network-prod-folder.google_tags_tag_binding.binding["environment"]:
- timeouts: null
- ? module.branch-network-r-sa.google_project_iam_member.project-roles["fast-prod-automation-roles/serviceusage.serviceUsageConsumer"]
- : condition: []
- project: fast-prod-automation
- role: roles/serviceusage.serviceUsageConsumer
- module.branch-network-r-sa.google_service_account.service_account[0]:
- account_id: fast2-prod-resman-net-0r
- create_ignore_already_exists: null
- description: null
- disabled: false
- display_name: Terraform resman networking service account (read-only).
- project: fast-prod-automation
- timeouts: null
- module.branch-network-r-sa.google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
- condition: []
- members: null
- role: roles/iam.serviceAccountTokenCreator
- ? module.branch-network-r-sa.google_storage_bucket_iam_member.bucket-roles["test-organizations/123456789012/roles/storageViewer"]
- : bucket: test
- condition: []
- role: organizations/123456789012/roles/storageViewer
- ? module.branch-network-sa.google_project_iam_member.project-roles["fast-prod-automation-roles/serviceusage.serviceUsageConsumer"]
- : condition: []
- project: fast-prod-automation
- role: roles/serviceusage.serviceUsageConsumer
- module.branch-network-sa.google_service_account.service_account[0]:
- account_id: fast2-prod-resman-net-0
- create_ignore_already_exists: null
- description: null
- disabled: false
- display_name: Terraform resman networking service account.
- project: fast-prod-automation
- timeouts: null
- module.branch-network-sa.google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
- condition: []
- members: null
- role: roles/iam.serviceAccountTokenCreator
- module.branch-network-sa.google_storage_bucket_iam_member.bucket-roles["test-roles/storage.objectAdmin"]:
- bucket: test
- condition: []
- role: roles/storage.objectAdmin
- module.branch-pf-dev-gcs.google_storage_bucket.bucket:
- autoclass: []
- cors: []
- custom_placement_config: []
- default_event_based_hold: null
- enable_object_retention: null
- encryption: []
- force_destroy: false
- labels: null
- lifecycle_rule: []
- location: EU
- logging: []
- name: fast2-dev-resman-pf-0
- project: fast-prod-automation
- requester_pays: null
- retention_policy: []
- storage_class: STANDARD
- timeouts: null
- uniform_bucket_level_access: true
- versioning:
- - enabled: true
- module.branch-pf-dev-gcs.google_storage_bucket_iam_binding.authoritative["roles/storage.objectAdmin"]:
- bucket: fast2-dev-resman-pf-0
- condition: []
- members:
- - serviceAccount:fast2-dev-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/storage.objectAdmin
- module.branch-pf-dev-gcs.google_storage_bucket_iam_binding.authoritative["roles/storage.objectViewer"]:
- bucket: fast2-dev-resman-pf-0
- condition: []
- members:
- - serviceAccount:fast2-dev-resman-pf-0r@fast-prod-automation.iam.gserviceaccount.com
- role: roles/storage.objectViewer
- ? module.branch-pf-dev-r-sa.google_project_iam_member.project-roles["fast-prod-automation-roles/serviceusage.serviceUsageConsumer"]
- : condition: []
- project: fast-prod-automation
- role: roles/serviceusage.serviceUsageConsumer
- module.branch-pf-dev-r-sa.google_service_account.service_account[0]:
- account_id: fast2-dev-resman-pf-0r
- create_ignore_already_exists: null
- description: null
- disabled: false
- display_name: Terraform project factory development service account (read-only).
- project: fast-prod-automation
- timeouts: null
- module.branch-pf-dev-r-sa.google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
- condition: []
- members: null
- role: roles/iam.serviceAccountTokenCreator
- ? module.branch-pf-dev-r-sa.google_storage_bucket_iam_member.bucket-roles["test-organizations/123456789012/roles/storageViewer"]
- : bucket: test
- condition: []
- role: organizations/123456789012/roles/storageViewer
- ? module.branch-pf-dev-sa.google_project_iam_member.project-roles["fast-prod-automation-roles/serviceusage.serviceUsageConsumer"]
- : condition: []
- project: fast-prod-automation
- role: roles/serviceusage.serviceUsageConsumer
- module.branch-pf-dev-sa.google_service_account.service_account[0]:
- account_id: fast2-dev-resman-pf-0
- create_ignore_already_exists: null
- description: null
- disabled: false
- display_name: Terraform project factory development service account.
- project: fast-prod-automation
- timeouts: null
- module.branch-pf-dev-sa.google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
- condition: []
- members: null
- role: roles/iam.serviceAccountTokenCreator
- module.branch-pf-dev-sa.google_storage_bucket_iam_member.bucket-roles["test-roles/storage.objectAdmin"]:
- bucket: test
- condition: []
- role: roles/storage.objectAdmin
- module.branch-pf-gcs.google_storage_bucket.bucket:
- autoclass: []
- cors: []
- custom_placement_config: []
- default_event_based_hold: null
- enable_object_retention: null
- encryption: []
- force_destroy: false
- labels: null
- lifecycle_rule: []
- location: EU
- logging: []
- name: fast2-resman-pf-0
- project: fast-prod-automation
- requester_pays: null
- retention_policy: []
- storage_class: STANDARD
- timeouts: null
- uniform_bucket_level_access: true
- versioning:
- - enabled: true
- module.branch-pf-gcs.google_storage_bucket_iam_binding.authoritative["roles/storage.objectAdmin"]:
- bucket: fast2-resman-pf-0
- condition: []
- members:
- - serviceAccount:fast2-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/storage.objectAdmin
- module.branch-pf-gcs.google_storage_bucket_iam_binding.authoritative["roles/storage.objectViewer"]:
- bucket: fast2-resman-pf-0
- condition: []
- members:
- - serviceAccount:fast2-resman-pf-0r@fast-prod-automation.iam.gserviceaccount.com
- role: roles/storage.objectViewer
- module.branch-pf-prod-gcs.google_storage_bucket.bucket:
- autoclass: []
- cors: []
- custom_placement_config: []
- default_event_based_hold: null
- enable_object_retention: null
- encryption: []
- force_destroy: false
- labels: null
- lifecycle_rule: []
- location: EU
- logging: []
- name: fast2-prod-resman-pf-0
- project: fast-prod-automation
- requester_pays: null
- retention_policy: []
- storage_class: STANDARD
- timeouts: null
- uniform_bucket_level_access: true
- versioning:
- - enabled: true
- module.branch-pf-prod-gcs.google_storage_bucket_iam_binding.authoritative["roles/storage.objectAdmin"]:
- bucket: fast2-prod-resman-pf-0
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/storage.objectAdmin
- module.branch-pf-prod-gcs.google_storage_bucket_iam_binding.authoritative["roles/storage.objectViewer"]:
- bucket: fast2-prod-resman-pf-0
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-pf-0r@fast-prod-automation.iam.gserviceaccount.com
- role: roles/storage.objectViewer
- ? module.branch-pf-prod-r-sa.google_project_iam_member.project-roles["fast-prod-automation-roles/serviceusage.serviceUsageConsumer"]
- : condition: []
- project: fast-prod-automation
- role: roles/serviceusage.serviceUsageConsumer
- module.branch-pf-prod-r-sa.google_service_account.service_account[0]:
- account_id: fast2-prod-resman-pf-0r
- create_ignore_already_exists: null
- description: null
- disabled: false
- display_name: Terraform project factory production service account (read-only).
- project: fast-prod-automation
- timeouts: null
- module.branch-pf-prod-r-sa.google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
- condition: []
- members: null
- role: roles/iam.serviceAccountTokenCreator
- ? module.branch-pf-prod-r-sa.google_storage_bucket_iam_member.bucket-roles["test-organizations/123456789012/roles/storageViewer"]
- : bucket: test
- condition: []
- role: organizations/123456789012/roles/storageViewer
- ? module.branch-pf-prod-sa.google_project_iam_member.project-roles["fast-prod-automation-roles/serviceusage.serviceUsageConsumer"]
- : condition: []
- project: fast-prod-automation
- role: roles/serviceusage.serviceUsageConsumer
- module.branch-pf-prod-sa.google_service_account.service_account[0]:
- account_id: fast2-prod-resman-pf-0
- create_ignore_already_exists: null
- description: null
- disabled: false
- display_name: Terraform project factory production service account.
- project: fast-prod-automation
- timeouts: null
- module.branch-pf-prod-sa.google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
- condition: []
- members: null
- role: roles/iam.serviceAccountTokenCreator
- module.branch-pf-prod-sa.google_storage_bucket_iam_member.bucket-roles["test-roles/storage.objectAdmin"]:
- bucket: test
- condition: []
- role: roles/storage.objectAdmin
- ? module.branch-pf-r-sa.google_project_iam_member.project-roles["fast-prod-automation-roles/serviceusage.serviceUsageConsumer"]
- : condition: []
- project: fast-prod-automation
- role: roles/serviceusage.serviceUsageConsumer
- module.branch-pf-r-sa.google_service_account.service_account[0]:
- account_id: fast2-resman-pf-0r
- create_ignore_already_exists: null
- description: null
- disabled: false
- display_name: Terraform project factory main service account (read-only).
- project: fast-prod-automation
- timeouts: null
- module.branch-pf-r-sa.google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
- condition: []
- members: null
- role: roles/iam.serviceAccountTokenCreator
- module.branch-pf-r-sa.google_storage_bucket_iam_member.bucket-roles["test-organizations/123456789012/roles/storageViewer"]:
- bucket: test
- condition: []
- role: organizations/123456789012/roles/storageViewer
- ? module.branch-pf-sa.google_project_iam_member.project-roles["fast-prod-automation-roles/serviceusage.serviceUsageConsumer"]
- : condition: []
- project: fast-prod-automation
- role: roles/serviceusage.serviceUsageConsumer
- module.branch-pf-sa.google_service_account.service_account[0]:
- account_id: fast2-resman-pf-0
- create_ignore_already_exists: null
- description: null
- disabled: false
- display_name: Terraform project factory main service account.
- project: fast-prod-automation
- timeouts: null
- module.branch-pf-sa.google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
- condition: []
- members: null
- role: roles/iam.serviceAccountTokenCreator
- module.branch-pf-sa.google_storage_bucket_iam_member.bucket-roles["test-roles/storage.objectAdmin"]:
- bucket: test
- condition: []
- role: roles/storage.objectAdmin
- module.branch-security-folder.google_folder.folder[0]:
- display_name: Security
- parent: organizations/123456789012
- timeouts: null
- module.branch-security-folder.google_folder_iam_binding.authoritative["roles/editor"]:
- condition: []
- members:
- - group:gcp-security-admins@fast.example.com
- role: roles/editor
- module.branch-security-folder.google_folder_iam_binding.authoritative["roles/logging.admin"]:
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-sec-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/logging.admin
- module.branch-security-folder.google_folder_iam_binding.authoritative["roles/owner"]:
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-sec-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/owner
- module.branch-security-folder.google_folder_iam_binding.authoritative["roles/resourcemanager.folderAdmin"]:
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-sec-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/resourcemanager.folderAdmin
- module.branch-security-folder.google_folder_iam_binding.authoritative["roles/resourcemanager.folderViewer"]:
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-sec-0r@fast-prod-automation.iam.gserviceaccount.com
- role: roles/resourcemanager.folderViewer
- module.branch-security-folder.google_folder_iam_binding.authoritative["roles/resourcemanager.projectCreator"]:
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-sec-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/resourcemanager.projectCreator
- module.branch-security-folder.google_folder_iam_binding.authoritative["roles/viewer"]:
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-sec-0r@fast-prod-automation.iam.gserviceaccount.com
- role: roles/viewer
- module.branch-security-folder.google_folder_iam_binding.bindings["tenant_iam_admin_conditional"]:
- condition:
- - description: Certificate Authority Service delegated grants.
- expression: api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly(['roles/privateca.certificateManager'])
- title: security_sa_delegated_grants
- members:
- - serviceAccount:fast2-prod-resman-sec-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/resourcemanager.folderIamAdmin
- module.branch-security-folder.google_tags_tag_binding.binding["context"]:
- timeouts: null
- module.branch-security-gcs.google_storage_bucket.bucket:
- autoclass: []
- cors: []
- custom_placement_config: []
- default_event_based_hold: null
- enable_object_retention: null
- encryption: []
- force_destroy: false
- labels: null
- lifecycle_rule: []
- location: EU
- logging: []
- name: fast2-prod-resman-sec-0
- project: fast-prod-automation
- requester_pays: null
- retention_policy: []
- storage_class: STANDARD
- timeouts: null
- uniform_bucket_level_access: true
- versioning:
- - enabled: true
- module.branch-security-gcs.google_storage_bucket_iam_binding.authoritative["roles/storage.objectAdmin"]:
- bucket: fast2-prod-resman-sec-0
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-sec-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/storage.objectAdmin
- module.branch-security-gcs.google_storage_bucket_iam_binding.authoritative["roles/storage.objectViewer"]:
- bucket: fast2-prod-resman-sec-0
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-sec-0r@fast-prod-automation.iam.gserviceaccount.com
- role: roles/storage.objectViewer
- ? module.branch-security-r-sa.google_project_iam_member.project-roles["fast-prod-automation-roles/serviceusage.serviceUsageConsumer"]
- : condition: []
- project: fast-prod-automation
- role: roles/serviceusage.serviceUsageConsumer
- module.branch-security-r-sa.google_service_account.service_account[0]:
- account_id: fast2-prod-resman-sec-0r
- create_ignore_already_exists: null
- description: null
- disabled: false
- display_name: Terraform resman security service account (read-only).
- project: fast-prod-automation
- timeouts: null
- module.branch-security-r-sa.google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
- condition: []
- members: null
- role: roles/iam.serviceAccountTokenCreator
- ? module.branch-security-r-sa.google_storage_bucket_iam_member.bucket-roles["test-organizations/123456789012/roles/storageViewer"]
- : bucket: test
- condition: []
- role: organizations/123456789012/roles/storageViewer
- ? module.branch-security-sa.google_project_iam_member.project-roles["fast-prod-automation-roles/serviceusage.serviceUsageConsumer"]
- : condition: []
- project: fast-prod-automation
- role: roles/serviceusage.serviceUsageConsumer
- module.branch-security-sa.google_service_account.service_account[0]:
- account_id: fast2-prod-resman-sec-0
- create_ignore_already_exists: null
- description: null
- disabled: false
- display_name: Terraform resman security service account.
- project: fast-prod-automation
- timeouts: null
- module.branch-security-sa.google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
- condition: []
- members: null
- role: roles/iam.serviceAccountTokenCreator
- module.branch-security-sa.google_storage_bucket_iam_member.bucket-roles["test-roles/storage.objectAdmin"]:
- bucket: test
- condition: []
- role: roles/storage.objectAdmin
- module.checklist-folder-1["Common"].google_folder.folder[0]:
- display_name: Common
- parent: organizations/123456789012
- timeouts: null
- module.checklist-folder-1["Department 1"].google_folder.folder[0]:
- display_name: Department 1
- parent: organizations/123456789012
- timeouts: null
- module.checklist-folder-1["Department 2"].google_folder.folder[0]:
- display_name: Department 2
- parent: organizations/123456789012
- timeouts: null
- module.checklist-folder-1["Department 3"].google_folder.folder[0]:
- display_name: Department 3
- parent: organizations/123456789012
- timeouts: null
- module.checklist-folder-2["Department 1/Team 1"].google_folder.folder[0]:
- display_name: Team 1
- timeouts: null
- module.checklist-folder-2["Department 1/Team 2"].google_folder.folder[0]:
- display_name: Team 2
- timeouts: null
- module.checklist-folder-2["Department 1/Team 3"].google_folder.folder[0]:
- display_name: Team 3
- timeouts: null
- module.checklist-folder-2["Department 1/Team 4"].google_folder.folder[0]:
- display_name: Team 4
- timeouts: null
- module.checklist-folder-2["Department 2/Team 1"].google_folder.folder[0]:
- display_name: Team 1
- timeouts: null
- module.checklist-folder-2["Department 2/Team 2"].google_folder.folder[0]:
- display_name: Team 2
- timeouts: null
- module.checklist-folder-2["Department 2/Team 3"].google_folder.folder[0]:
- display_name: Team 3
- timeouts: null
- module.checklist-folder-2["Department 2/Team 4"].google_folder.folder[0]:
- display_name: Team 4
- timeouts: null
- module.checklist-folder-2["Department 3/Team 1"].google_folder.folder[0]:
- display_name: Team 1
- timeouts: null
- module.checklist-folder-2["Department 3/Team 2"].google_folder.folder[0]:
- display_name: Team 2
- timeouts: null
- module.checklist-folder-2["Department 3/Team 3"].google_folder.folder[0]:
- display_name: Team 3
- timeouts: null
- module.checklist-folder-2["Department 3/Team 4"].google_folder.folder[0]:
- display_name: Team 4
- timeouts: null
- module.checklist-folder-3["Department 1/Team 1/Development"].google_folder.folder[0]:
- display_name: Development
- timeouts: null
- ? module.checklist-folder-3["Department 1/Team 1/Development"].google_folder_iam_binding.authoritative["roles/compute.instanceAdmin.v1"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/compute.instanceAdmin.v1
- ? module.checklist-folder-3["Department 1/Team 1/Development"].google_folder_iam_binding.authoritative["roles/container.admin"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/container.admin
- module.checklist-folder-3["Department 1/Team 1/Non-Production"].google_folder.folder[0]:
- display_name: Non-Production
- timeouts: null
- ? module.checklist-folder-3["Department 1/Team 1/Non-Production"].google_folder_iam_binding.authoritative["roles/compute.instanceAdmin.v1"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/compute.instanceAdmin.v1
- ? module.checklist-folder-3["Department 1/Team 1/Non-Production"].google_folder_iam_binding.authoritative["roles/container.admin"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/container.admin
- module.checklist-folder-3["Department 1/Team 1/Production"].google_folder.folder[0]:
- display_name: Production
- timeouts: null
- module.checklist-folder-3["Department 1/Team 2/Development"].google_folder.folder[0]:
- display_name: Development
- timeouts: null
- ? module.checklist-folder-3["Department 1/Team 2/Development"].google_folder_iam_binding.authoritative["roles/compute.instanceAdmin.v1"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/compute.instanceAdmin.v1
- ? module.checklist-folder-3["Department 1/Team 2/Development"].google_folder_iam_binding.authoritative["roles/container.admin"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/container.admin
- module.checklist-folder-3["Department 1/Team 2/Non-Production"].google_folder.folder[0]:
- display_name: Non-Production
- timeouts: null
- ? module.checklist-folder-3["Department 1/Team 2/Non-Production"].google_folder_iam_binding.authoritative["roles/compute.instanceAdmin.v1"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/compute.instanceAdmin.v1
- ? module.checklist-folder-3["Department 1/Team 2/Non-Production"].google_folder_iam_binding.authoritative["roles/container.admin"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/container.admin
- module.checklist-folder-3["Department 1/Team 2/Production"].google_folder.folder[0]:
- display_name: Production
- timeouts: null
- module.checklist-folder-3["Department 1/Team 3/Development"].google_folder.folder[0]:
- display_name: Development
- timeouts: null
- ? module.checklist-folder-3["Department 1/Team 3/Development"].google_folder_iam_binding.authoritative["roles/compute.instanceAdmin.v1"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/compute.instanceAdmin.v1
- ? module.checklist-folder-3["Department 1/Team 3/Development"].google_folder_iam_binding.authoritative["roles/container.admin"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/container.admin
- module.checklist-folder-3["Department 1/Team 3/Non-Production"].google_folder.folder[0]:
- display_name: Non-Production
- timeouts: null
- ? module.checklist-folder-3["Department 1/Team 3/Non-Production"].google_folder_iam_binding.authoritative["roles/compute.instanceAdmin.v1"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/compute.instanceAdmin.v1
- ? module.checklist-folder-3["Department 1/Team 3/Non-Production"].google_folder_iam_binding.authoritative["roles/container.admin"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/container.admin
- module.checklist-folder-3["Department 1/Team 3/Production"].google_folder.folder[0]:
- display_name: Production
- timeouts: null
- module.checklist-folder-3["Department 1/Team 4/Development"].google_folder.folder[0]:
- display_name: Development
- timeouts: null
- ? module.checklist-folder-3["Department 1/Team 4/Development"].google_folder_iam_binding.authoritative["roles/compute.instanceAdmin.v1"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/compute.instanceAdmin.v1
- ? module.checklist-folder-3["Department 1/Team 4/Development"].google_folder_iam_binding.authoritative["roles/container.admin"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/container.admin
- module.checklist-folder-3["Department 1/Team 4/Non-Production"].google_folder.folder[0]:
- display_name: Non-Production
- timeouts: null
- ? module.checklist-folder-3["Department 1/Team 4/Non-Production"].google_folder_iam_binding.authoritative["roles/compute.instanceAdmin.v1"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/compute.instanceAdmin.v1
- ? module.checklist-folder-3["Department 1/Team 4/Non-Production"].google_folder_iam_binding.authoritative["roles/container.admin"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/container.admin
- module.checklist-folder-3["Department 1/Team 4/Production"].google_folder.folder[0]:
- display_name: Production
- timeouts: null
- module.checklist-folder-3["Department 2/Team 1/Development"].google_folder.folder[0]:
- display_name: Development
- timeouts: null
- ? module.checklist-folder-3["Department 2/Team 1/Development"].google_folder_iam_binding.authoritative["roles/compute.instanceAdmin.v1"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/compute.instanceAdmin.v1
- ? module.checklist-folder-3["Department 2/Team 1/Development"].google_folder_iam_binding.authoritative["roles/container.admin"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/container.admin
- module.checklist-folder-3["Department 2/Team 1/Non-Production"].google_folder.folder[0]:
- display_name: Non-Production
- timeouts: null
- ? module.checklist-folder-3["Department 2/Team 1/Non-Production"].google_folder_iam_binding.authoritative["roles/compute.instanceAdmin.v1"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/compute.instanceAdmin.v1
- ? module.checklist-folder-3["Department 2/Team 1/Non-Production"].google_folder_iam_binding.authoritative["roles/container.admin"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/container.admin
- module.checklist-folder-3["Department 2/Team 1/Production"].google_folder.folder[0]:
- display_name: Production
- timeouts: null
- module.checklist-folder-3["Department 2/Team 2/Development"].google_folder.folder[0]:
- display_name: Development
- timeouts: null
- ? module.checklist-folder-3["Department 2/Team 2/Development"].google_folder_iam_binding.authoritative["roles/compute.instanceAdmin.v1"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/compute.instanceAdmin.v1
- ? module.checklist-folder-3["Department 2/Team 2/Development"].google_folder_iam_binding.authoritative["roles/container.admin"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/container.admin
- module.checklist-folder-3["Department 2/Team 2/Non-Production"].google_folder.folder[0]:
- display_name: Non-Production
- timeouts: null
- ? module.checklist-folder-3["Department 2/Team 2/Non-Production"].google_folder_iam_binding.authoritative["roles/compute.instanceAdmin.v1"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/compute.instanceAdmin.v1
- ? module.checklist-folder-3["Department 2/Team 2/Non-Production"].google_folder_iam_binding.authoritative["roles/container.admin"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/container.admin
- module.checklist-folder-3["Department 2/Team 2/Production"].google_folder.folder[0]:
- display_name: Production
- timeouts: null
- module.checklist-folder-3["Department 2/Team 3/Development"].google_folder.folder[0]:
- display_name: Development
- timeouts: null
- ? module.checklist-folder-3["Department 2/Team 3/Development"].google_folder_iam_binding.authoritative["roles/compute.instanceAdmin.v1"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/compute.instanceAdmin.v1
- ? module.checklist-folder-3["Department 2/Team 3/Development"].google_folder_iam_binding.authoritative["roles/container.admin"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/container.admin
- module.checklist-folder-3["Department 2/Team 3/Non-Production"].google_folder.folder[0]:
- display_name: Non-Production
- timeouts: null
- ? module.checklist-folder-3["Department 2/Team 3/Non-Production"].google_folder_iam_binding.authoritative["roles/compute.instanceAdmin.v1"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/compute.instanceAdmin.v1
- ? module.checklist-folder-3["Department 2/Team 3/Non-Production"].google_folder_iam_binding.authoritative["roles/container.admin"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/container.admin
- module.checklist-folder-3["Department 2/Team 3/Production"].google_folder.folder[0]:
- display_name: Production
- timeouts: null
- module.checklist-folder-3["Department 2/Team 4/Development"].google_folder.folder[0]:
- display_name: Development
- timeouts: null
- ? module.checklist-folder-3["Department 2/Team 4/Development"].google_folder_iam_binding.authoritative["roles/compute.instanceAdmin.v1"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/compute.instanceAdmin.v1
- ? module.checklist-folder-3["Department 2/Team 4/Development"].google_folder_iam_binding.authoritative["roles/container.admin"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/container.admin
- module.checklist-folder-3["Department 2/Team 4/Non-Production"].google_folder.folder[0]:
- display_name: Non-Production
- timeouts: null
- ? module.checklist-folder-3["Department 2/Team 4/Non-Production"].google_folder_iam_binding.authoritative["roles/compute.instanceAdmin.v1"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/compute.instanceAdmin.v1
- ? module.checklist-folder-3["Department 2/Team 4/Non-Production"].google_folder_iam_binding.authoritative["roles/container.admin"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/container.admin
- module.checklist-folder-3["Department 2/Team 4/Production"].google_folder.folder[0]:
- display_name: Production
- timeouts: null
- module.checklist-folder-3["Department 3/Team 1/Development"].google_folder.folder[0]:
- display_name: Development
- timeouts: null
- ? module.checklist-folder-3["Department 3/Team 1/Development"].google_folder_iam_binding.authoritative["roles/compute.instanceAdmin.v1"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/compute.instanceAdmin.v1
- ? module.checklist-folder-3["Department 3/Team 1/Development"].google_folder_iam_binding.authoritative["roles/container.admin"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/container.admin
- module.checklist-folder-3["Department 3/Team 1/Non-Production"].google_folder.folder[0]:
- display_name: Non-Production
- timeouts: null
- ? module.checklist-folder-3["Department 3/Team 1/Non-Production"].google_folder_iam_binding.authoritative["roles/compute.instanceAdmin.v1"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/compute.instanceAdmin.v1
- ? module.checklist-folder-3["Department 3/Team 1/Non-Production"].google_folder_iam_binding.authoritative["roles/container.admin"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/container.admin
- module.checklist-folder-3["Department 3/Team 1/Production"].google_folder.folder[0]:
- display_name: Production
- timeouts: null
- module.checklist-folder-3["Department 3/Team 2/Development"].google_folder.folder[0]:
- display_name: Development
- timeouts: null
- ? module.checklist-folder-3["Department 3/Team 2/Development"].google_folder_iam_binding.authoritative["roles/compute.instanceAdmin.v1"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/compute.instanceAdmin.v1
- ? module.checklist-folder-3["Department 3/Team 2/Development"].google_folder_iam_binding.authoritative["roles/container.admin"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/container.admin
- module.checklist-folder-3["Department 3/Team 2/Non-Production"].google_folder.folder[0]:
- display_name: Non-Production
- timeouts: null
- ? module.checklist-folder-3["Department 3/Team 2/Non-Production"].google_folder_iam_binding.authoritative["roles/compute.instanceAdmin.v1"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/compute.instanceAdmin.v1
- ? module.checklist-folder-3["Department 3/Team 2/Non-Production"].google_folder_iam_binding.authoritative["roles/container.admin"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/container.admin
- module.checklist-folder-3["Department 3/Team 2/Production"].google_folder.folder[0]:
- display_name: Production
- timeouts: null
- module.checklist-folder-3["Department 3/Team 3/Development"].google_folder.folder[0]:
- display_name: Development
- timeouts: null
- ? module.checklist-folder-3["Department 3/Team 3/Development"].google_folder_iam_binding.authoritative["roles/compute.instanceAdmin.v1"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/compute.instanceAdmin.v1
- ? module.checklist-folder-3["Department 3/Team 3/Development"].google_folder_iam_binding.authoritative["roles/container.admin"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/container.admin
- module.checklist-folder-3["Department 3/Team 3/Non-Production"].google_folder.folder[0]:
- display_name: Non-Production
- timeouts: null
- ? module.checklist-folder-3["Department 3/Team 3/Non-Production"].google_folder_iam_binding.authoritative["roles/compute.instanceAdmin.v1"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/compute.instanceAdmin.v1
- ? module.checklist-folder-3["Department 3/Team 3/Non-Production"].google_folder_iam_binding.authoritative["roles/container.admin"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/container.admin
- module.checklist-folder-3["Department 3/Team 3/Production"].google_folder.folder[0]:
- display_name: Production
- timeouts: null
- module.checklist-folder-3["Department 3/Team 4/Development"].google_folder.folder[0]:
- display_name: Development
- timeouts: null
- ? module.checklist-folder-3["Department 3/Team 4/Development"].google_folder_iam_binding.authoritative["roles/compute.instanceAdmin.v1"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/compute.instanceAdmin.v1
- ? module.checklist-folder-3["Department 3/Team 4/Development"].google_folder_iam_binding.authoritative["roles/container.admin"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/container.admin
- module.checklist-folder-3["Department 3/Team 4/Non-Production"].google_folder.folder[0]:
- display_name: Non-Production
- timeouts: null
- ? module.checklist-folder-3["Department 3/Team 4/Non-Production"].google_folder_iam_binding.authoritative["roles/compute.instanceAdmin.v1"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/compute.instanceAdmin.v1
- ? module.checklist-folder-3["Department 3/Team 4/Non-Production"].google_folder_iam_binding.authoritative["roles/container.admin"]
- : condition: []
- members:
- - group:gcp-developers@fast.example.com
- role: roles/container.admin
- module.checklist-folder-3["Department 3/Team 4/Production"].google_folder.folder[0]:
- display_name: Production
- timeouts: null
- module.organization[0].google_organization_iam_member.bindings["sa_net_billing"]:
- condition: []
- member: serviceAccount:fast2-prod-resman-net-0@fast-prod-automation.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/billing.user
- module.organization[0].google_organization_iam_member.bindings["sa_net_fw_policy_admin"]:
- condition: []
- member: serviceAccount:fast2-prod-resman-net-0@fast-prod-automation.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/compute.orgFirewallPolicyAdmin
- module.organization[0].google_organization_iam_member.bindings["sa_net_xpn_admin"]:
- condition: []
- member: serviceAccount:fast2-prod-resman-net-0@fast-prod-automation.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/compute.xpnAdmin
- module.organization[0].google_organization_iam_member.bindings["sa_pf_billing"]:
- condition: []
- member: serviceAccount:fast2-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/billing.user
- module.organization[0].google_organization_iam_member.bindings["sa_pf_conditional_org_policy"]:
- condition:
- - description: Org policy tag scoped grant for project factory main.
- expression: 'resource.matchTag(''123456789012/context'', ''project-factory'')
-
- '
- title: org_policy_tag_pf_scoped
- member: serviceAccount:fast2-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/orgpolicy.policyAdmin
- module.organization[0].google_organization_iam_member.bindings["sa_pf_costs_manager"]:
- condition: []
- member: serviceAccount:fast2-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/billing.costsManager
- module.organization[0].google_organization_iam_member.bindings["sa_pf_dev_billing"]:
- condition: []
- member: serviceAccount:fast2-dev-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/billing.user
- module.organization[0].google_organization_iam_member.bindings["sa_pf_dev_conditional_org_policy"]:
- condition:
- - description: Org policy tag scoped grant for project factory dev.
- expression: 'resource.matchTag(''123456789012/context'', ''project-factory'')
-
- &&
-
- resource.matchTag(''123456789012/environment'', ''development'')
-
- '
- title: org_policy_tag_pf_scoped_dev
- member: serviceAccount:fast2-dev-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/orgpolicy.policyAdmin
- module.organization[0].google_organization_iam_member.bindings["sa_pf_dev_costs_manager"]:
- condition: []
- member: serviceAccount:fast2-dev-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/billing.costsManager
- module.organization[0].google_organization_iam_member.bindings["sa_pf_prod_billing"]:
- condition: []
- member: serviceAccount:fast2-prod-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/billing.user
- module.organization[0].google_organization_iam_member.bindings["sa_pf_prod_conditional_org_policy"]:
- condition:
- - description: Org policy tag scoped grant for project factory prod.
- expression: 'resource.matchTag(''123456789012/context'', ''project-factory'')
-
- &&
-
- resource.matchTag(''123456789012/environment'', ''production'')
-
- '
- title: org_policy_tag_pf_scoped_prod
- member: serviceAccount:fast2-prod-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/orgpolicy.policyAdmin
- module.organization[0].google_organization_iam_member.bindings["sa_pf_prod_costs_manager"]:
- condition: []
- member: serviceAccount:fast2-prod-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/billing.costsManager
- module.organization[0].google_organization_iam_member.bindings["sa_sec_asset_viewer"]:
- condition: []
- member: serviceAccount:fast2-prod-resman-sec-0@fast-prod-automation.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/cloudasset.viewer
- module.organization[0].google_organization_iam_member.bindings["sa_sec_billing"]:
- condition: []
- member: serviceAccount:fast2-prod-resman-sec-0@fast-prod-automation.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/billing.user
- module.organization[0].google_tags_tag_key.default["context"]:
- description: Resource management context.
- parent: organizations/123456789012
- purpose: null
- purpose_data: null
- short_name: context
- timeouts: null
- module.organization[0].google_tags_tag_key.default["environment"]:
- description: Environment definition.
- parent: organizations/123456789012
- purpose: null
- purpose_data: null
- short_name: environment
- timeouts: null
- module.organization[0].google_tags_tag_value.default["context/data"]:
- description: Managed by the Terraform organization module.
- short_name: data
- timeouts: null
- module.organization[0].google_tags_tag_value.default["context/gcve"]:
- description: Managed by the Terraform organization module.
- short_name: gcve
- timeouts: null
- module.organization[0].google_tags_tag_value.default["context/gke"]:
- description: Managed by the Terraform organization module.
- short_name: gke
- timeouts: null
- module.organization[0].google_tags_tag_value.default["context/networking"]:
- description: Managed by the Terraform organization module.
- short_name: networking
- timeouts: null
- module.organization[0].google_tags_tag_value.default["context/project-factory"]:
- description: Managed by the Terraform organization module.
- short_name: project-factory
- timeouts: null
- module.organization[0].google_tags_tag_value.default["context/sandbox"]:
- description: Managed by the Terraform organization module.
- short_name: sandbox
- timeouts: null
- module.organization[0].google_tags_tag_value.default["context/security"]:
- description: Managed by the Terraform organization module.
- short_name: security
- timeouts: null
- module.organization[0].google_tags_tag_value.default["environment/development"]:
- description: Managed by the Terraform organization module.
- short_name: development
- timeouts: null
- module.organization[0].google_tags_tag_value.default["environment/production"]:
- description: Managed by the Terraform organization module.
- short_name: production
- timeouts: null
- module.organization[0].google_tags_tag_value_iam_binding.bindings["environment/development:pf"]:
- condition: []
- members:
- - serviceAccount:fast2-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/resourcemanager.tagUser
- module.organization[0].google_tags_tag_value_iam_binding.bindings["environment/production:pf"]:
- condition: []
- members:
- - serviceAccount:fast2-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/resourcemanager.tagUser
- module.top-level-folder["teams"].google_folder.folder[0]:
- display_name: Teams
- parent: organizations/123456789012
- timeouts: null
- ? module.top-level-folder["teams"].google_folder_iam_binding.authoritative["organizations/123456789012/roles/xpnServiceAdmin"]
- : condition: []
- members:
- - serviceAccount:fast2-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- role: organizations/123456789012/roles/xpnServiceAdmin
- module.top-level-folder["teams"].google_folder_iam_binding.authoritative["roles/owner"]:
- condition: []
- members:
- - serviceAccount:fast2-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/owner
- module.top-level-folder["teams"].google_folder_iam_binding.authoritative["roles/resourcemanager.folderAdmin"]:
- condition: []
- members:
- - serviceAccount:fast2-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/resourcemanager.folderAdmin
- module.top-level-folder["teams"].google_folder_iam_binding.authoritative["roles/resourcemanager.projectCreator"]:
- condition: []
- members:
- - serviceAccount:fast2-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/resourcemanager.projectCreator
- module.top-level-folder["teams"].google_folder_iam_binding.authoritative["roles/resourcemanager.tagUser"]:
- condition: []
- members:
- - serviceAccount:fast2-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/resourcemanager.tagUser
- module.top-level-folder["teams"].google_tags_tag_binding.binding["context"]:
- timeouts: null
-
-counts:
- google_folder: 57
- google_folder_iam_binding: 75
- google_organization_iam_member: 14
- google_project_iam_member: 10
- google_service_account: 10
- google_service_account_iam_binding: 10
- google_storage_bucket: 5
- google_storage_bucket_iam_binding: 10
- google_storage_bucket_iam_member: 10
- google_storage_bucket_object: 11
- google_tags_tag_binding: 5
- google_tags_tag_key: 2
- google_tags_tag_value: 9
- google_tags_tag_value_iam_binding: 2
- modules: 73
- resources: 230
diff --git a/tests/fast/stages/s1_resman/simple.tfvars b/tests/fast/stages/s1_resman/simple.tfvars
index 18c402bfe..ce8f7894f 100644
--- a/tests/fast/stages/s1_resman/simple.tfvars
+++ b/tests/fast/stages/s1_resman/simple.tfvars
@@ -1,28 +1,8 @@
-automation = {
- cicd_backends = null
- federated_identity_pool = null
- federated_identity_providers = null
- project_id = "fast-prod-automation"
- project_number = 123456
- outputs_bucket = "test"
- service_accounts = {
- resman-r = "ldj-prod-resman-0r@fast2-prod-iac-core-0.iam.gserviceaccount.com"
- }
-}
+# globals
+
billing_account = {
id = "000000-111111-222222"
}
-custom_roles = {
- # organization_iam_admin = "organizations/123456789012/roles/organizationIamAdmin",
- gcve_network_admin = "organizations/123456789012/roles/gcveNetworkAdmin"
- network_firewall_policies_admin = "organizations/123456789012/roles/networkFirewallPoliciesAdmin"
- network_firewall_policies_viewer = "organizations/123456789012/roles/networkFirewallPoliciesViewer"
- ngfw_enterprise_admin = "organizations/123456789012/roles/ngfwEnterpriseAdmin"
- ngfw_enterprise_viewer = "organizations/123456789012/roles/ngfwEnterpriseViewer"
- 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",
gcp-devops = "gcp-devops",
@@ -31,46 +11,134 @@ groups = {
gcp-security-admins = "gcp-security-admins",
gcp-support = "gcp-support"
}
-logging = {
- project_id = "fast-prod-log-audit-0"
-}
organization = {
domain = "fast.example.com"
id = 123456789012
customer_id = "C00000000"
}
prefix = "fast2"
-folder_iam = {
- data_platform = {
- "roles/owner" = ["user:extra-owner@fast.example.com"]
- "roles/browser" = ["user:extra-browser@fast.example.com"]
- }
- gcve = {
- "roles/owner" = ["user:extra-owner@fast.example.com"]
- "roles/browser" = ["user:extra-browser@fast.example.com"]
- }
- gke = {
- "roles/owner" = ["user:extra-owner@fast.example.com"]
- "roles/browser" = ["user:extra-browser@fast.example.com"]
- }
- sandbox = {
- "roles/owner" = ["user:extra-owner@fast.example.com"]
- "roles/browser" = ["user:extra-browser@fast.example.com"]
- }
- security = {
- "roles/owner" = ["user:extra-owner@fast.example.com"]
- "roles/browser" = ["user:extra-browser@fast.example.com"]
- }
- network = {
- "roles/owner" = ["user:extra-owner@fast.example.com"]
- "roles/browser" = ["user:extra-browser@fast.example.com"]
- }
- teams = {
- "roles/owner" = ["user:extra-owner@fast.example.com"]
- "roles/browser" = ["user:extra-browser@fast.example.com"]
- }
- tenants = {
- "roles/owner" = ["user:extra-owner@fast.example.com"]
- "roles/browser" = ["user:extra-browser@fast.example.com"]
+
+# stage 0
+
+automation = {
+ federated_identity_pool = "projects/1234567890/locations/global/workloadIdentityPools/ldj-bootstrap"
+ federated_identity_providers = {
+ gh-test = {
+ audiences = [
+ "https://iam.googleapis.com/projects/1234567890/locations/global/workloadIdentityPools/ldj-bootstrap/providers/ldj-bootstrap-github-ludomagno"
+ ],
+ issuer = "github",
+ issuer_uri = "https://token.actions.githubusercontent.com"
+ name = "projects/1234567890/locations/global/workloadIdentityPools/ldj-bootstrap/providers/ldj-bootstrap-github-ludomagno"
+ principal_branch = "principalSet://iam.googleapis.com/%s/attribute.fast_sub/repo:%s:ref:refs/heads/%s"
+ principal_repo = "principalSet://iam.googleapis.com/%s/attribute.repository/%s"
+ }
+ gl-test = {
+ audiences = [
+ "https://iam.googleapis.com/projects/1234567890/locations/global/workloadIdentityPools/ldj-bootstrap/providers/ldj-bootstrap-gitlab-ludomagno"
+ ]
+ issuer = "gitlab"
+ issuer_uri = "https://gitlab.com"
+ name = "projects/1234567890/locations/global/workloadIdentityPools/ldj-bootstrap/providers/ldj-bootstrap-gitlab-ludomagno"
+ principal_branch = "principalSet://iam.googleapis.com/%s/attribute.sub/project_path:%s:ref_type:branch:ref:%s"
+ principal_repo = "principalSet://iam.googleapis.com/%s/attribute.repository/%s"
+ }
+ },
+ outputs_bucket = "fast2-prod-iac-core-outputs"
+ project_id = "fast2-prod-automation"
+ project_number = 123456
+ service_accounts = {
+ resman-r = "fast2-prod-resman-0r@fast2-prod-iac-core-0.iam.gserviceaccount.com"
+ }
+}
+custom_roles = {
+ # organization_iam_admin = "organizations/123456789012/roles/organizationIamAdmin",
+ billing_viewer = "organizations/123456789012/roles/billingViewer"
+ gcve_network_admin = "organizations/123456789012/roles/gcveNetworkAdmin"
+ gcve_network_viewer = "organizations/123456789012/roles/gcveNetworkViewer"
+ network_firewall_policies_admin = "organizations/123456789012/roles/networkFirewallPoliciesAdmin"
+ ngfw_enterprise_admin = "organizations/123456789012/roles/ngfwEnterpriseAdmin"
+ ngfw_enterprise_viewer = "organizations/123456789012/roles/ngfwEnterpriseViewer"
+ organization_admin_viewer = "organizations/123456789012/roles/organizationAdminViewer"
+ project_iam_viewer = "organizations/123456789012/roles/projectIamViewer"
+ service_project_network_admin = "organizations/123456789012/roles/xpnServiceAdmin"
+ storage_viewer = "organizations/123456789012/roles/storageViewer"
+}
+environments = {
+ dev = {
+ is_default = false
+ name = "Development"
+ tag_name = "development"
+ }
+ prod = {
+ is_default = true
+ name = "Production"
+ tag_name = "production"
+ }
+}
+logging = {
+ project_id = "fast-prod-log-audit-0"
+}
+
+# stage variables
+
+fast_stage_2 = {
+ networking = {
+ cicd_config = {
+ identity_provider = "gh-test"
+ repository = {
+ branch = "main"
+ name = "test/00-networking"
+ type = "github"
+ }
+ }
+ }
+ security = {
+ cicd_config = {
+ identity_provider = "gl-test"
+ repository = {
+ name = "test/00-security"
+ type = "gitlab"
+ }
+ }
+ }
+ network_security = {
+ enabled = true
+ }
+}
+tags = {
+ context = {
+ values = {
+ data-platform = {}
+ gcve = {}
+ gke = {}
+ nsec = {}
+ sandbox = {}
+ }
+ }
+ environment = {
+ values = {
+ development = {
+ iam = {
+ "roles/resourcemanager.tagUser" = ["project-factory-dev"]
+ "roles/resourcemanager.tagViewer" = ["project-factory-dev-r"]
+ }
+ }
+ production = {
+ iam = {
+ "roles/resourcemanager.tagUser" = ["project-factory-prod"]
+ "roles/resourcemanager.tagViewer" = ["project-factory-prod-r"]
+ }
+ }
+ }
+ }
+}
+top_level_folders = {
+ tenants = {
+ name = "Tenants"
+ automation = {
+ enable = false
+ }
+ iam_by_principals = {}
}
}
diff --git a/tests/fast/stages/s1_resman/simple.yaml b/tests/fast/stages/s1_resman/simple.yaml
index 8c019e5d0..5fe25986c 100644
--- a/tests/fast/stages/s1_resman/simple.yaml
+++ b/tests/fast/stages/s1_resman/simple.yaml
@@ -13,247 +13,172 @@
# limitations under the License.
values:
+ google_storage_bucket_object.providers["1-resman-folder-sandbox"]:
+ bucket: fast2-prod-iac-core-outputs
+ name: providers/1-resman-folder-sandbox-providers.tf
+ google_storage_bucket_object.providers["1-resman-folder-tenants"]:
+ bucket: fast2-prod-iac-core-outputs
+ name: providers/1-resman-folder-tenants-providers.tf
+ google_storage_bucket_object.providers["2-network-security"]:
+ bucket: fast2-prod-iac-core-outputs
+ name: providers/2-network-security-providers.tf
+ google_storage_bucket_object.providers["2-network-security-r"]:
+ bucket: fast2-prod-iac-core-outputs
+ name: providers/2-network-security-r-providers.tf
google_storage_bucket_object.providers["2-networking"]:
- bucket: test
- cache_control: null
- content_disposition: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
+ bucket: fast2-prod-iac-core-outputs
name: providers/2-networking-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
google_storage_bucket_object.providers["2-networking-r"]:
- bucket: test
- cache_control: null
- content_disposition: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
+ bucket: fast2-prod-iac-core-outputs
name: providers/2-networking-r-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
google_storage_bucket_object.providers["2-project-factory"]:
- bucket: test
- cache_control: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
+ bucket: fast2-prod-iac-core-outputs
name: providers/2-project-factory-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
- google_storage_bucket_object.providers["2-project-factory-dev"]:
- bucket: test
- cache_control: null
- content_disposition: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
- name: providers/2-project-factory-dev-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
- google_storage_bucket_object.providers["2-project-factory-dev-r"]:
- bucket: test
- cache_control: null
- content_disposition: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
- name: providers/2-project-factory-dev-r-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
- google_storage_bucket_object.providers["2-project-factory-prod"]:
- bucket: test
- cache_control: null
- content_disposition: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
- name: providers/2-project-factory-prod-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
- google_storage_bucket_object.providers["2-project-factory-prod-r"]:
- bucket: test
- cache_control: null
- content_disposition: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
- name: providers/2-project-factory-prod-r-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
google_storage_bucket_object.providers["2-project-factory-r"]:
- bucket: test
- cache_control: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
+ bucket: fast2-prod-iac-core-outputs
name: providers/2-project-factory-r-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
google_storage_bucket_object.providers["2-security"]:
- bucket: test
- cache_control: null
- content_disposition: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
+ bucket: fast2-prod-iac-core-outputs
name: providers/2-security-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
google_storage_bucket_object.providers["2-security-r"]:
- bucket: test
- cache_control: null
- content_disposition: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
+ bucket: fast2-prod-iac-core-outputs
name: providers/2-security-r-providers.tf
- retention: []
- source: null
- temporary_hold: null
- timeouts: null
+ google_storage_bucket_object.providers["3-gcve-dev"]:
+ bucket: fast2-prod-iac-core-outputs
+ name: providers/3-gcve-dev-providers.tf
+ google_storage_bucket_object.providers["3-gcve-dev-r"]:
+ bucket: fast2-prod-iac-core-outputs
+ name: providers/3-gcve-dev-r-providers.tf
+ google_storage_bucket_object.providers["3-gcve-prod"]:
+ bucket: fast2-prod-iac-core-outputs
+ name: providers/3-gcve-prod-providers.tf
+ google_storage_bucket_object.providers["3-gcve-prod-r"]:
+ bucket: fast2-prod-iac-core-outputs
+ name: providers/3-gcve-prod-r-providers.tf
+ google_storage_bucket_object.providers["3-gke-dev"]:
+ bucket: fast2-prod-iac-core-outputs
+ name: providers/3-gke-dev-providers.tf
+ google_storage_bucket_object.providers["3-gke-dev-r"]:
+ bucket: fast2-prod-iac-core-outputs
+ name: providers/3-gke-dev-r-providers.tf
+ google_storage_bucket_object.providers["3-gke-prod"]:
+ bucket: fast2-prod-iac-core-outputs
+ name: providers/3-gke-prod-providers.tf
+ google_storage_bucket_object.providers["3-gke-prod-r"]:
+ bucket: fast2-prod-iac-core-outputs
+ name: providers/3-gke-prod-r-providers.tf
+ google_storage_bucket_object.providers["3-project-factory-dev"]:
+ bucket: fast2-prod-iac-core-outputs
+ name: providers/3-project-factory-dev-providers.tf
+ google_storage_bucket_object.providers["3-project-factory-dev-r"]:
+ bucket: fast2-prod-iac-core-outputs
+ name: providers/3-project-factory-dev-r-providers.tf
+ google_storage_bucket_object.providers["3-project-factory-prod"]:
+ bucket: fast2-prod-iac-core-outputs
+ name: providers/3-project-factory-prod-providers.tf
+ google_storage_bucket_object.providers["3-project-factory-prod-r"]:
+ bucket: fast2-prod-iac-core-outputs
+ name: providers/3-project-factory-prod-r-providers.tf
google_storage_bucket_object.tfvars:
- bucket: test
- cache_control: null
- content_disposition: null
- content_encoding: null
- content_language: null
- customer_encryption: []
- detect_md5hash: different hash
- event_based_hold: null
- metadata: null
+ bucket: fast2-prod-iac-core-outputs
name: tfvars/1-resman.auto.tfvars.json
- retention: []
- source: null
- temporary_hold: null
+ google_storage_bucket_object.workflows["networking"]:
+ bucket: fast2-prod-iac-core-outputs
+ name: workflows/networking-workflow.yaml
+ google_storage_bucket_object.workflows["security"]:
+ bucket: fast2-prod-iac-core-outputs
+ name: workflows/security-workflow.yaml
+ module.cicd-sa-ro["networking"].google_project_iam_member.project-roles["fast2-prod-automation-roles/logging.logWriter"]:
+ condition: []
+ project: fast2-prod-automation
+ role: roles/logging.logWriter
+ module.cicd-sa-ro["networking"].google_service_account.service_account[0]:
+ account_id: fast2-prod-resman-net-1r
+ create_ignore_already_exists: null
+ description: null
+ disabled: false
+ display_name: CI/CD 2-net prod service account (read-only).
+ project: fast2-prod-automation
timeouts: null
- module.branch-network-dev-folder.google_folder.folder[0]:
- display_name: Development
+ module.cicd-sa-ro["networking"].google_service_account_iam_binding.authoritative["roles/iam.workloadIdentityUser"]:
+ condition: []
+ members:
+ - principalSet://iam.googleapis.com/projects/1234567890/locations/global/workloadIdentityPools/ldj-bootstrap/attribute.repository/test/00-networking
+ role: roles/iam.workloadIdentityUser
+ ? module.cicd-sa-ro["networking"].google_storage_bucket_iam_member.bucket-roles["fast2-prod-iac-core-outputs-roles/storage.objectViewer"]
+ : bucket: fast2-prod-iac-core-outputs
+ condition: []
+ role: roles/storage.objectViewer
+ module.cicd-sa-ro["security"].google_project_iam_member.project-roles["fast2-prod-automation-roles/logging.logWriter"]:
+ condition: []
+ project: fast2-prod-automation
+ role: roles/logging.logWriter
+ module.cicd-sa-ro["security"].google_service_account.service_account[0]:
+ account_id: fast2-prod-resman-sec-1r
+ create_ignore_already_exists: null
+ description: null
+ disabled: false
+ display_name: CI/CD 2-sec prod service account (read-only).
+ project: fast2-prod-automation
timeouts: null
- ? module.branch-network-dev-folder.google_folder_iam_binding.authoritative["organizations/123456789012/roles/gcveNetworkAdmin"]
- : condition: []
- members: null
- role: organizations/123456789012/roles/gcveNetworkAdmin
- ? module.branch-network-dev-folder.google_folder_iam_binding.authoritative["organizations/123456789012/roles/xpnServiceAdmin"]
- : condition: []
- members:
- - serviceAccount:fast2-dev-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- - serviceAccount:fast2-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- role: organizations/123456789012/roles/xpnServiceAdmin
- module.branch-network-dev-folder.google_folder_iam_binding.authoritative["roles/compute.networkViewer"]:
+ module.cicd-sa-ro["security"].google_service_account_iam_binding.authoritative["roles/iam.workloadIdentityUser"]:
condition: []
members:
- - serviceAccount:fast2-dev-resman-pf-0r@fast-prod-automation.iam.gserviceaccount.com
- - serviceAccount:fast2-resman-pf-0r@fast-prod-automation.iam.gserviceaccount.com
- role: roles/compute.networkViewer
- module.branch-network-dev-folder.google_tags_tag_binding.binding["environment"]:
+ - principalSet://iam.googleapis.com/projects/1234567890/locations/global/workloadIdentityPools/ldj-bootstrap/attribute.repository/test/00-security
+ role: roles/iam.workloadIdentityUser
+ ? module.cicd-sa-ro["security"].google_storage_bucket_iam_member.bucket-roles["fast2-prod-iac-core-outputs-roles/storage.objectViewer"]
+ : bucket: fast2-prod-iac-core-outputs
+ condition: []
+ role: roles/storage.objectViewer
+ module.cicd-sa-rw["networking"].google_project_iam_member.project-roles["fast2-prod-automation-roles/logging.logWriter"]:
+ condition: []
+ project: fast2-prod-automation
+ role: roles/logging.logWriter
+ module.cicd-sa-rw["networking"].google_service_account.service_account[0]:
+ account_id: fast2-prod-resman-net-1
+ create_ignore_already_exists: null
+ description: null
+ disabled: false
+ display_name: CI/CD 2-net prod service account.
+ project: fast2-prod-automation
timeouts: null
- module.branch-network-folder.google_folder.folder[0]:
- display_name: Networking
- parent: organizations/123456789012
+ module.cicd-sa-rw["networking"].google_service_account_iam_binding.authoritative["roles/iam.workloadIdentityUser"]:
+ condition: []
+ members:
+ - principalSet://iam.googleapis.com/projects/1234567890/locations/global/workloadIdentityPools/ldj-bootstrap/attribute.fast_sub/repo:test/00-networking:ref:refs/heads/main
+ role: roles/iam.workloadIdentityUser
+ ? module.cicd-sa-rw["networking"].google_storage_bucket_iam_member.bucket-roles["fast2-prod-iac-core-outputs-roles/storage.objectViewer"]
+ : bucket: fast2-prod-iac-core-outputs
+ condition: []
+ role: roles/storage.objectViewer
+ module.cicd-sa-rw["security"].google_project_iam_member.project-roles["fast2-prod-automation-roles/logging.logWriter"]:
+ condition: []
+ project: fast2-prod-automation
+ role: roles/logging.logWriter
+ module.cicd-sa-rw["security"].google_service_account.service_account[0]:
+ account_id: fast2-prod-resman-sec-1
+ create_ignore_already_exists: null
+ description: null
+ disabled: false
+ display_name: CI/CD 2-sec prod service account.
+ project: fast2-prod-automation
timeouts: null
- module.branch-network-folder.google_folder_iam_binding.authoritative["roles/browser"]:
+ module.cicd-sa-rw["security"].google_service_account_iam_binding.authoritative["roles/iam.workloadIdentityUser"]:
condition: []
members:
- - user:extra-browser@fast.example.com
- role: roles/browser
- module.branch-network-folder.google_folder_iam_binding.authoritative["roles/compute.xpnAdmin"]:
+ - principalSet://iam.googleapis.com/projects/1234567890/locations/global/workloadIdentityPools/ldj-bootstrap/attribute.repository/test/00-security
+ role: roles/iam.workloadIdentityUser
+ ? module.cicd-sa-rw["security"].google_storage_bucket_iam_member.bucket-roles["fast2-prod-iac-core-outputs-roles/storage.objectViewer"]
+ : bucket: fast2-prod-iac-core-outputs
condition: []
- members:
- - serviceAccount:fast2-prod-resman-net-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/compute.xpnAdmin
- module.branch-network-folder.google_folder_iam_binding.authoritative["roles/editor"]:
- condition: []
- members:
- - group:gcp-vpc-network-admins@fast.example.com
- role: roles/editor
- module.branch-network-folder.google_folder_iam_binding.authoritative["roles/logging.admin"]:
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-net-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/logging.admin
- module.branch-network-folder.google_folder_iam_binding.authoritative["roles/owner"]:
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-net-0@fast-prod-automation.iam.gserviceaccount.com
- - user:extra-owner@fast.example.com
- role: roles/owner
- module.branch-network-folder.google_folder_iam_binding.authoritative["roles/resourcemanager.folderAdmin"]:
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-net-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/resourcemanager.folderAdmin
- module.branch-network-folder.google_folder_iam_binding.authoritative["roles/resourcemanager.folderViewer"]:
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-net-0r@fast-prod-automation.iam.gserviceaccount.com
- role: roles/resourcemanager.folderViewer
- module.branch-network-folder.google_folder_iam_binding.authoritative["roles/resourcemanager.projectCreator"]:
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-net-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/resourcemanager.projectCreator
- module.branch-network-folder.google_folder_iam_binding.authoritative["roles/viewer"]:
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-net-0r@fast-prod-automation.iam.gserviceaccount.com
- role: roles/viewer
- module.branch-network-folder.google_tags_tag_binding.binding["context"]:
- timeouts: null
- module.branch-network-gcs.google_storage_bucket.bucket:
+ role: roles/storage.objectViewer
+ module.net-bucket[0].google_storage_bucket.bucket:
autoclass: []
cors: []
custom_placement_config: []
default_event_based_hold: null
+ effective_labels:
+ goog-terraform-provisioned: 'true'
enable_object_retention: null
encryption: []
force_destroy: false
@@ -262,92 +187,262 @@ values:
location: EU
logging: []
name: fast2-prod-resman-net-0
- project: fast-prod-automation
+ project: fast2-prod-automation
requester_pays: null
retention_policy: []
storage_class: STANDARD
+ terraform_labels:
+ goog-terraform-provisioned: 'true'
timeouts: null
uniform_bucket_level_access: true
versioning:
- enabled: true
- module.branch-network-gcs.google_storage_bucket_iam_binding.authoritative["roles/storage.objectAdmin"]:
+ module.net-bucket[0].google_storage_bucket_iam_binding.authoritative["roles/storage.objectAdmin"]:
bucket: fast2-prod-resman-net-0
condition: []
members:
- - serviceAccount:fast2-prod-resman-net-0@fast-prod-automation.iam.gserviceaccount.com
+ - serviceAccount:fast2-prod-resman-net-0@fast2-prod-automation.iam.gserviceaccount.com
role: roles/storage.objectAdmin
- module.branch-network-gcs.google_storage_bucket_iam_binding.authoritative["roles/storage.objectViewer"]:
+ module.net-bucket[0].google_storage_bucket_iam_binding.authoritative["roles/storage.objectViewer"]:
bucket: fast2-prod-resman-net-0
condition: []
members:
- - serviceAccount:fast2-prod-resman-net-0r@fast-prod-automation.iam.gserviceaccount.com
+ - serviceAccount:fast2-prod-resman-net-0r@fast2-prod-automation.iam.gserviceaccount.com
role: roles/storage.objectViewer
- module.branch-network-prod-folder.google_folder.folder[0]:
+ module.net-folder-dev[0].google_folder.folder[0]:
+ deletion_protection: false
+ display_name: Development
+ timeouts: null
+ module.net-folder-dev[0].google_tags_tag_binding.binding["environment"]:
+ timeouts: null
+ module.net-folder-prod[0].google_folder.folder[0]:
+ deletion_protection: false
display_name: Production
timeouts: null
- ? module.branch-network-prod-folder.google_folder_iam_binding.authoritative["organizations/123456789012/roles/gcveNetworkAdmin"]
- : condition: []
- members: null
- role: organizations/123456789012/roles/gcveNetworkAdmin
- ? module.branch-network-prod-folder.google_folder_iam_binding.authoritative["organizations/123456789012/roles/xpnServiceAdmin"]
+ module.net-folder-prod[0].google_tags_tag_binding.binding["environment"]:
+ timeouts: null
+ module.net-folder[0].google_folder.folder[0]:
+ deletion_protection: false
+ display_name: Networking
+ parent: organizations/123456789012
+ timeouts: null
+ ? module.net-folder[0].google_folder_iam_binding.authoritative["organizations/123456789012/roles/networkFirewallPoliciesAdmin"]
: condition: []
members:
- - serviceAccount:fast2-prod-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- - serviceAccount:fast2-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- role: organizations/123456789012/roles/xpnServiceAdmin
- module.branch-network-prod-folder.google_folder_iam_binding.authoritative["roles/compute.networkViewer"]:
+ - serviceAccount:fast2-resman-nsec-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: organizations/123456789012/roles/networkFirewallPoliciesAdmin
+ module.net-folder[0].google_folder_iam_binding.authoritative["organizations/123456789012/roles/projectIamViewer"]:
condition: []
members:
- - serviceAccount:fast2-prod-resman-pf-0r@fast-prod-automation.iam.gserviceaccount.com
- - serviceAccount:fast2-resman-pf-0r@fast-prod-automation.iam.gserviceaccount.com
+ - serviceAccount:fast2-resman-pf-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: organizations/123456789012/roles/projectIamViewer
+ module.net-folder[0].google_folder_iam_binding.authoritative["organizations/123456789012/roles/xpnServiceAdmin"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-resman-pf-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: organizations/123456789012/roles/xpnServiceAdmin
+ module.net-folder[0].google_folder_iam_binding.authoritative["roles/compute.networkViewer"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-resman-pf-0r@fast2-prod-automation.iam.gserviceaccount.com
role: roles/compute.networkViewer
- module.branch-network-prod-folder.google_tags_tag_binding.binding["environment"]:
- timeouts: null
- ? module.branch-network-r-sa.google_project_iam_member.project-roles["fast-prod-automation-roles/serviceusage.serviceUsageConsumer"]
- : condition: []
- project: fast-prod-automation
+ module.net-folder[0].google_folder_iam_binding.authoritative["roles/compute.orgFirewallPolicyUser"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-resman-nsec-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/compute.orgFirewallPolicyUser
+ module.net-folder[0].google_folder_iam_binding.authoritative["roles/compute.xpnAdmin"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-net-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/compute.xpnAdmin
+ module.net-folder[0].google_folder_iam_binding.authoritative["roles/editor"]:
+ condition: []
+ members:
+ - group:gcp-vpc-network-admins@fast.example.com
+ role: roles/editor
+ module.net-folder[0].google_folder_iam_binding.authoritative["roles/logging.admin"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-net-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/logging.admin
+ module.net-folder[0].google_folder_iam_binding.authoritative["roles/owner"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-net-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/owner
+ module.net-folder[0].google_folder_iam_binding.authoritative["roles/resourcemanager.folderAdmin"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-net-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.folderAdmin
+ module.net-folder[0].google_folder_iam_binding.authoritative["roles/resourcemanager.folderViewer"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-net-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.folderViewer
+ module.net-folder[0].google_folder_iam_binding.authoritative["roles/resourcemanager.projectCreator"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-net-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.projectCreator
+ module.net-folder[0].google_folder_iam_binding.authoritative["roles/resourcemanager.tagUser"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-net-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.tagUser
+ module.net-folder[0].google_folder_iam_binding.authoritative["roles/resourcemanager.tagViewer"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-net-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.tagViewer
+ module.net-folder[0].google_folder_iam_binding.authoritative["roles/serviceusage.serviceUsageAdmin"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-sec-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/serviceusage.serviceUsageAdmin
+ module.net-folder[0].google_folder_iam_binding.authoritative["roles/serviceusage.serviceUsageConsumer"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-sec-0r@fast2-prod-automation.iam.gserviceaccount.com
role: roles/serviceusage.serviceUsageConsumer
- module.branch-network-r-sa.google_service_account.service_account[0]:
+ module.net-folder[0].google_folder_iam_binding.authoritative["roles/viewer"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-net-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/viewer
+ module.net-folder[0].google_folder_iam_binding.bindings["organizations/123456789012/roles/gcveNetworkAdmin:development"]:
+ condition:
+ - description: null
+ expression: "resource.matchTag(\n '123456789012/environment',\n 'development'\n\
+ )\n"
+ title: stage 3 development
+ members:
+ - serviceAccount:fast2-dev-resman-gcve-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: organizations/123456789012/roles/gcveNetworkAdmin
+ module.net-folder[0].google_folder_iam_binding.bindings["organizations/123456789012/roles/gcveNetworkAdmin:production"]:
+ condition:
+ - description: null
+ expression: "resource.matchTag(\n '123456789012/environment',\n 'production'\n\
+ )\n"
+ title: stage 3 production
+ members:
+ - serviceAccount:fast2-prod-resman-gcve-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: organizations/123456789012/roles/gcveNetworkAdmin
+ module.net-folder[0].google_folder_iam_binding.bindings["organizations/123456789012/roles/gcveNetworkViewer:development"]:
+ condition:
+ - description: null
+ expression: "resource.matchTag(\n '123456789012/environment',\n 'development'\n\
+ )\n"
+ title: stage 3 development
+ members:
+ - serviceAccount:fast2-dev-resman-gcve-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: organizations/123456789012/roles/gcveNetworkViewer
+ module.net-folder[0].google_folder_iam_binding.bindings["organizations/123456789012/roles/gcveNetworkViewer:production"]:
+ condition:
+ - description: null
+ expression: "resource.matchTag(\n '123456789012/environment',\n 'production'\n\
+ )\n"
+ title: stage 3 production
+ members:
+ - serviceAccount:fast2-prod-resman-gcve-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: organizations/123456789012/roles/gcveNetworkViewer
+ module.net-folder[0].google_folder_iam_binding.bindings["pf_delegated_grant"]:
+ condition:
+ - description: Project factory delegated grant.
+ expression: api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly(['roles/compute.networkUser',
+ 'roles/composer.sharedVpcAgent', 'roles/container.hostServiceAgentUser', 'roles/vpcaccess.user'])
+ title: project factory project delegated admin
+ members:
+ - serviceAccount:fast2-resman-pf-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.projectIamAdmin
+ module.net-folder[0].google_folder_iam_binding.bindings["roles/dns.admin:development"]:
+ condition:
+ - description: null
+ expression: "resource.matchTag(\n '123456789012/environment',\n 'development'\n\
+ )\n"
+ title: stage 3 development
+ members:
+ - serviceAccount:fast2-dev-resman-gke-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/dns.admin
+ module.net-folder[0].google_folder_iam_binding.bindings["roles/dns.admin:production"]:
+ condition:
+ - description: null
+ expression: "resource.matchTag(\n '123456789012/environment',\n 'production'\n\
+ )\n"
+ title: stage 3 production
+ members:
+ - serviceAccount:fast2-prod-resman-gke-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/dns.admin
+ module.net-folder[0].google_folder_iam_binding.bindings["roles/dns.reader:development"]:
+ condition:
+ - description: null
+ expression: "resource.matchTag(\n '123456789012/environment',\n 'development'\n\
+ )\n"
+ title: stage 3 development
+ members:
+ - serviceAccount:fast2-dev-resman-gke-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/dns.reader
+ module.net-folder[0].google_folder_iam_binding.bindings["roles/dns.reader:production"]:
+ condition:
+ - description: null
+ expression: "resource.matchTag(\n '123456789012/environment',\n 'production'\n\
+ )\n"
+ title: stage 3 production
+ members:
+ - serviceAccount:fast2-prod-resman-gke-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/dns.reader
+ module.net-folder[0].google_tags_tag_binding.binding["context"]:
+ timeouts: null
+ ? module.net-sa-ro[0].google_project_iam_member.project-roles["fast2-prod-automation-roles/serviceusage.serviceUsageConsumer"]
+ : condition: []
+ project: fast2-prod-automation
+ role: roles/serviceusage.serviceUsageConsumer
+ module.net-sa-ro[0].google_service_account.service_account[0]:
account_id: fast2-prod-resman-net-0r
create_ignore_already_exists: null
description: null
disabled: false
display_name: Terraform resman networking service account (read-only).
- project: fast-prod-automation
+ project: fast2-prod-automation
timeouts: null
- module.branch-network-r-sa.google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
+ module.net-sa-ro[0].google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
condition: []
- members: null
+ members:
+ - serviceAccount:fast2-prod-resman-net-1r@fast2-prod-automation.iam.gserviceaccount.com
role: roles/iam.serviceAccountTokenCreator
- ? module.branch-network-r-sa.google_storage_bucket_iam_member.bucket-roles["test-organizations/123456789012/roles/storageViewer"]
- : bucket: test
+ ? module.net-sa-ro[0].google_storage_bucket_iam_member.bucket-roles["fast2-prod-iac-core-outputs-organizations/123456789012/roles/storageViewer"]
+ : bucket: fast2-prod-iac-core-outputs
condition: []
role: organizations/123456789012/roles/storageViewer
- ? module.branch-network-sa.google_project_iam_member.project-roles["fast-prod-automation-roles/serviceusage.serviceUsageConsumer"]
+ ? module.net-sa-rw[0].google_project_iam_member.project-roles["fast2-prod-automation-roles/serviceusage.serviceUsageConsumer"]
: condition: []
- project: fast-prod-automation
+ project: fast2-prod-automation
role: roles/serviceusage.serviceUsageConsumer
- module.branch-network-sa.google_service_account.service_account[0]:
+ module.net-sa-rw[0].google_service_account.service_account[0]:
account_id: fast2-prod-resman-net-0
create_ignore_already_exists: null
description: null
disabled: false
display_name: Terraform resman networking service account.
- project: fast-prod-automation
+ project: fast2-prod-automation
timeouts: null
- module.branch-network-sa.google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
+ module.net-sa-rw[0].google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
condition: []
- members: null
+ members:
+ - serviceAccount:fast2-prod-resman-net-1@fast2-prod-automation.iam.gserviceaccount.com
role: roles/iam.serviceAccountTokenCreator
- module.branch-network-sa.google_storage_bucket_iam_member.bucket-roles["test-roles/storage.objectAdmin"]:
- bucket: test
+ module.net-sa-rw[0].google_storage_bucket_iam_member.bucket-roles["fast2-prod-iac-core-outputs-roles/storage.objectAdmin"]:
+ bucket: fast2-prod-iac-core-outputs
condition: []
role: roles/storage.objectAdmin
- module.branch-pf-dev-gcs.google_storage_bucket.bucket:
+ module.nsec-bucket[0].google_storage_bucket.bucket:
autoclass: []
cors: []
custom_placement_config: []
default_event_based_hold: null
+ effective_labels:
+ goog-terraform-provisioned: 'true'
enable_object_retention: null
encryption: []
force_destroy: false
@@ -355,432 +450,167 @@ values:
lifecycle_rule: []
location: EU
logging: []
- name: fast2-dev-resman-pf-0
- project: fast-prod-automation
+ name: fast2-resman-nsec-0
+ project: fast2-prod-automation
requester_pays: null
retention_policy: []
storage_class: STANDARD
+ terraform_labels:
+ goog-terraform-provisioned: 'true'
timeouts: null
uniform_bucket_level_access: true
versioning:
- enabled: true
- module.branch-pf-dev-gcs.google_storage_bucket_iam_binding.authoritative["roles/storage.objectAdmin"]:
- bucket: fast2-dev-resman-pf-0
+ module.nsec-bucket[0].google_storage_bucket_iam_binding.authoritative["roles/storage.objectAdmin"]:
+ bucket: fast2-resman-nsec-0
condition: []
members:
- - serviceAccount:fast2-dev-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
+ - serviceAccount:fast2-resman-nsec-0@fast2-prod-automation.iam.gserviceaccount.com
role: roles/storage.objectAdmin
- module.branch-pf-dev-gcs.google_storage_bucket_iam_binding.authoritative["roles/storage.objectViewer"]:
- bucket: fast2-dev-resman-pf-0
+ module.nsec-bucket[0].google_storage_bucket_iam_binding.authoritative["roles/storage.objectViewer"]:
+ bucket: fast2-resman-nsec-0
condition: []
members:
- - serviceAccount:fast2-dev-resman-pf-0r@fast-prod-automation.iam.gserviceaccount.com
+ - serviceAccount:fast2-resman-nsec-0r@fast2-prod-automation.iam.gserviceaccount.com
role: roles/storage.objectViewer
- ? module.branch-pf-dev-r-sa.google_project_iam_member.project-roles["fast-prod-automation-roles/serviceusage.serviceUsageConsumer"]
+ ? module.nsec-sa-ro[0].google_project_iam_member.project-roles["fast2-prod-automation-roles/serviceusage.serviceUsageConsumer"]
: condition: []
- project: fast-prod-automation
+ project: fast2-prod-automation
role: roles/serviceusage.serviceUsageConsumer
- module.branch-pf-dev-r-sa.google_service_account.service_account[0]:
- account_id: fast2-dev-resman-pf-0r
+ module.nsec-sa-ro[0].google_service_account.service_account[0]:
+ account_id: fast2-resman-nsec-0r
create_ignore_already_exists: null
description: null
disabled: false
- display_name: Terraform project factory development service account (read-only).
- project: fast-prod-automation
+ display_name: Terraform resman network security main service account (read-only).
+ project: fast2-prod-automation
timeouts: null
- module.branch-pf-dev-r-sa.google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
+ module.nsec-sa-ro[0].google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
condition: []
members: null
role: roles/iam.serviceAccountTokenCreator
- ? module.branch-pf-dev-r-sa.google_storage_bucket_iam_member.bucket-roles["test-organizations/123456789012/roles/storageViewer"]
- : bucket: test
+ ? module.nsec-sa-ro[0].google_storage_bucket_iam_member.bucket-roles["fast2-prod-iac-core-outputs-organizations/123456789012/roles/storageViewer"]
+ : bucket: fast2-prod-iac-core-outputs
condition: []
role: organizations/123456789012/roles/storageViewer
- ? module.branch-pf-dev-sa.google_project_iam_member.project-roles["fast-prod-automation-roles/serviceusage.serviceUsageConsumer"]
+ ? module.nsec-sa-rw[0].google_project_iam_member.project-roles["fast2-prod-automation-roles/serviceusage.serviceUsageConsumer"]
: condition: []
- project: fast-prod-automation
+ project: fast2-prod-automation
role: roles/serviceusage.serviceUsageConsumer
- module.branch-pf-dev-sa.google_service_account.service_account[0]:
- account_id: fast2-dev-resman-pf-0
+ module.nsec-sa-rw[0].google_service_account.service_account[0]:
+ account_id: fast2-resman-nsec-0
create_ignore_already_exists: null
description: null
disabled: false
- display_name: Terraform project factory development service account.
- project: fast-prod-automation
+ display_name: Terraform resman network security main service account.
+ project: fast2-prod-automation
timeouts: null
- module.branch-pf-dev-sa.google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
+ module.nsec-sa-rw[0].google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
condition: []
members: null
role: roles/iam.serviceAccountTokenCreator
- module.branch-pf-dev-sa.google_storage_bucket_iam_member.bucket-roles["test-roles/storage.objectAdmin"]:
- bucket: test
+ ? module.nsec-sa-rw[0].google_storage_bucket_iam_member.bucket-roles["fast2-prod-iac-core-outputs-roles/storage.objectAdmin"]
+ : bucket: fast2-prod-iac-core-outputs
condition: []
role: roles/storage.objectAdmin
- module.branch-pf-gcs.google_storage_bucket.bucket:
- autoclass: []
- cors: []
- custom_placement_config: []
- default_event_based_hold: null
- enable_object_retention: null
- encryption: []
- force_destroy: false
- labels: null
- lifecycle_rule: []
- location: EU
- logging: []
- name: fast2-resman-pf-0
- project: fast-prod-automation
- requester_pays: null
- retention_policy: []
- storage_class: STANDARD
- timeouts: null
- uniform_bucket_level_access: true
- versioning:
- - enabled: true
- module.branch-pf-gcs.google_storage_bucket_iam_binding.authoritative["roles/storage.objectAdmin"]:
- bucket: fast2-resman-pf-0
+ module.organization[0].google_organization_iam_member.bindings["gcve-dev"]:
condition: []
- members:
- - serviceAccount:fast2-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/storage.objectAdmin
- module.branch-pf-gcs.google_storage_bucket_iam_binding.authoritative["roles/storage.objectViewer"]:
- bucket: fast2-resman-pf-0
+ member: serviceAccount:fast2-dev-resman-gcve-0@fast2-prod-automation.iam.gserviceaccount.com
+ org_id: '123456789012'
+ role: roles/billing.user
+ module.organization[0].google_organization_iam_member.bindings["gcve-prod"]:
condition: []
- members:
- - serviceAccount:fast2-resman-pf-0r@fast-prod-automation.iam.gserviceaccount.com
- role: roles/storage.objectViewer
- module.branch-pf-prod-gcs.google_storage_bucket.bucket:
- autoclass: []
- cors: []
- custom_placement_config: []
- default_event_based_hold: null
- enable_object_retention: null
- encryption: []
- force_destroy: false
- labels: null
- lifecycle_rule: []
- location: EU
- logging: []
- name: fast2-prod-resman-pf-0
- project: fast-prod-automation
- requester_pays: null
- retention_policy: []
- storage_class: STANDARD
- timeouts: null
- uniform_bucket_level_access: true
- versioning:
- - enabled: true
- module.branch-pf-prod-gcs.google_storage_bucket_iam_binding.authoritative["roles/storage.objectAdmin"]:
- bucket: fast2-prod-resman-pf-0
+ member: serviceAccount:fast2-prod-resman-gcve-0@fast2-prod-automation.iam.gserviceaccount.com
+ org_id: '123456789012'
+ role: roles/billing.user
+ module.organization[0].google_organization_iam_member.bindings["gke-dev"]:
condition: []
- members:
- - serviceAccount:fast2-prod-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/storage.objectAdmin
- module.branch-pf-prod-gcs.google_storage_bucket_iam_binding.authoritative["roles/storage.objectViewer"]:
- bucket: fast2-prod-resman-pf-0
+ member: serviceAccount:fast2-dev-resman-gke-0@fast2-prod-automation.iam.gserviceaccount.com
+ org_id: '123456789012'
+ role: roles/billing.user
+ module.organization[0].google_organization_iam_member.bindings["gke-prod"]:
condition: []
- members:
- - serviceAccount:fast2-prod-resman-pf-0r@fast-prod-automation.iam.gserviceaccount.com
- role: roles/storage.objectViewer
- ? module.branch-pf-prod-r-sa.google_project_iam_member.project-roles["fast-prod-automation-roles/serviceusage.serviceUsageConsumer"]
- : condition: []
- project: fast-prod-automation
- role: roles/serviceusage.serviceUsageConsumer
- module.branch-pf-prod-r-sa.google_service_account.service_account[0]:
- account_id: fast2-prod-resman-pf-0r
- create_ignore_already_exists: null
- description: null
- disabled: false
- display_name: Terraform project factory production service account (read-only).
- project: fast-prod-automation
- timeouts: null
- module.branch-pf-prod-r-sa.google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
+ member: serviceAccount:fast2-prod-resman-gke-0@fast2-prod-automation.iam.gserviceaccount.com
+ org_id: '123456789012'
+ role: roles/billing.user
+ module.organization[0].google_organization_iam_member.bindings["project-factory-dev"]:
condition: []
- members: null
- role: roles/iam.serviceAccountTokenCreator
- ? module.branch-pf-prod-r-sa.google_storage_bucket_iam_member.bucket-roles["test-organizations/123456789012/roles/storageViewer"]
- : bucket: test
+ member: serviceAccount:fast2-dev-resman-pf-0@fast2-prod-automation.iam.gserviceaccount.com
+ org_id: '123456789012'
+ role: roles/billing.user
+ module.organization[0].google_organization_iam_member.bindings["project-factory-prod"]:
condition: []
- role: organizations/123456789012/roles/storageViewer
- ? module.branch-pf-prod-sa.google_project_iam_member.project-roles["fast-prod-automation-roles/serviceusage.serviceUsageConsumer"]
- : condition: []
- project: fast-prod-automation
- role: roles/serviceusage.serviceUsageConsumer
- module.branch-pf-prod-sa.google_service_account.service_account[0]:
- account_id: fast2-prod-resman-pf-0
- create_ignore_already_exists: null
- description: null
- disabled: false
- display_name: Terraform project factory production service account.
- project: fast-prod-automation
- timeouts: null
- module.branch-pf-prod-sa.google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
- condition: []
- members: null
- role: roles/iam.serviceAccountTokenCreator
- module.branch-pf-prod-sa.google_storage_bucket_iam_member.bucket-roles["test-roles/storage.objectAdmin"]:
- bucket: test
- condition: []
- role: roles/storage.objectAdmin
- ? module.branch-pf-r-sa.google_project_iam_member.project-roles["fast-prod-automation-roles/serviceusage.serviceUsageConsumer"]
- : condition: []
- project: fast-prod-automation
- role: roles/serviceusage.serviceUsageConsumer
- module.branch-pf-r-sa.google_service_account.service_account[0]:
- account_id: fast2-resman-pf-0r
- create_ignore_already_exists: null
- description: null
- disabled: false
- display_name: Terraform project factory main service account (read-only).
- project: fast-prod-automation
- timeouts: null
- module.branch-pf-r-sa.google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
- condition: []
- members: null
- role: roles/iam.serviceAccountTokenCreator
- module.branch-pf-r-sa.google_storage_bucket_iam_member.bucket-roles["test-organizations/123456789012/roles/storageViewer"]:
- bucket: test
- condition: []
- role: organizations/123456789012/roles/storageViewer
- ? module.branch-pf-sa.google_project_iam_member.project-roles["fast-prod-automation-roles/serviceusage.serviceUsageConsumer"]
- : condition: []
- project: fast-prod-automation
- role: roles/serviceusage.serviceUsageConsumer
- module.branch-pf-sa.google_service_account.service_account[0]:
- account_id: fast2-resman-pf-0
- create_ignore_already_exists: null
- description: null
- disabled: false
- display_name: Terraform project factory main service account.
- project: fast-prod-automation
- timeouts: null
- module.branch-pf-sa.google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
- condition: []
- members: null
- role: roles/iam.serviceAccountTokenCreator
- module.branch-pf-sa.google_storage_bucket_iam_member.bucket-roles["test-roles/storage.objectAdmin"]:
- bucket: test
- condition: []
- role: roles/storage.objectAdmin
- module.branch-security-folder.google_folder.folder[0]:
- display_name: Security
- parent: organizations/123456789012
- timeouts: null
- module.branch-security-folder.google_folder_iam_binding.authoritative["roles/browser"]:
- condition: []
- members:
- - user:extra-browser@fast.example.com
- role: roles/browser
- module.branch-security-folder.google_folder_iam_binding.authoritative["roles/editor"]:
- condition: []
- members:
- - group:gcp-security-admins@fast.example.com
- role: roles/editor
- module.branch-security-folder.google_folder_iam_binding.authoritative["roles/logging.admin"]:
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-sec-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/logging.admin
- module.branch-security-folder.google_folder_iam_binding.authoritative["roles/owner"]:
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-sec-0@fast-prod-automation.iam.gserviceaccount.com
- - user:extra-owner@fast.example.com
- role: roles/owner
- module.branch-security-folder.google_folder_iam_binding.authoritative["roles/resourcemanager.folderAdmin"]:
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-sec-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/resourcemanager.folderAdmin
- module.branch-security-folder.google_folder_iam_binding.authoritative["roles/resourcemanager.folderViewer"]:
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-sec-0r@fast-prod-automation.iam.gserviceaccount.com
- role: roles/resourcemanager.folderViewer
- module.branch-security-folder.google_folder_iam_binding.authoritative["roles/resourcemanager.projectCreator"]:
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-sec-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/resourcemanager.projectCreator
- module.branch-security-folder.google_folder_iam_binding.authoritative["roles/viewer"]:
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-sec-0r@fast-prod-automation.iam.gserviceaccount.com
- role: roles/viewer
- module.branch-security-folder.google_folder_iam_binding.bindings["tenant_iam_admin_conditional"]:
- condition:
- - description: Certificate Authority Service delegated grants.
- expression: api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly(['roles/privateca.certificateManager'])
- title: security_sa_delegated_grants
- members:
- - serviceAccount:fast2-prod-resman-sec-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/resourcemanager.folderIamAdmin
- module.branch-security-folder.google_tags_tag_binding.binding["context"]:
- timeouts: null
- module.branch-security-gcs.google_storage_bucket.bucket:
- autoclass: []
- cors: []
- custom_placement_config: []
- default_event_based_hold: null
- enable_object_retention: null
- encryption: []
- force_destroy: false
- labels: null
- lifecycle_rule: []
- location: EU
- logging: []
- name: fast2-prod-resman-sec-0
- project: fast-prod-automation
- requester_pays: null
- retention_policy: []
- storage_class: STANDARD
- timeouts: null
- uniform_bucket_level_access: true
- versioning:
- - enabled: true
- module.branch-security-gcs.google_storage_bucket_iam_binding.authoritative["roles/storage.objectAdmin"]:
- bucket: fast2-prod-resman-sec-0
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-sec-0@fast-prod-automation.iam.gserviceaccount.com
- role: roles/storage.objectAdmin
- module.branch-security-gcs.google_storage_bucket_iam_binding.authoritative["roles/storage.objectViewer"]:
- bucket: fast2-prod-resman-sec-0
- condition: []
- members:
- - serviceAccount:fast2-prod-resman-sec-0r@fast-prod-automation.iam.gserviceaccount.com
- role: roles/storage.objectViewer
- ? module.branch-security-r-sa.google_project_iam_member.project-roles["fast-prod-automation-roles/serviceusage.serviceUsageConsumer"]
- : condition: []
- project: fast-prod-automation
- role: roles/serviceusage.serviceUsageConsumer
- module.branch-security-r-sa.google_service_account.service_account[0]:
- account_id: fast2-prod-resman-sec-0r
- create_ignore_already_exists: null
- description: null
- disabled: false
- display_name: Terraform resman security service account (read-only).
- project: fast-prod-automation
- timeouts: null
- module.branch-security-r-sa.google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
- condition: []
- members: null
- role: roles/iam.serviceAccountTokenCreator
- ? module.branch-security-r-sa.google_storage_bucket_iam_member.bucket-roles["test-organizations/123456789012/roles/storageViewer"]
- : bucket: test
- condition: []
- role: organizations/123456789012/roles/storageViewer
- ? module.branch-security-sa.google_project_iam_member.project-roles["fast-prod-automation-roles/serviceusage.serviceUsageConsumer"]
- : condition: []
- project: fast-prod-automation
- role: roles/serviceusage.serviceUsageConsumer
- module.branch-security-sa.google_service_account.service_account[0]:
- account_id: fast2-prod-resman-sec-0
- create_ignore_already_exists: null
- description: null
- disabled: false
- display_name: Terraform resman security service account.
- project: fast-prod-automation
- timeouts: null
- module.branch-security-sa.google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
- condition: []
- members: null
- role: roles/iam.serviceAccountTokenCreator
- module.branch-security-sa.google_storage_bucket_iam_member.bucket-roles["test-roles/storage.objectAdmin"]:
- bucket: test
- condition: []
- role: roles/storage.objectAdmin
+ member: serviceAccount:fast2-prod-resman-pf-0@fast2-prod-automation.iam.gserviceaccount.com
+ org_id: '123456789012'
+ role: roles/billing.user
module.organization[0].google_organization_iam_member.bindings["sa_net_billing"]:
condition: []
- member: serviceAccount:fast2-prod-resman-net-0@fast-prod-automation.iam.gserviceaccount.com
+ member: serviceAccount:fast2-prod-resman-net-0@fast2-prod-automation.iam.gserviceaccount.com
org_id: '123456789012'
role: roles/billing.user
module.organization[0].google_organization_iam_member.bindings["sa_net_fw_policy_admin"]:
condition: []
- member: serviceAccount:fast2-prod-resman-net-0@fast-prod-automation.iam.gserviceaccount.com
+ member: serviceAccount:fast2-prod-resman-net-0@fast2-prod-automation.iam.gserviceaccount.com
org_id: '123456789012'
role: roles/compute.orgFirewallPolicyAdmin
+ module.organization[0].google_organization_iam_member.bindings["sa_net_nsec_fw_policy_user"]:
+ condition: []
+ member: serviceAccount:fast2-resman-nsec-0@fast2-prod-automation.iam.gserviceaccount.com
+ org_id: '123456789012'
+ role: roles/compute.orgFirewallPolicyUser
+ module.organization[0].google_organization_iam_member.bindings["sa_net_nsec_ngfw_enterprise_admin"]:
+ condition: []
+ member: serviceAccount:fast2-resman-nsec-0@fast2-prod-automation.iam.gserviceaccount.com
+ org_id: '123456789012'
+ role: organizations/123456789012/roles/ngfwEnterpriseAdmin
+ module.organization[0].google_organization_iam_member.bindings["sa_net_nsec_ro_ngfw_enterprise_viewer"]:
+ condition: []
+ member: serviceAccount:fast2-resman-nsec-0r@fast2-prod-automation.iam.gserviceaccount.com
+ org_id: '123456789012'
+ role: organizations/123456789012/roles/ngfwEnterpriseViewer
module.organization[0].google_organization_iam_member.bindings["sa_net_xpn_admin"]:
condition: []
- member: serviceAccount:fast2-prod-resman-net-0@fast-prod-automation.iam.gserviceaccount.com
+ member: serviceAccount:fast2-prod-resman-net-0@fast2-prod-automation.iam.gserviceaccount.com
org_id: '123456789012'
role: roles/compute.xpnAdmin
+ module.organization[0].google_organization_iam_member.bindings["sa_nsec_fw_policy_admin"]:
+ condition: []
+ member: serviceAccount:fast2-resman-nsec-0@fast2-prod-automation.iam.gserviceaccount.com
+ org_id: '123456789012'
+ role: roles/compute.orgFirewallPolicyAdmin
module.organization[0].google_organization_iam_member.bindings["sa_pf_billing"]:
condition: []
- member: serviceAccount:fast2-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
+ member: serviceAccount:fast2-resman-pf-0@fast2-prod-automation.iam.gserviceaccount.com
org_id: '123456789012'
role: roles/billing.user
module.organization[0].google_organization_iam_member.bindings["sa_pf_conditional_org_policy"]:
condition:
- - description: Org policy tag scoped grant for project factory main.
+ - description: Org policy tag scoped grant for project factory.
expression: 'resource.matchTag(''123456789012/context'', ''project-factory'')
'
title: org_policy_tag_pf_scoped
- member: serviceAccount:fast2-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
+ member: serviceAccount:fast2-resman-pf-0@fast2-prod-automation.iam.gserviceaccount.com
org_id: '123456789012'
role: roles/orgpolicy.policyAdmin
module.organization[0].google_organization_iam_member.bindings["sa_pf_costs_manager"]:
condition: []
- member: serviceAccount:fast2-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
+ member: serviceAccount:fast2-resman-pf-0@fast2-prod-automation.iam.gserviceaccount.com
org_id: '123456789012'
role: roles/billing.costsManager
- module.organization[0].google_organization_iam_member.bindings["sa_pf_dev_billing"]:
+ module.organization[0].google_organization_iam_member.bindings["sa_pf_ro_viewer"]:
condition: []
- member: serviceAccount:fast2-dev-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
+ member: serviceAccount:fast2-resman-pf-0r@fast2-prod-automation.iam.gserviceaccount.com
org_id: '123456789012'
- role: roles/billing.user
- module.organization[0].google_organization_iam_member.bindings["sa_pf_dev_conditional_org_policy"]:
- condition:
- - description: Org policy tag scoped grant for project factory dev.
- expression: 'resource.matchTag(''123456789012/context'', ''project-factory'')
-
- &&
-
- resource.matchTag(''123456789012/environment'', ''development'')
-
- '
- title: org_policy_tag_pf_scoped_dev
- member: serviceAccount:fast2-dev-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/orgpolicy.policyAdmin
- module.organization[0].google_organization_iam_member.bindings["sa_pf_dev_costs_manager"]:
- condition: []
- member: serviceAccount:fast2-dev-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/billing.costsManager
- module.organization[0].google_organization_iam_member.bindings["sa_pf_prod_billing"]:
- condition: []
- member: serviceAccount:fast2-prod-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/billing.user
- module.organization[0].google_organization_iam_member.bindings["sa_pf_prod_conditional_org_policy"]:
- condition:
- - description: Org policy tag scoped grant for project factory prod.
- expression: 'resource.matchTag(''123456789012/context'', ''project-factory'')
-
- &&
-
- resource.matchTag(''123456789012/environment'', ''production'')
-
- '
- title: org_policy_tag_pf_scoped_prod
- member: serviceAccount:fast2-prod-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/orgpolicy.policyAdmin
- module.organization[0].google_organization_iam_member.bindings["sa_pf_prod_costs_manager"]:
- condition: []
- member: serviceAccount:fast2-prod-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
- org_id: '123456789012'
- role: roles/billing.costsManager
+ role: organizations/123456789012/roles/billingViewer
module.organization[0].google_organization_iam_member.bindings["sa_sec_asset_viewer"]:
condition: []
- member: serviceAccount:fast2-prod-resman-sec-0@fast-prod-automation.iam.gserviceaccount.com
+ member: serviceAccount:fast2-prod-resman-sec-0@fast2-prod-automation.iam.gserviceaccount.com
org_id: '123456789012'
role: roles/cloudasset.viewer
module.organization[0].google_organization_iam_member.bindings["sa_sec_billing"]:
condition: []
- member: serviceAccount:fast2-prod-resman-sec-0@fast-prod-automation.iam.gserviceaccount.com
+ member: serviceAccount:fast2-prod-resman-sec-0@fast2-prod-automation.iam.gserviceaccount.com
org_id: '123456789012'
role: roles/billing.user
module.organization[0].google_tags_tag_key.default["context"]:
@@ -797,9 +627,9 @@ values:
purpose_data: null
short_name: environment
timeouts: null
- module.organization[0].google_tags_tag_value.default["context/data"]:
+ module.organization[0].google_tags_tag_value.default["context/data-platform"]:
description: Managed by the Terraform organization module.
- short_name: data
+ short_name: data-platform
timeouts: null
module.organization[0].google_tags_tag_value.default["context/gcve"]:
description: Managed by the Terraform organization module.
@@ -809,10 +639,18 @@ values:
description: Managed by the Terraform organization module.
short_name: gke
timeouts: null
+ module.organization[0].google_tags_tag_value.default["context/network-security"]:
+ description: Managed by the Terraform organization module.
+ short_name: network-security
+ timeouts: null
module.organization[0].google_tags_tag_value.default["context/networking"]:
description: Managed by the Terraform organization module.
short_name: networking
timeouts: null
+ module.organization[0].google_tags_tag_value.default["context/nsec"]:
+ description: Managed by the Terraform organization module.
+ short_name: nsec
+ timeouts: null
module.organization[0].google_tags_tag_value.default["context/project-factory"]:
description: Managed by the Terraform organization module.
short_name: project-factory
@@ -825,6 +663,10 @@ values:
description: Managed by the Terraform organization module.
short_name: security
timeouts: null
+ module.organization[0].google_tags_tag_value.default["context/tenants"]:
+ description: Managed by the Terraform organization module.
+ short_name: tenants
+ timeouts: null
module.organization[0].google_tags_tag_value.default["environment/development"]:
description: Managed by the Terraform organization module.
short_name: development
@@ -833,62 +675,1141 @@ values:
description: Managed by the Terraform organization module.
short_name: production
timeouts: null
- module.organization[0].google_tags_tag_value_iam_binding.bindings["environment/development:pf"]:
+ module.organization[0].google_tags_tag_value_iam_binding.default["environment/development:roles/resourcemanager.tagUser"]:
condition: []
members:
- - serviceAccount:fast2-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
+ - serviceAccount:fast2-dev-resman-pf-0@fast2-prod-automation.iam.gserviceaccount.com
+ - serviceAccount:fast2-prod-resman-net-0@fast2-prod-automation.iam.gserviceaccount.com
+ - serviceAccount:fast2-prod-resman-sec-0@fast2-prod-automation.iam.gserviceaccount.com
+ - serviceAccount:fast2-resman-pf-0@fast2-prod-automation.iam.gserviceaccount.com
role: roles/resourcemanager.tagUser
- module.organization[0].google_tags_tag_value_iam_binding.bindings["environment/production:pf"]:
+ ? module.organization[0].google_tags_tag_value_iam_binding.default["environment/development:roles/resourcemanager.tagViewer"]
+ : condition: []
+ members:
+ - serviceAccount:fast2-dev-resman-pf-0r@fast2-prod-automation.iam.gserviceaccount.com
+ - serviceAccount:fast2-prod-resman-net-0r@fast2-prod-automation.iam.gserviceaccount.com
+ - serviceAccount:fast2-prod-resman-sec-0r@fast2-prod-automation.iam.gserviceaccount.com
+ - serviceAccount:fast2-resman-pf-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.tagViewer
+ module.organization[0].google_tags_tag_value_iam_binding.default["environment/production:roles/resourcemanager.tagUser"]:
condition: []
members:
- - serviceAccount:fast2-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
+ - serviceAccount:fast2-prod-resman-net-0@fast2-prod-automation.iam.gserviceaccount.com
+ - serviceAccount:fast2-prod-resman-pf-0@fast2-prod-automation.iam.gserviceaccount.com
+ - serviceAccount:fast2-prod-resman-sec-0@fast2-prod-automation.iam.gserviceaccount.com
+ - serviceAccount:fast2-resman-pf-0@fast2-prod-automation.iam.gserviceaccount.com
role: roles/resourcemanager.tagUser
+ module.organization[0].google_tags_tag_value_iam_binding.default["environment/production:roles/resourcemanager.tagViewer"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-net-0r@fast2-prod-automation.iam.gserviceaccount.com
+ - serviceAccount:fast2-prod-resman-pf-0r@fast2-prod-automation.iam.gserviceaccount.com
+ - serviceAccount:fast2-prod-resman-sec-0r@fast2-prod-automation.iam.gserviceaccount.com
+ - serviceAccount:fast2-resman-pf-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.tagViewer
+ module.pf-bucket[0].google_storage_bucket.bucket:
+ autoclass: []
+ cors: []
+ custom_placement_config: []
+ default_event_based_hold: null
+ effective_labels:
+ goog-terraform-provisioned: 'true'
+ enable_object_retention: null
+ encryption: []
+ force_destroy: false
+ labels: null
+ lifecycle_rule: []
+ location: EU
+ logging: []
+ name: fast2-resman-pf-0
+ project: fast2-prod-automation
+ requester_pays: null
+ retention_policy: []
+ storage_class: STANDARD
+ terraform_labels:
+ goog-terraform-provisioned: 'true'
+ timeouts: null
+ uniform_bucket_level_access: true
+ versioning:
+ - enabled: true
+ module.pf-bucket[0].google_storage_bucket_iam_binding.authoritative["roles/storage.objectAdmin"]:
+ bucket: fast2-resman-pf-0
+ condition: []
+ members:
+ - serviceAccount:fast2-resman-pf-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/storage.objectAdmin
+ module.pf-bucket[0].google_storage_bucket_iam_binding.authoritative["roles/storage.objectViewer"]:
+ bucket: fast2-resman-pf-0
+ condition: []
+ members:
+ - serviceAccount:fast2-resman-pf-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/storage.objectViewer
+ ? module.pf-sa-ro[0].google_project_iam_member.project-roles["fast2-prod-automation-roles/serviceusage.serviceUsageConsumer"]
+ : condition: []
+ project: fast2-prod-automation
+ role: roles/serviceusage.serviceUsageConsumer
+ module.pf-sa-ro[0].google_service_account.service_account[0]:
+ account_id: fast2-resman-pf-0r
+ create_ignore_already_exists: null
+ description: null
+ disabled: false
+ display_name: Terraform resman project factory main service account (read-only).
+ project: fast2-prod-automation
+ timeouts: null
+ module.pf-sa-ro[0].google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
+ condition: []
+ members: null
+ role: roles/iam.serviceAccountTokenCreator
+ ? module.pf-sa-ro[0].google_storage_bucket_iam_member.bucket-roles["fast2-prod-iac-core-outputs-organizations/123456789012/roles/storageViewer"]
+ : bucket: fast2-prod-iac-core-outputs
+ condition: []
+ role: organizations/123456789012/roles/storageViewer
+ ? module.pf-sa-rw[0].google_project_iam_member.project-roles["fast2-prod-automation-roles/serviceusage.serviceUsageConsumer"]
+ : condition: []
+ project: fast2-prod-automation
+ role: roles/serviceusage.serviceUsageConsumer
+ module.pf-sa-rw[0].google_service_account.service_account[0]:
+ account_id: fast2-resman-pf-0
+ create_ignore_already_exists: null
+ description: null
+ disabled: false
+ display_name: Terraform resman project factory main service account.
+ project: fast2-prod-automation
+ timeouts: null
+ module.pf-sa-rw[0].google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
+ condition: []
+ members: null
+ role: roles/iam.serviceAccountTokenCreator
+ module.pf-sa-rw[0].google_storage_bucket_iam_member.bucket-roles["fast2-prod-iac-core-outputs-roles/storage.objectAdmin"]:
+ bucket: fast2-prod-iac-core-outputs
+ condition: []
+ role: roles/storage.objectAdmin
+ module.sec-bucket[0].google_storage_bucket.bucket:
+ autoclass: []
+ cors: []
+ custom_placement_config: []
+ default_event_based_hold: null
+ effective_labels:
+ goog-terraform-provisioned: 'true'
+ enable_object_retention: null
+ encryption: []
+ force_destroy: false
+ labels: null
+ lifecycle_rule: []
+ location: EU
+ logging: []
+ name: fast2-prod-resman-sec-0
+ project: fast2-prod-automation
+ requester_pays: null
+ retention_policy: []
+ storage_class: STANDARD
+ terraform_labels:
+ goog-terraform-provisioned: 'true'
+ timeouts: null
+ uniform_bucket_level_access: true
+ versioning:
+ - enabled: true
+ module.sec-bucket[0].google_storage_bucket_iam_binding.authoritative["roles/storage.objectAdmin"]:
+ bucket: fast2-prod-resman-sec-0
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-sec-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/storage.objectAdmin
+ module.sec-bucket[0].google_storage_bucket_iam_binding.authoritative["roles/storage.objectViewer"]:
+ bucket: fast2-prod-resman-sec-0
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-sec-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/storage.objectViewer
+ module.sec-folder[0].google_folder.folder[0]:
+ deletion_protection: false
+ display_name: Security
+ parent: organizations/123456789012
+ timeouts: null
+ module.sec-folder[0].google_folder_iam_binding.authoritative["organizations/123456789012/roles/projectIamViewer"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-resman-pf-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: organizations/123456789012/roles/projectIamViewer
+ module.sec-folder[0].google_folder_iam_binding.authoritative["roles/cloudkms.cryptoKeyEncrypterDecrypter"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-resman-pf-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/cloudkms.cryptoKeyEncrypterDecrypter
+ module.sec-folder[0].google_folder_iam_binding.authoritative["roles/cloudkms.viewer"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-resman-pf-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/cloudkms.viewer
+ module.sec-folder[0].google_folder_iam_binding.authoritative["roles/editor"]:
+ condition: []
+ members:
+ - group:gcp-security-admins@fast.example.com
+ role: roles/editor
+ module.sec-folder[0].google_folder_iam_binding.authoritative["roles/logging.admin"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-sec-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/logging.admin
+ module.sec-folder[0].google_folder_iam_binding.authoritative["roles/owner"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-sec-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/owner
+ module.sec-folder[0].google_folder_iam_binding.authoritative["roles/resourcemanager.folderAdmin"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-sec-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.folderAdmin
+ module.sec-folder[0].google_folder_iam_binding.authoritative["roles/resourcemanager.folderViewer"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-sec-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.folderViewer
+ module.sec-folder[0].google_folder_iam_binding.authoritative["roles/resourcemanager.projectCreator"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-sec-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.projectCreator
+ module.sec-folder[0].google_folder_iam_binding.authoritative["roles/resourcemanager.tagUser"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-net-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.tagUser
+ module.sec-folder[0].google_folder_iam_binding.authoritative["roles/resourcemanager.tagViewer"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-net-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.tagViewer
+ module.sec-folder[0].google_folder_iam_binding.authoritative["roles/viewer"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-sec-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/viewer
+ module.sec-folder[0].google_folder_iam_binding.bindings["pf_delegated_grant"]:
+ condition:
+ - description: Project factory delegated grant.
+ expression: api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly(['roles/cloudkms.cryptoKeyEncrypterDecrypter'])
+ title: pf_delegated_grant
+ members:
+ - serviceAccount:fast2-resman-pf-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.projectIamAdmin
+ module.sec-folder[0].google_tags_tag_binding.binding["context"]:
+ timeouts: null
+ ? module.sec-sa-ro[0].google_project_iam_member.project-roles["fast2-prod-automation-roles/serviceusage.serviceUsageConsumer"]
+ : condition: []
+ project: fast2-prod-automation
+ role: roles/serviceusage.serviceUsageConsumer
+ module.sec-sa-ro[0].google_service_account.service_account[0]:
+ account_id: fast2-prod-resman-sec-0r
+ create_ignore_already_exists: null
+ description: null
+ disabled: false
+ display_name: Terraform resman security service account (read-only).
+ project: fast2-prod-automation
+ timeouts: null
+ module.sec-sa-ro[0].google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-sec-1r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/iam.serviceAccountTokenCreator
+ ? module.sec-sa-ro[0].google_storage_bucket_iam_member.bucket-roles["fast2-prod-iac-core-outputs-organizations/123456789012/roles/storageViewer"]
+ : bucket: fast2-prod-iac-core-outputs
+ condition: []
+ role: organizations/123456789012/roles/storageViewer
+ ? module.sec-sa-rw[0].google_project_iam_member.project-roles["fast2-prod-automation-roles/serviceusage.serviceUsageConsumer"]
+ : condition: []
+ project: fast2-prod-automation
+ role: roles/serviceusage.serviceUsageConsumer
+ module.sec-sa-rw[0].google_service_account.service_account[0]:
+ account_id: fast2-prod-resman-sec-0
+ create_ignore_already_exists: null
+ description: null
+ disabled: false
+ display_name: Terraform resman security service account.
+ project: fast2-prod-automation
+ timeouts: null
+ module.sec-sa-rw[0].google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-sec-1@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/iam.serviceAccountTokenCreator
+ module.sec-sa-rw[0].google_storage_bucket_iam_member.bucket-roles["fast2-prod-iac-core-outputs-roles/storage.objectAdmin"]:
+ bucket: fast2-prod-iac-core-outputs
+ condition: []
+ role: roles/storage.objectAdmin
+ module.stage3-bucket["gcve-dev"].google_storage_bucket.bucket:
+ autoclass: []
+ cors: []
+ custom_placement_config: []
+ default_event_based_hold: null
+ effective_labels:
+ goog-terraform-provisioned: 'true'
+ enable_object_retention: null
+ encryption: []
+ force_destroy: false
+ labels: null
+ lifecycle_rule: []
+ location: EU
+ logging: []
+ name: fast2-dev-resman-gcve-0
+ project: fast2-prod-automation
+ requester_pays: null
+ retention_policy: []
+ storage_class: STANDARD
+ terraform_labels:
+ goog-terraform-provisioned: 'true'
+ timeouts: null
+ uniform_bucket_level_access: true
+ versioning:
+ - enabled: true
+ module.stage3-bucket["gcve-dev"].google_storage_bucket_iam_binding.authoritative["roles/storage.objectAdmin"]:
+ bucket: fast2-dev-resman-gcve-0
+ condition: []
+ members:
+ - serviceAccount:fast2-dev-resman-gcve-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/storage.objectAdmin
+ module.stage3-bucket["gcve-dev"].google_storage_bucket_iam_binding.authoritative["roles/storage.objectViewer"]:
+ bucket: fast2-dev-resman-gcve-0
+ condition: []
+ members:
+ - serviceAccount:fast2-dev-resman-gcve-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/storage.objectViewer
+ module.stage3-bucket["gcve-prod"].google_storage_bucket.bucket:
+ autoclass: []
+ cors: []
+ custom_placement_config: []
+ default_event_based_hold: null
+ effective_labels:
+ goog-terraform-provisioned: 'true'
+ enable_object_retention: null
+ encryption: []
+ force_destroy: false
+ labels: null
+ lifecycle_rule: []
+ location: EU
+ logging: []
+ name: fast2-prod-resman-gcve-0
+ project: fast2-prod-automation
+ requester_pays: null
+ retention_policy: []
+ storage_class: STANDARD
+ terraform_labels:
+ goog-terraform-provisioned: 'true'
+ timeouts: null
+ uniform_bucket_level_access: true
+ versioning:
+ - enabled: true
+ module.stage3-bucket["gcve-prod"].google_storage_bucket_iam_binding.authoritative["roles/storage.objectAdmin"]:
+ bucket: fast2-prod-resman-gcve-0
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-gcve-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/storage.objectAdmin
+ module.stage3-bucket["gcve-prod"].google_storage_bucket_iam_binding.authoritative["roles/storage.objectViewer"]:
+ bucket: fast2-prod-resman-gcve-0
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-gcve-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/storage.objectViewer
+ module.stage3-bucket["gke-dev"].google_storage_bucket.bucket:
+ autoclass: []
+ cors: []
+ custom_placement_config: []
+ default_event_based_hold: null
+ effective_labels:
+ goog-terraform-provisioned: 'true'
+ enable_object_retention: null
+ encryption: []
+ force_destroy: false
+ labels: null
+ lifecycle_rule: []
+ location: EU
+ logging: []
+ name: fast2-dev-resman-gke-0
+ project: fast2-prod-automation
+ requester_pays: null
+ retention_policy: []
+ storage_class: STANDARD
+ terraform_labels:
+ goog-terraform-provisioned: 'true'
+ timeouts: null
+ uniform_bucket_level_access: true
+ versioning:
+ - enabled: true
+ module.stage3-bucket["gke-dev"].google_storage_bucket_iam_binding.authoritative["roles/storage.objectAdmin"]:
+ bucket: fast2-dev-resman-gke-0
+ condition: []
+ members:
+ - serviceAccount:fast2-dev-resman-gke-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/storage.objectAdmin
+ module.stage3-bucket["gke-dev"].google_storage_bucket_iam_binding.authoritative["roles/storage.objectViewer"]:
+ bucket: fast2-dev-resman-gke-0
+ condition: []
+ members:
+ - serviceAccount:fast2-dev-resman-gke-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/storage.objectViewer
+ module.stage3-bucket["gke-prod"].google_storage_bucket.bucket:
+ autoclass: []
+ cors: []
+ custom_placement_config: []
+ default_event_based_hold: null
+ effective_labels:
+ goog-terraform-provisioned: 'true'
+ enable_object_retention: null
+ encryption: []
+ force_destroy: false
+ labels: null
+ lifecycle_rule: []
+ location: EU
+ logging: []
+ name: fast2-prod-resman-gke-0
+ project: fast2-prod-automation
+ requester_pays: null
+ retention_policy: []
+ storage_class: STANDARD
+ terraform_labels:
+ goog-terraform-provisioned: 'true'
+ timeouts: null
+ uniform_bucket_level_access: true
+ versioning:
+ - enabled: true
+ module.stage3-bucket["gke-prod"].google_storage_bucket_iam_binding.authoritative["roles/storage.objectAdmin"]:
+ bucket: fast2-prod-resman-gke-0
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-gke-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/storage.objectAdmin
+ module.stage3-bucket["gke-prod"].google_storage_bucket_iam_binding.authoritative["roles/storage.objectViewer"]:
+ bucket: fast2-prod-resman-gke-0
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-gke-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/storage.objectViewer
+ module.stage3-bucket["project-factory-dev"].google_storage_bucket.bucket:
+ autoclass: []
+ cors: []
+ custom_placement_config: []
+ default_event_based_hold: null
+ effective_labels:
+ goog-terraform-provisioned: 'true'
+ enable_object_retention: null
+ encryption: []
+ force_destroy: false
+ labels: null
+ lifecycle_rule: []
+ location: EU
+ logging: []
+ name: fast2-dev-resman-pf-0
+ project: fast2-prod-automation
+ requester_pays: null
+ retention_policy: []
+ storage_class: STANDARD
+ terraform_labels:
+ goog-terraform-provisioned: 'true'
+ timeouts: null
+ uniform_bucket_level_access: true
+ versioning:
+ - enabled: true
+ module.stage3-bucket["project-factory-dev"].google_storage_bucket_iam_binding.authoritative["roles/storage.objectAdmin"]:
+ bucket: fast2-dev-resman-pf-0
+ condition: []
+ members:
+ - serviceAccount:fast2-dev-resman-pf-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/storage.objectAdmin
+ module.stage3-bucket["project-factory-dev"].google_storage_bucket_iam_binding.authoritative["roles/storage.objectViewer"]:
+ bucket: fast2-dev-resman-pf-0
+ condition: []
+ members:
+ - serviceAccount:fast2-dev-resman-pf-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/storage.objectViewer
+ module.stage3-bucket["project-factory-prod"].google_storage_bucket.bucket:
+ autoclass: []
+ cors: []
+ custom_placement_config: []
+ default_event_based_hold: null
+ effective_labels:
+ goog-terraform-provisioned: 'true'
+ enable_object_retention: null
+ encryption: []
+ force_destroy: false
+ labels: null
+ lifecycle_rule: []
+ location: EU
+ logging: []
+ name: fast2-prod-resman-pf-0
+ project: fast2-prod-automation
+ requester_pays: null
+ retention_policy: []
+ storage_class: STANDARD
+ terraform_labels:
+ goog-terraform-provisioned: 'true'
+ timeouts: null
+ uniform_bucket_level_access: true
+ versioning:
+ - enabled: true
+ module.stage3-bucket["project-factory-prod"].google_storage_bucket_iam_binding.authoritative["roles/storage.objectAdmin"]:
+ bucket: fast2-prod-resman-pf-0
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-pf-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/storage.objectAdmin
+ module.stage3-bucket["project-factory-prod"].google_storage_bucket_iam_binding.authoritative["roles/storage.objectViewer"]:
+ bucket: fast2-prod-resman-pf-0
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-pf-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/storage.objectViewer
+ module.stage3-folder["gcve-dev"].google_folder.folder[0]:
+ deletion_protection: false
+ display_name: Development
+ timeouts: null
+ module.stage3-folder["gcve-dev"].google_folder_iam_binding.authoritative["roles/compute.xpnAdmin"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-dev-resman-gcve-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/compute.xpnAdmin
+ module.stage3-folder["gcve-dev"].google_folder_iam_binding.authoritative["roles/logging.admin"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-dev-resman-gcve-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/logging.admin
+ module.stage3-folder["gcve-dev"].google_folder_iam_binding.authoritative["roles/owner"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-dev-resman-gcve-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/owner
+ module.stage3-folder["gcve-dev"].google_folder_iam_binding.authoritative["roles/resourcemanager.folderAdmin"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-dev-resman-gcve-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.folderAdmin
+ module.stage3-folder["gcve-dev"].google_folder_iam_binding.authoritative["roles/resourcemanager.folderViewer"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-dev-resman-gcve-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.folderViewer
+ module.stage3-folder["gcve-dev"].google_folder_iam_binding.authoritative["roles/resourcemanager.projectCreator"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-dev-resman-gcve-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.projectCreator
+ module.stage3-folder["gcve-dev"].google_folder_iam_binding.authoritative["roles/viewer"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-dev-resman-gcve-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/viewer
+ module.stage3-folder["gcve-dev"].google_tags_tag_binding.binding["environment"]:
+ timeouts: null
+ module.stage3-folder["gcve-prod"].google_folder.folder[0]:
+ deletion_protection: false
+ display_name: Production
+ timeouts: null
+ module.stage3-folder["gcve-prod"].google_folder_iam_binding.authoritative["roles/compute.xpnAdmin"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-gcve-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/compute.xpnAdmin
+ module.stage3-folder["gcve-prod"].google_folder_iam_binding.authoritative["roles/logging.admin"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-gcve-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/logging.admin
+ module.stage3-folder["gcve-prod"].google_folder_iam_binding.authoritative["roles/owner"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-gcve-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/owner
+ module.stage3-folder["gcve-prod"].google_folder_iam_binding.authoritative["roles/resourcemanager.folderAdmin"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-gcve-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.folderAdmin
+ module.stage3-folder["gcve-prod"].google_folder_iam_binding.authoritative["roles/resourcemanager.folderViewer"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-gcve-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.folderViewer
+ module.stage3-folder["gcve-prod"].google_folder_iam_binding.authoritative["roles/resourcemanager.projectCreator"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-gcve-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.projectCreator
+ module.stage3-folder["gcve-prod"].google_folder_iam_binding.authoritative["roles/viewer"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-gcve-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/viewer
+ module.stage3-folder["gcve-prod"].google_tags_tag_binding.binding["environment"]:
+ timeouts: null
+ module.stage3-folder["gke-dev"].google_folder.folder[0]:
+ deletion_protection: false
+ display_name: Development
+ timeouts: null
+ module.stage3-folder["gke-dev"].google_folder_iam_binding.authoritative["roles/compute.xpnAdmin"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-dev-resman-gke-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/compute.xpnAdmin
+ module.stage3-folder["gke-dev"].google_folder_iam_binding.authoritative["roles/logging.admin"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-dev-resman-gke-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/logging.admin
+ module.stage3-folder["gke-dev"].google_folder_iam_binding.authoritative["roles/owner"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-dev-resman-gke-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/owner
+ module.stage3-folder["gke-dev"].google_folder_iam_binding.authoritative["roles/resourcemanager.folderAdmin"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-dev-resman-gke-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.folderAdmin
+ module.stage3-folder["gke-dev"].google_folder_iam_binding.authoritative["roles/resourcemanager.folderViewer"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-dev-resman-gke-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.folderViewer
+ module.stage3-folder["gke-dev"].google_folder_iam_binding.authoritative["roles/resourcemanager.projectCreator"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-dev-resman-gke-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.projectCreator
+ module.stage3-folder["gke-dev"].google_folder_iam_binding.authoritative["roles/viewer"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-dev-resman-gke-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/viewer
+ module.stage3-folder["gke-dev"].google_tags_tag_binding.binding["environment"]:
+ timeouts: null
+ module.stage3-folder["gke-prod"].google_folder.folder[0]:
+ deletion_protection: false
+ display_name: Production
+ timeouts: null
+ module.stage3-folder["gke-prod"].google_folder_iam_binding.authoritative["roles/compute.xpnAdmin"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-gke-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/compute.xpnAdmin
+ module.stage3-folder["gke-prod"].google_folder_iam_binding.authoritative["roles/logging.admin"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-gke-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/logging.admin
+ module.stage3-folder["gke-prod"].google_folder_iam_binding.authoritative["roles/owner"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-gke-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/owner
+ module.stage3-folder["gke-prod"].google_folder_iam_binding.authoritative["roles/resourcemanager.folderAdmin"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-gke-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.folderAdmin
+ module.stage3-folder["gke-prod"].google_folder_iam_binding.authoritative["roles/resourcemanager.folderViewer"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-gke-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.folderViewer
+ module.stage3-folder["gke-prod"].google_folder_iam_binding.authoritative["roles/resourcemanager.projectCreator"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-gke-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.projectCreator
+ module.stage3-folder["gke-prod"].google_folder_iam_binding.authoritative["roles/viewer"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-gke-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/viewer
+ module.stage3-folder["gke-prod"].google_tags_tag_binding.binding["environment"]:
+ timeouts: null
+ ? module.stage3-sa-ro["gcve-dev"].google_project_iam_member.project-roles["fast2-prod-automation-roles/serviceusage.serviceUsageConsumer"]
+ : condition: []
+ project: fast2-prod-automation
+ role: roles/serviceusage.serviceUsageConsumer
+ module.stage3-sa-ro["gcve-dev"].google_service_account.service_account[0]:
+ account_id: fast2-dev-resman-gcve-0r
+ create_ignore_already_exists: null
+ description: null
+ disabled: false
+ display_name: Terraform resman gcve-dev service account (read-only).
+ project: fast2-prod-automation
+ timeouts: null
+ module.stage3-sa-ro["gcve-dev"].google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
+ condition: []
+ members: null
+ role: roles/iam.serviceAccountTokenCreator
+ ? module.stage3-sa-ro["gcve-dev"].google_storage_bucket_iam_member.bucket-roles["fast2-prod-iac-core-outputs-organizations/123456789012/roles/storageViewer"]
+ : bucket: fast2-prod-iac-core-outputs
+ condition: []
+ role: organizations/123456789012/roles/storageViewer
+ ? module.stage3-sa-ro["gcve-prod"].google_project_iam_member.project-roles["fast2-prod-automation-roles/serviceusage.serviceUsageConsumer"]
+ : condition: []
+ project: fast2-prod-automation
+ role: roles/serviceusage.serviceUsageConsumer
+ module.stage3-sa-ro["gcve-prod"].google_service_account.service_account[0]:
+ account_id: fast2-prod-resman-gcve-0r
+ create_ignore_already_exists: null
+ description: null
+ disabled: false
+ display_name: Terraform resman gcve-prod service account (read-only).
+ project: fast2-prod-automation
+ timeouts: null
+ module.stage3-sa-ro["gcve-prod"].google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
+ condition: []
+ members: null
+ role: roles/iam.serviceAccountTokenCreator
+ ? module.stage3-sa-ro["gcve-prod"].google_storage_bucket_iam_member.bucket-roles["fast2-prod-iac-core-outputs-organizations/123456789012/roles/storageViewer"]
+ : bucket: fast2-prod-iac-core-outputs
+ condition: []
+ role: organizations/123456789012/roles/storageViewer
+ ? module.stage3-sa-ro["gke-dev"].google_project_iam_member.project-roles["fast2-prod-automation-roles/serviceusage.serviceUsageConsumer"]
+ : condition: []
+ project: fast2-prod-automation
+ role: roles/serviceusage.serviceUsageConsumer
+ module.stage3-sa-ro["gke-dev"].google_service_account.service_account[0]:
+ account_id: fast2-dev-resman-gke-0r
+ create_ignore_already_exists: null
+ description: null
+ disabled: false
+ display_name: Terraform resman gke-dev service account (read-only).
+ project: fast2-prod-automation
+ timeouts: null
+ module.stage3-sa-ro["gke-dev"].google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
+ condition: []
+ members: null
+ role: roles/iam.serviceAccountTokenCreator
+ ? module.stage3-sa-ro["gke-dev"].google_storage_bucket_iam_member.bucket-roles["fast2-prod-iac-core-outputs-organizations/123456789012/roles/storageViewer"]
+ : bucket: fast2-prod-iac-core-outputs
+ condition: []
+ role: organizations/123456789012/roles/storageViewer
+ ? module.stage3-sa-ro["gke-prod"].google_project_iam_member.project-roles["fast2-prod-automation-roles/serviceusage.serviceUsageConsumer"]
+ : condition: []
+ project: fast2-prod-automation
+ role: roles/serviceusage.serviceUsageConsumer
+ module.stage3-sa-ro["gke-prod"].google_service_account.service_account[0]:
+ account_id: fast2-prod-resman-gke-0r
+ create_ignore_already_exists: null
+ description: null
+ disabled: false
+ display_name: Terraform resman gke-prod service account (read-only).
+ project: fast2-prod-automation
+ timeouts: null
+ module.stage3-sa-ro["gke-prod"].google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
+ condition: []
+ members: null
+ role: roles/iam.serviceAccountTokenCreator
+ ? module.stage3-sa-ro["gke-prod"].google_storage_bucket_iam_member.bucket-roles["fast2-prod-iac-core-outputs-organizations/123456789012/roles/storageViewer"]
+ : bucket: fast2-prod-iac-core-outputs
+ condition: []
+ role: organizations/123456789012/roles/storageViewer
+ ? module.stage3-sa-ro["project-factory-dev"].google_project_iam_member.project-roles["fast2-prod-automation-roles/serviceusage.serviceUsageConsumer"]
+ : condition: []
+ project: fast2-prod-automation
+ role: roles/serviceusage.serviceUsageConsumer
+ module.stage3-sa-ro["project-factory-dev"].google_service_account.service_account[0]:
+ account_id: fast2-dev-resman-pf-0r
+ create_ignore_already_exists: null
+ description: null
+ disabled: false
+ display_name: Terraform resman project-factory-dev service account (read-only).
+ project: fast2-prod-automation
+ timeouts: null
+ ? module.stage3-sa-ro["project-factory-dev"].google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]
+ : condition: []
+ members: null
+ role: roles/iam.serviceAccountTokenCreator
+ ? module.stage3-sa-ro["project-factory-dev"].google_storage_bucket_iam_member.bucket-roles["fast2-prod-iac-core-outputs-organizations/123456789012/roles/storageViewer"]
+ : bucket: fast2-prod-iac-core-outputs
+ condition: []
+ role: organizations/123456789012/roles/storageViewer
+ ? module.stage3-sa-ro["project-factory-prod"].google_project_iam_member.project-roles["fast2-prod-automation-roles/serviceusage.serviceUsageConsumer"]
+ : condition: []
+ project: fast2-prod-automation
+ role: roles/serviceusage.serviceUsageConsumer
+ module.stage3-sa-ro["project-factory-prod"].google_service_account.service_account[0]:
+ account_id: fast2-prod-resman-pf-0r
+ create_ignore_already_exists: null
+ description: null
+ disabled: false
+ display_name: Terraform resman project-factory-prod service account (read-only).
+ project: fast2-prod-automation
+ timeouts: null
+ ? module.stage3-sa-ro["project-factory-prod"].google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]
+ : condition: []
+ members: null
+ role: roles/iam.serviceAccountTokenCreator
+ ? module.stage3-sa-ro["project-factory-prod"].google_storage_bucket_iam_member.bucket-roles["fast2-prod-iac-core-outputs-organizations/123456789012/roles/storageViewer"]
+ : bucket: fast2-prod-iac-core-outputs
+ condition: []
+ role: organizations/123456789012/roles/storageViewer
+ ? module.stage3-sa-rw["gcve-dev"].google_project_iam_member.project-roles["fast2-prod-automation-roles/serviceusage.serviceUsageConsumer"]
+ : condition: []
+ project: fast2-prod-automation
+ role: roles/serviceusage.serviceUsageConsumer
+ module.stage3-sa-rw["gcve-dev"].google_service_account.service_account[0]:
+ account_id: fast2-dev-resman-gcve-0
+ create_ignore_already_exists: null
+ description: null
+ disabled: false
+ display_name: Terraform resman gcve-dev service account.
+ project: fast2-prod-automation
+ timeouts: null
+ module.stage3-sa-rw["gcve-dev"].google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
+ condition: []
+ members: null
+ role: roles/iam.serviceAccountTokenCreator
+ ? module.stage3-sa-rw["gcve-dev"].google_storage_bucket_iam_member.bucket-roles["fast2-prod-iac-core-outputs-roles/storage.objectAdmin"]
+ : bucket: fast2-prod-iac-core-outputs
+ condition: []
+ role: roles/storage.objectAdmin
+ ? module.stage3-sa-rw["gcve-prod"].google_project_iam_member.project-roles["fast2-prod-automation-roles/serviceusage.serviceUsageConsumer"]
+ : condition: []
+ project: fast2-prod-automation
+ role: roles/serviceusage.serviceUsageConsumer
+ module.stage3-sa-rw["gcve-prod"].google_service_account.service_account[0]:
+ account_id: fast2-prod-resman-gcve-0
+ create_ignore_already_exists: null
+ description: null
+ disabled: false
+ display_name: Terraform resman gcve-prod service account.
+ project: fast2-prod-automation
+ timeouts: null
+ module.stage3-sa-rw["gcve-prod"].google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
+ condition: []
+ members: null
+ role: roles/iam.serviceAccountTokenCreator
+ ? module.stage3-sa-rw["gcve-prod"].google_storage_bucket_iam_member.bucket-roles["fast2-prod-iac-core-outputs-roles/storage.objectAdmin"]
+ : bucket: fast2-prod-iac-core-outputs
+ condition: []
+ role: roles/storage.objectAdmin
+ ? module.stage3-sa-rw["gke-dev"].google_project_iam_member.project-roles["fast2-prod-automation-roles/serviceusage.serviceUsageConsumer"]
+ : condition: []
+ project: fast2-prod-automation
+ role: roles/serviceusage.serviceUsageConsumer
+ module.stage3-sa-rw["gke-dev"].google_service_account.service_account[0]:
+ account_id: fast2-dev-resman-gke-0
+ create_ignore_already_exists: null
+ description: null
+ disabled: false
+ display_name: Terraform resman gke-dev service account.
+ project: fast2-prod-automation
+ timeouts: null
+ module.stage3-sa-rw["gke-dev"].google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
+ condition: []
+ members: null
+ role: roles/iam.serviceAccountTokenCreator
+ ? module.stage3-sa-rw["gke-dev"].google_storage_bucket_iam_member.bucket-roles["fast2-prod-iac-core-outputs-roles/storage.objectAdmin"]
+ : bucket: fast2-prod-iac-core-outputs
+ condition: []
+ role: roles/storage.objectAdmin
+ ? module.stage3-sa-rw["gke-prod"].google_project_iam_member.project-roles["fast2-prod-automation-roles/serviceusage.serviceUsageConsumer"]
+ : condition: []
+ project: fast2-prod-automation
+ role: roles/serviceusage.serviceUsageConsumer
+ module.stage3-sa-rw["gke-prod"].google_service_account.service_account[0]:
+ account_id: fast2-prod-resman-gke-0
+ create_ignore_already_exists: null
+ description: null
+ disabled: false
+ display_name: Terraform resman gke-prod service account.
+ project: fast2-prod-automation
+ timeouts: null
+ module.stage3-sa-rw["gke-prod"].google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
+ condition: []
+ members: null
+ role: roles/iam.serviceAccountTokenCreator
+ ? module.stage3-sa-rw["gke-prod"].google_storage_bucket_iam_member.bucket-roles["fast2-prod-iac-core-outputs-roles/storage.objectAdmin"]
+ : bucket: fast2-prod-iac-core-outputs
+ condition: []
+ role: roles/storage.objectAdmin
+ ? module.stage3-sa-rw["project-factory-dev"].google_project_iam_member.project-roles["fast2-prod-automation-roles/serviceusage.serviceUsageConsumer"]
+ : condition: []
+ project: fast2-prod-automation
+ role: roles/serviceusage.serviceUsageConsumer
+ module.stage3-sa-rw["project-factory-dev"].google_service_account.service_account[0]:
+ account_id: fast2-dev-resman-pf-0
+ create_ignore_already_exists: null
+ description: null
+ disabled: false
+ display_name: Terraform resman project-factory-dev service account.
+ project: fast2-prod-automation
+ timeouts: null
+ ? module.stage3-sa-rw["project-factory-dev"].google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]
+ : condition: []
+ members: null
+ role: roles/iam.serviceAccountTokenCreator
+ ? module.stage3-sa-rw["project-factory-dev"].google_storage_bucket_iam_member.bucket-roles["fast2-prod-iac-core-outputs-roles/storage.objectAdmin"]
+ : bucket: fast2-prod-iac-core-outputs
+ condition: []
+ role: roles/storage.objectAdmin
+ ? module.stage3-sa-rw["project-factory-prod"].google_project_iam_member.project-roles["fast2-prod-automation-roles/serviceusage.serviceUsageConsumer"]
+ : condition: []
+ project: fast2-prod-automation
+ role: roles/serviceusage.serviceUsageConsumer
+ module.stage3-sa-rw["project-factory-prod"].google_service_account.service_account[0]:
+ account_id: fast2-prod-resman-pf-0
+ create_ignore_already_exists: null
+ description: null
+ disabled: false
+ display_name: Terraform resman project-factory-prod service account.
+ project: fast2-prod-automation
+ timeouts: null
+ ? module.stage3-sa-rw["project-factory-prod"].google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]
+ : condition: []
+ members: null
+ role: roles/iam.serviceAccountTokenCreator
+ ? module.stage3-sa-rw["project-factory-prod"].google_storage_bucket_iam_member.bucket-roles["fast2-prod-iac-core-outputs-roles/storage.objectAdmin"]
+ : bucket: fast2-prod-iac-core-outputs
+ condition: []
+ role: roles/storage.objectAdmin
+ module.top-level-bucket["sandbox"].google_storage_bucket.bucket:
+ autoclass: []
+ cors: []
+ custom_placement_config: []
+ default_event_based_hold: null
+ effective_labels:
+ goog-terraform-provisioned: 'true'
+ enable_object_retention: null
+ encryption: []
+ force_destroy: false
+ labels: null
+ lifecycle_rule: []
+ location: EU
+ logging: []
+ name: fast2-dev-resman-sbox-0
+ project: fast2-prod-automation
+ requester_pays: null
+ retention_policy: []
+ storage_class: STANDARD
+ terraform_labels:
+ goog-terraform-provisioned: 'true'
+ timeouts: null
+ uniform_bucket_level_access: true
+ versioning:
+ - enabled: true
+ module.top-level-bucket["sandbox"].google_storage_bucket_iam_binding.authoritative["roles/storage.objectAdmin"]:
+ bucket: fast2-dev-resman-sbox-0
+ condition: []
+ members:
+ - serviceAccount:fast2-dev-resman-sbox-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/storage.objectAdmin
+ module.top-level-bucket["sandbox"].google_storage_bucket_iam_binding.authoritative["roles/storage.objectViewer"]:
+ bucket: fast2-dev-resman-sbox-0
+ condition: []
+ members:
+ - serviceAccount:fast2-dev-resman-sbox-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/storage.objectViewer
+ module.top-level-bucket["tenants"].google_storage_bucket.bucket:
+ autoclass: []
+ cors: []
+ custom_placement_config: []
+ default_event_based_hold: null
+ effective_labels:
+ goog-terraform-provisioned: 'true'
+ enable_object_retention: null
+ encryption: []
+ force_destroy: false
+ labels: null
+ lifecycle_rule: []
+ location: EU
+ logging: []
+ name: fast2-prod-resman-tenants-0
+ project: fast2-prod-automation
+ requester_pays: null
+ retention_policy: []
+ storage_class: STANDARD
+ terraform_labels:
+ goog-terraform-provisioned: 'true'
+ timeouts: null
+ uniform_bucket_level_access: true
+ versioning:
+ - enabled: true
+ module.top-level-bucket["tenants"].google_storage_bucket_iam_binding.authoritative["roles/storage.objectAdmin"]:
+ bucket: fast2-prod-resman-tenants-0
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-tenants-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/storage.objectAdmin
+ module.top-level-bucket["tenants"].google_storage_bucket_iam_binding.authoritative["roles/storage.objectViewer"]:
+ bucket: fast2-prod-resman-tenants-0
+ condition: []
+ members:
+ - serviceAccount:fast2-prod-resman-tenants-0@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/storage.objectViewer
+ module.top-level-folder["gcve"].google_folder.folder[0]:
+ deletion_protection: false
+ display_name: GCVE
+ parent: organizations/123456789012
+ timeouts: null
+ module.top-level-folder["gcve"].google_tags_tag_binding.binding["context"]:
+ timeouts: null
+ module.top-level-folder["gke"].google_folder.folder[0]:
+ deletion_protection: false
+ display_name: GKE
+ parent: organizations/123456789012
+ timeouts: null
+ module.top-level-folder["gke"].google_tags_tag_binding.binding["context"]:
+ timeouts: null
+ module.top-level-folder["sandbox"].google_folder.folder[0]:
+ deletion_protection: false
+ display_name: Sandbox
+ parent: organizations/123456789012
+ module.top-level-folder["sandbox"].google_org_policy_policy.default["compute.vmExternalIpAccess"]:
+ dry_run_spec: []
+ spec:
+ - inherit_from_parent: null
+ reset: null
+ rules:
+ - allow_all: 'TRUE'
+ condition: []
+ deny_all: null
+ enforce: null
+ values: []
+ timeouts: null
+ module.top-level-folder["sandbox"].google_org_policy_policy.default["sql.restrictPublicIp"]:
+ dry_run_spec: []
+ spec:
+ - inherit_from_parent: null
+ reset: null
+ rules:
+ - allow_all: null
+ condition: []
+ deny_all: null
+ enforce: 'TRUE'
+ values: []
+ timeouts: null
+ module.top-level-folder["sandbox"].google_tags_tag_binding.binding["context"]:
+ timeouts: null
module.top-level-folder["teams"].google_folder.folder[0]:
+ deletion_protection: false
display_name: Teams
parent: organizations/123456789012
timeouts: null
? module.top-level-folder["teams"].google_folder_iam_binding.authoritative["organizations/123456789012/roles/xpnServiceAdmin"]
: condition: []
members:
- - serviceAccount:fast2-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
+ - serviceAccount:fast2-resman-pf-0@fast2-prod-automation.iam.gserviceaccount.com
role: organizations/123456789012/roles/xpnServiceAdmin
module.top-level-folder["teams"].google_folder_iam_binding.authoritative["roles/owner"]:
condition: []
members:
- - serviceAccount:fast2-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
+ - serviceAccount:fast2-resman-pf-0@fast2-prod-automation.iam.gserviceaccount.com
role: roles/owner
module.top-level-folder["teams"].google_folder_iam_binding.authoritative["roles/resourcemanager.folderAdmin"]:
condition: []
members:
- - serviceAccount:fast2-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
+ - serviceAccount:fast2-resman-pf-0@fast2-prod-automation.iam.gserviceaccount.com
role: roles/resourcemanager.folderAdmin
+ module.top-level-folder["teams"].google_folder_iam_binding.authoritative["roles/resourcemanager.folderViewer"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-resman-pf-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.folderViewer
module.top-level-folder["teams"].google_folder_iam_binding.authoritative["roles/resourcemanager.projectCreator"]:
condition: []
members:
- - serviceAccount:fast2-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
+ - serviceAccount:fast2-resman-pf-0@fast2-prod-automation.iam.gserviceaccount.com
role: roles/resourcemanager.projectCreator
module.top-level-folder["teams"].google_folder_iam_binding.authoritative["roles/resourcemanager.tagUser"]:
condition: []
members:
- - serviceAccount:fast2-resman-pf-0@fast-prod-automation.iam.gserviceaccount.com
+ - serviceAccount:fast2-resman-pf-0@fast2-prod-automation.iam.gserviceaccount.com
role: roles/resourcemanager.tagUser
+ module.top-level-folder["teams"].google_folder_iam_binding.authoritative["roles/resourcemanager.tagViewer"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-resman-pf-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/resourcemanager.tagViewer
+ module.top-level-folder["teams"].google_folder_iam_binding.authoritative["roles/viewer"]:
+ condition: []
+ members:
+ - serviceAccount:fast2-resman-pf-0r@fast2-prod-automation.iam.gserviceaccount.com
+ role: roles/viewer
module.top-level-folder["teams"].google_tags_tag_binding.binding["context"]:
timeouts: null
+ module.top-level-folder["tenants"].google_folder.folder[0]:
+ deletion_protection: false
+ display_name: Tenants
+ parent: organizations/123456789012
+ timeouts: null
+ module.top-level-folder["tenants"].google_tags_tag_binding.binding["context"]:
+ timeouts: null
+ ? module.top-level-sa["sandbox"].google_project_iam_member.project-roles["fast2-prod-automation-roles/serviceusage.serviceUsageConsumer"]
+ : condition: []
+ project: fast2-prod-automation
+ role: roles/serviceusage.serviceUsageConsumer
+ module.top-level-sa["sandbox"].google_service_account.service_account[0]:
+ account_id: fast2-dev-resman-sbox-0
+ create_ignore_already_exists: null
+ description: null
+ disabled: false
+ display_name: Terraform resman sandbox folder service account.
+ project: fast2-prod-automation
+ timeouts: null
+ module.top-level-sa["sandbox"].google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
+ condition: []
+ members: null
+ role: roles/iam.serviceAccountTokenCreator
+ ? module.top-level-sa["sandbox"].google_storage_bucket_iam_member.bucket-roles["fast2-prod-iac-core-outputs-roles/storage.objectAdmin"]
+ : bucket: fast2-prod-iac-core-outputs
+ condition: []
+ role: roles/storage.objectAdmin
+ ? module.top-level-sa["tenants"].google_project_iam_member.project-roles["fast2-prod-automation-roles/serviceusage.serviceUsageConsumer"]
+ : condition: []
+ project: fast2-prod-automation
+ role: roles/serviceusage.serviceUsageConsumer
+ module.top-level-sa["tenants"].google_service_account.service_account[0]:
+ account_id: fast2-prod-resman-tenants-0
+ create_ignore_already_exists: null
+ description: null
+ disabled: false
+ display_name: Terraform resman tenants folder service account.
+ project: fast2-prod-automation
+ timeouts: null
+ module.top-level-sa["tenants"].google_service_account_iam_binding.authoritative["roles/iam.serviceAccountTokenCreator"]:
+ condition: []
+ members: null
+ role: roles/iam.serviceAccountTokenCreator
+ ? module.top-level-sa["tenants"].google_storage_bucket_iam_member.bucket-roles["fast2-prod-iac-core-outputs-roles/storage.objectAdmin"]
+ : bucket: fast2-prod-iac-core-outputs
+ condition: []
+ role: roles/storage.objectAdmin
counts:
- google_folder: 5
- google_folder_iam_binding: 29
- google_organization_iam_member: 14
- google_project_iam_member: 10
- google_service_account: 10
- google_service_account_iam_binding: 10
- google_storage_bucket: 5
- google_storage_bucket_iam_binding: 10
- google_storage_bucket_iam_member: 10
- google_storage_bucket_object: 11
- google_tags_tag_binding: 5
+ google_folder: 13
+ google_folder_iam_binding: 75
+ google_org_policy_policy: 2
+ google_organization_iam_member: 19
+ google_project_iam_member: 26
+ google_service_account: 26
+ google_service_account_iam_binding: 26
+ google_storage_bucket: 12
+ google_storage_bucket_iam_binding: 24
+ google_storage_bucket_iam_member: 26
+ google_storage_bucket_object: 25
+ google_tags_tag_binding: 13
google_tags_tag_key: 2
- google_tags_tag_value: 9
- google_tags_tag_value_iam_binding: 2
- modules: 21
- resources: 132
+ google_tags_tag_value: 12
+ google_tags_tag_value_iam_binding: 4
+ modules: 52
+ resources: 305
+
+outputs:
+ cicd_repositories:
+ networking:
+ provider: projects/1234567890/locations/global/workloadIdentityPools/ldj-bootstrap/providers/ldj-bootstrap-github-ludomagno
+ repository:
+ branch: main
+ name: test/00-networking
+ parent_id: null
+ type: github
+ security:
+ provider: projects/1234567890/locations/global/workloadIdentityPools/ldj-bootstrap/providers/ldj-bootstrap-gitlab-ludomagno
+ repository:
+ branch: null
+ name: test/00-security
+ type: gitlab
+ folder_ids: __missing__
+ tfvars: __missing__
diff --git a/tests/fast/stages/s1_resman/tftest.yaml b/tests/fast/stages/s1_resman/tftest.yaml
index 2bdff45ff..c09a159a6 100644
--- a/tests/fast/stages/s1_resman/tftest.yaml
+++ b/tests/fast/stages/s1_resman/tftest.yaml
@@ -15,7 +15,4 @@
module: fast/stages/1-resman
tests:
- checklist:
- extra_files:
- - ../../../tests/fast/stages/s0_bootstrap/data/checklist-data.json
simple:
diff --git a/tests/fast/stages/s1_tenant_factory/simple.yaml b/tests/fast/stages/s1_tenant_factory/simple.yaml
index dfcc464f5..ce130cbb6 100644
--- a/tests/fast/stages/s1_tenant_factory/simple.yaml
+++ b/tests/fast/stages/s1_tenant_factory/simple.yaml
@@ -14,7 +14,7 @@
counts:
google_access_context_manager_access_policy: 2
- google_access_context_manager_access_policy_iam_member: 7
+ google_access_context_manager_access_policy_iam_member: 5
google_bigquery_default_service_account: 4
google_essential_contacts_contact: 2
google_folder: 8
@@ -23,7 +23,7 @@ counts:
google_iam_workload_identity_pool_provider: 1
google_logging_folder_sink: 4
google_logging_project_bucket_config: 4
- google_org_policy_policy: 3
+ google_org_policy_policy: 6
google_organization_iam_member: 6
google_project: 6
google_project_iam_audit_config: 2
@@ -43,4 +43,4 @@ counts:
google_tags_tag_key: 1
google_tags_tag_value: 4
modules: 50
- resources: 290
+ resources: 291
diff --git a/tests/fast/stages/s3_network_security/__init__.py b/tests/fast/stages/s2_network_security/__init__.py
similarity index 100%
rename from tests/fast/stages/s3_network_security/__init__.py
rename to tests/fast/stages/s2_network_security/__init__.py
diff --git a/tests/fast/stages/s3_network_security/simple.tfvars b/tests/fast/stages/s2_network_security/simple.tfvars
similarity index 93%
rename from tests/fast/stages/s3_network_security/simple.tfvars
rename to tests/fast/stages/s2_network_security/simple.tfvars
index f713e5af7..1ab02d8d2 100644
--- a/tests/fast/stages/s3_network_security/simple.tfvars
+++ b/tests/fast/stages/s2_network_security/simple.tfvars
@@ -1,3 +1,6 @@
+automation = {
+ outputs_bucket = "test"
+}
billing_account = {
id = "000000-111111-222222"
}
diff --git a/tests/fast/stages/s3_network_security/simple.yaml b/tests/fast/stages/s2_network_security/simple.yaml
similarity index 95%
rename from tests/fast/stages/s3_network_security/simple.yaml
rename to tests/fast/stages/s2_network_security/simple.yaml
index 4deac063d..c0ff76a2d 100644
--- a/tests/fast/stages/s3_network_security/simple.yaml
+++ b/tests/fast/stages/s2_network_security/simple.yaml
@@ -23,5 +23,6 @@ counts:
google_project: 1
google_project_service: 1
google_project_service_identity: 1
+ google_storage_bucket_object: 1
modules: 3
- resources: 24
+ resources: 25
diff --git a/tests/fast/stages/s3_network_security/tftest.yaml b/tests/fast/stages/s2_network_security/tftest.yaml
similarity index 93%
rename from tests/fast/stages/s3_network_security/tftest.yaml
rename to tests/fast/stages/s2_network_security/tftest.yaml
index 5f6eafbb3..05246b4eb 100644
--- a/tests/fast/stages/s3_network_security/tftest.yaml
+++ b/tests/fast/stages/s2_network_security/tftest.yaml
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-module: fast/stages/3-network-security/
+module: fast/stages/2-network-security/
tests:
simple:
diff --git a/tests/fast/stages/s3_network_security/tls.tfvars b/tests/fast/stages/s2_network_security/tls.tfvars
similarity index 96%
rename from tests/fast/stages/s3_network_security/tls.tfvars
rename to tests/fast/stages/s2_network_security/tls.tfvars
index 72f88d660..ecd91f565 100644
--- a/tests/fast/stages/s3_network_security/tls.tfvars
+++ b/tests/fast/stages/s2_network_security/tls.tfvars
@@ -1,3 +1,6 @@
+automation = {
+ outputs_bucket = "test"
+}
billing_account = {
id = "000000-111111-222222"
}
diff --git a/tests/fast/stages/s3_network_security/tls.yaml b/tests/fast/stages/s2_network_security/tls.yaml
similarity index 90%
rename from tests/fast/stages/s3_network_security/tls.yaml
rename to tests/fast/stages/s2_network_security/tls.yaml
index 83431eac8..8c6e0a93d 100644
--- a/tests/fast/stages/s3_network_security/tls.yaml
+++ b/tests/fast/stages/s2_network_security/tls.yaml
@@ -34,7 +34,7 @@ values:
name: fast2-ngfw-endpoint-europe-west1-d
parent: organizations/123456789012
timeouts: null
- google_network_security_firewall_endpoint_association.dev_fw_ep_association["europe-west1-b"]:
+ google_network_security_firewall_endpoint_association.dev["europe-west1-b"]:
disabled: false
labels: null
location: europe-west1-b
@@ -43,7 +43,7 @@ values:
parent: projects/dev-project
timeouts: null
tls_inspection_policy: projects/project1/locations/europe-west1/tlsInspectionPolicies/dev-tls-ip-0
- google_network_security_firewall_endpoint_association.dev_fw_ep_association["europe-west1-c"]:
+ google_network_security_firewall_endpoint_association.dev["europe-west1-c"]:
disabled: false
labels: null
location: europe-west1-c
@@ -52,7 +52,7 @@ values:
parent: projects/dev-project
timeouts: null
tls_inspection_policy: projects/project1/locations/europe-west1/tlsInspectionPolicies/dev-tls-ip-0
- google_network_security_firewall_endpoint_association.dev_fw_ep_association["europe-west1-d"]:
+ google_network_security_firewall_endpoint_association.dev["europe-west1-d"]:
disabled: false
labels: null
location: europe-west1-d
@@ -61,7 +61,7 @@ values:
parent: projects/dev-project
timeouts: null
tls_inspection_policy: projects/project1/locations/europe-west1/tlsInspectionPolicies/dev-tls-ip-0
- google_network_security_firewall_endpoint_association.prod_fw_ep_association["europe-west1-b"]:
+ google_network_security_firewall_endpoint_association.prod["europe-west1-b"]:
disabled: false
labels: null
location: europe-west1-b
@@ -70,7 +70,7 @@ values:
parent: projects/prod-project
timeouts: null
tls_inspection_policy: projects/project1/locations/europe-west1/tlsInspectionPolicies/prod-tls-ip-0
- google_network_security_firewall_endpoint_association.prod_fw_ep_association["europe-west1-c"]:
+ google_network_security_firewall_endpoint_association.prod["europe-west1-c"]:
disabled: false
labels: null
location: europe-west1-c
@@ -79,7 +79,7 @@ values:
parent: projects/prod-project
timeouts: null
tls_inspection_policy: projects/project1/locations/europe-west1/tlsInspectionPolicies/prod-tls-ip-0
- google_network_security_firewall_endpoint_association.prod_fw_ep_association["europe-west1-d"]:
+ google_network_security_firewall_endpoint_association.prod["europe-west1-d"]:
disabled: false
labels: null
location: europe-west1-d
@@ -88,7 +88,7 @@ values:
parent: projects/prod-project
timeouts: null
tls_inspection_policy: projects/project1/locations/europe-west1/tlsInspectionPolicies/prod-tls-ip-0
- google_network_security_security_profile.dev_sec_profile:
+ google_network_security_security_profile.dev:
description: null
labels: null
location: global
@@ -97,7 +97,7 @@ values:
threat_prevention_profile: []
timeouts: null
type: THREAT_PREVENTION
- google_network_security_security_profile.prod_sec_profile:
+ google_network_security_security_profile.prod:
description: null
labels: null
location: global
@@ -106,20 +106,35 @@ values:
threat_prevention_profile: []
timeouts: null
type: THREAT_PREVENTION
- google_network_security_security_profile_group.dev_sec_profile_group:
+ google_network_security_security_profile_group.dev:
description: Dev security profile group.
labels: null
location: global
name: fast2-dev-spg-0
parent: organizations/123456789012
timeouts: null
- google_network_security_security_profile_group.prod_sec_profile_group:
+ google_network_security_security_profile_group.prod:
description: prod security profile group.
labels: null
location: global
name: fast2-prod-spg-0
parent: organizations/123456789012
timeouts: null
+ google_storage_bucket_object.tfvars:
+ bucket: test
+ cache_control: null
+ content_disposition: null
+ content_encoding: null
+ content_language: null
+ customer_encryption: []
+ detect_md5hash: different hash
+ event_based_hold: null
+ metadata: null
+ name: tfvars/2-nsec.auto.tfvars.json
+ retention: []
+ source: null
+ temporary_hold: null
+ timeouts: null
module.dev-spoke-firewall-policy.google_compute_network_firewall_policy.net-global[0]:
description: null
name: fast2-dev-fw-policy
@@ -300,8 +315,9 @@ counts:
google_project: 1
google_project_service: 1
google_project_service_identity: 1
+ google_storage_bucket_object: 1
modules: 3
- resources: 24
+ resources: 25
outputs:
ngfw_enterprise_endpoint_ids: __missing__
diff --git a/tests/fast/stages/s2_networking_a_simple/ncc.tfvars b/tests/fast/stages/s2_networking_a_simple/ncc.tfvars
index 0ef78ea33..ff17f1035 100644
--- a/tests/fast/stages/s2_networking_a_simple/ncc.tfvars
+++ b/tests/fast/stages/s2_networking_a_simple/ncc.tfvars
@@ -5,16 +5,29 @@ billing_account = {
id = "000000-111111-222222"
}
custom_roles = {
+ project_iam_viewer = "organizations/123456789012/roles/bar"
service_project_network_admin = "organizations/123456789012/roles/foo"
}
dns = {
resolvers = ["10.10.10.10"]
enable_logging = true
}
-enable_cloud_nat = true
+enable_cloud_nat = true
+environments = {
+ dev = {
+ is_default = false
+ name = "Development"
+ tag_name = "development"
+ }
+ prod = {
+ is_default = true
+ name = "Production"
+ tag_name = "production"
+ }
+}
essential_contacts = "gcp-network-admins@fast.example.com"
folder_ids = {
- networking = null
+ networking = "folders/12345"
networking-dev = null
networking-prod = null
}
@@ -39,3 +52,7 @@ service_accounts = {
spoke_configs = {
ncc_configs = {}
}
+tag_values = {
+ "environment/development" = "tagValues/12345"
+ "environment/production" = "tagValues/12346"
+}
diff --git a/tests/fast/stages/s2_networking_a_simple/ncc.yaml b/tests/fast/stages/s2_networking_a_simple/ncc.yaml
index d5187b444..65630a089 100644
--- a/tests/fast/stages/s2_networking_a_simple/ncc.yaml
+++ b/tests/fast/stages/s2_networking_a_simple/ncc.yaml
@@ -29,18 +29,18 @@ counts:
google_dns_response_policy: 1
google_dns_response_policy_rule: 39
google_essential_contacts_contact: 1
- google_folder: 1
google_monitoring_alert_policy: 2
google_monitoring_dashboard: 3
google_monitoring_monitored_project: 2
google_network_connectivity_hub: 1
google_network_connectivity_spoke: 2
google_project: 3
- google_project_iam_binding: 4
- google_project_iam_member: 18
- google_project_service: 24
- google_project_service_identity: 18
+ google_project_iam_binding: 2
+ google_project_iam_member: 20
+ google_project_service: 26
+ google_project_service_identity: 20
google_storage_bucket_object: 2
+ google_tags_tag_binding: 3
google_vpc_access_connector: 2
modules: 24
- resources: 174
+ resources: 180
diff --git a/tests/fast/stages/s2_networking_a_simple/simple.tfvars b/tests/fast/stages/s2_networking_a_simple/simple.tfvars
index 74d3dfb36..99e2cb2cb 100644
--- a/tests/fast/stages/s2_networking_a_simple/simple.tfvars
+++ b/tests/fast/stages/s2_networking_a_simple/simple.tfvars
@@ -5,16 +5,29 @@ billing_account = {
id = "000000-111111-222222"
}
custom_roles = {
+ project_iam_viewer = "organizations/123456789012/roles/bar"
service_project_network_admin = "organizations/123456789012/roles/foo"
}
dns = {
resolvers = ["10.10.10.10"]
enable_logging = true
}
-enable_cloud_nat = true
+enable_cloud_nat = true
+environments = {
+ dev = {
+ is_default = false
+ name = "Development"
+ tag_name = "development"
+ }
+ prod = {
+ is_default = true
+ name = "Production"
+ tag_name = "production"
+ }
+}
essential_contacts = "gcp-network-admins@fast.example.com"
folder_ids = {
- networking = null
+ networking = "folders/12345"
networking-dev = null
networking-prod = null
}
@@ -36,6 +49,35 @@ organization = {
customer_id = "C00000000"
}
prefix = "fast2"
+stage_config = {
+ networking = {
+ iam_delegated_principals = {
+ dev = [
+ "serviceAccount:fast2-dev-resman-gcve-0@fast2-prod-iac-core-0.iam.gserviceaccount.com",
+ "serviceAccount:fast2-dev-resman-pf-0@fast2-prod-iac-core-0.iam.gserviceaccount.com"
+ ]
+ prod = [
+ "serviceAccount:fast2-prod-resman-gcve-0@fast2-prod-iac-core-0.iam.gserviceaccount.com",
+ "serviceAccount:fast2-prod-resman-pf-0@fast2-prod-iac-core-0.iam.gserviceaccount.com"
+ ]
+ }
+ iam_viewer_principals = {
+ dev = [
+ "serviceAccount:fast2-dev-resman-gcve-0r@fast2-prod-iac-core-0.iam.gserviceaccount.com",
+ "serviceAccount:fast2-dev-resman-pf-0r@fast2-prod-iac-core-0.iam.gserviceaccount.com"
+ ]
+ prod = [
+ "serviceAccount:fast2-prod-resman-gcve-0r@fast2-prod-iac-core-0.iam.gserviceaccount.com",
+ "serviceAccount:fast2-prod-resman-pf-0r@fast2-prod-iac-core-0.iam.gserviceaccount.com"
+ ]
+ }
+ short_name = "net"
+ }
+}
+tag_values = {
+ "environment/development" = "tagValues/12345"
+ "environment/production" = "tagValues/12346"
+}
# spoke_configs defaults to peering
vpn_onprem_primary_config = {
peer_external_gateways = {
diff --git a/tests/fast/stages/s2_networking_a_simple/simple.yaml b/tests/fast/stages/s2_networking_a_simple/simple.yaml
index 79bc4b3b0..afd24899e 100644
--- a/tests/fast/stages/s2_networking_a_simple/simple.yaml
+++ b/tests/fast/stages/s2_networking_a_simple/simple.yaml
@@ -35,17 +35,17 @@ counts:
google_dns_response_policy: 1
google_dns_response_policy_rule: 39
google_essential_contacts_contact: 1
- google_folder: 1
google_monitoring_alert_policy: 2
google_monitoring_dashboard: 3
google_monitoring_monitored_project: 2
google_project: 3
google_project_iam_binding: 4
- google_project_iam_member: 17
- google_project_service: 23
- google_project_service_identity: 17
+ google_project_iam_member: 20
+ google_project_service: 26
+ google_project_service_identity: 20
google_storage_bucket_object: 2
+ google_tags_tag_binding: 3
google_vpc_access_connector: 2
modules: 29
random_id: 1
- resources: 186
+ resources: 197
diff --git a/tests/fast/stages/s2_networking_a_simple/vpn.tfvars b/tests/fast/stages/s2_networking_a_simple/vpn.tfvars
index e37c0436c..764902a0a 100644
--- a/tests/fast/stages/s2_networking_a_simple/vpn.tfvars
+++ b/tests/fast/stages/s2_networking_a_simple/vpn.tfvars
@@ -5,16 +5,29 @@ billing_account = {
id = "000000-111111-222222"
}
custom_roles = {
+ project_iam_viewer = "organizations/123456789012/roles/bar"
service_project_network_admin = "organizations/123456789012/roles/foo"
}
dns = {
resolvers = ["10.10.10.10"]
enable_logging = true
}
-enable_cloud_nat = true
+enable_cloud_nat = true
+environments = {
+ dev = {
+ is_default = false
+ name = "Development"
+ tag_name = "development"
+ }
+ prod = {
+ is_default = true
+ name = "Production"
+ tag_name = "production"
+ }
+}
essential_contacts = "gcp-network-admins@fast.example.com"
folder_ids = {
- networking = null
+ networking = "folders/12345"
networking-dev = null
networking-prod = null
}
@@ -39,3 +52,7 @@ service_accounts = {
spoke_configs = {
vpn_configs = {}
}
+tag_values = {
+ "environment/development" = "tagValues/12345"
+ "environment/production" = "tagValues/12346"
+}
diff --git a/tests/fast/stages/s2_networking_a_simple/vpn.yaml b/tests/fast/stages/s2_networking_a_simple/vpn.yaml
index 67c9f5238..869cd3b8f 100644
--- a/tests/fast/stages/s2_networking_a_simple/vpn.yaml
+++ b/tests/fast/stages/s2_networking_a_simple/vpn.yaml
@@ -33,17 +33,17 @@ counts:
google_dns_response_policy: 1
google_dns_response_policy_rule: 39
google_essential_contacts_contact: 1
- google_folder: 1
google_monitoring_alert_policy: 2
google_monitoring_dashboard: 3
google_monitoring_monitored_project: 2
google_project: 3
- google_project_iam_binding: 4
- google_project_iam_member: 17
- google_project_service: 23
- google_project_service_identity: 17
+ google_project_iam_binding: 2
+ google_project_iam_member: 20
+ google_project_service: 26
+ google_project_service_identity: 20
google_storage_bucket_object: 2
+ google_tags_tag_binding: 3
google_vpc_access_connector: 2
modules: 31
random_id: 5
- resources: 223
+ resources: 232
diff --git a/tests/fast/stages/s2_networking_b_nva/ncc-ra.tfvars b/tests/fast/stages/s2_networking_b_nva/ncc-ra.tfvars
index 8f6b1eeed..a1e74c195 100644
--- a/tests/fast/stages/s2_networking_b_nva/ncc-ra.tfvars
+++ b/tests/fast/stages/s2_networking_b_nva/ncc-ra.tfvars
@@ -5,6 +5,7 @@ billing_account = {
id = "000000-111111-222222"
}
custom_roles = {
+ project_iam_viewer = "organizations/123456789012/roles/bar"
service_project_network_admin = "organizations/123456789012/roles/foo"
}
dns = {
@@ -13,9 +14,21 @@ dns = {
}
enable_cloud_nat = true
enable_test_instances = true
-essential_contacts = "gcp-network-admins@fast.example.com"
+environments = {
+ dev = {
+ is_default = false
+ name = "Development"
+ tag_name = "development"
+ }
+ prod = {
+ is_default = true
+ name = "Production"
+ tag_name = "production"
+ }
+}
+essential_contacts = "gcp-network-admins@fast.example.com"
folder_ids = {
- networking = null
+ networking = "folders/12345"
networking-dev = null
networking-prod = null
}
@@ -116,3 +129,7 @@ vpn_onprem_secondary_config = {
}
}
}
+tag_values = {
+ "environment/development" = "tagValues/12345"
+ "environment/production" = "tagValues/12346"
+}
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 ba6529825..182338498 100644
--- a/tests/fast/stages/s2_networking_b_nva/ncc-ra.yaml
+++ b/tests/fast/stages/s2_networking_b_nva/ncc-ra.yaml
@@ -36,19 +36,19 @@ counts:
google_dns_response_policy: 1
google_dns_response_policy_rule: 39
google_essential_contacts_contact: 1
- google_folder: 1
google_monitoring_alert_policy: 2
google_monitoring_dashboard: 3
google_monitoring_monitored_project: 2
google_network_connectivity_hub: 2
google_network_connectivity_spoke: 4
google_project: 3
- google_project_iam_binding: 4
- google_project_iam_member: 18
- google_project_service: 24
- google_project_service_identity: 18
+ google_project_iam_binding: 2
+ google_project_iam_member: 19
+ google_project_service: 25
+ google_project_service_identity: 19
google_storage_bucket_object: 2
+ google_tags_tag_binding: 3
google_vpc_access_connector: 2
modules: 39
random_id: 2
- resources: 254
+ resources: 257
diff --git a/tests/fast/stages/s2_networking_b_nva/regional.tfvars b/tests/fast/stages/s2_networking_b_nva/regional.tfvars
index 36c04f78f..e8d4e4ce2 100644
--- a/tests/fast/stages/s2_networking_b_nva/regional.tfvars
+++ b/tests/fast/stages/s2_networking_b_nva/regional.tfvars
@@ -5,6 +5,7 @@ billing_account = {
id = "000000-111111-222222"
}
custom_roles = {
+ project_iam_viewer = "organizations/123456789012/roles/bar"
service_project_network_admin = "organizations/123456789012/roles/foo"
}
dns = {
@@ -13,9 +14,21 @@ dns = {
}
enable_cloud_nat = true
enable_test_instances = true
-essential_contacts = "gcp-network-admins@fast.example.com"
+environments = {
+ dev = {
+ is_default = false
+ name = "Development"
+ tag_name = "development"
+ }
+ prod = {
+ is_default = true
+ name = "Production"
+ tag_name = "production"
+ }
+}
+essential_contacts = "gcp-network-admins@fast.example.com"
folder_ids = {
- networking = null
+ networking = "folders/12345"
networking-dev = null
networking-prod = null
}
@@ -116,3 +129,7 @@ vpn_onprem_secondary_config = {
}
}
}
+tag_values = {
+ "environment/development" = "tagValues/12345"
+ "environment/production" = "tagValues/12346"
+}
diff --git a/tests/fast/stages/s2_networking_b_nva/regional.yaml b/tests/fast/stages/s2_networking_b_nva/regional.yaml
index baa06b82d..61d3d53cd 100644
--- a/tests/fast/stages/s2_networking_b_nva/regional.yaml
+++ b/tests/fast/stages/s2_networking_b_nva/regional.yaml
@@ -40,16 +40,17 @@ counts:
google_dns_response_policy: 1
google_dns_response_policy_rule: 39
google_essential_contacts_contact: 1
- google_folder: 1
google_monitoring_alert_policy: 2
google_monitoring_dashboard: 3
google_monitoring_monitored_project: 2
google_project: 3
- google_project_iam_binding: 4
- google_project_iam_member: 17
- google_project_service: 23
- google_project_service_identity: 17
+ google_project_iam_binding: 2
+ google_project_iam_member: 19
+ google_project_service: 25
+ google_project_service_identity: 19
google_storage_bucket_object: 2
+ google_tags_tag_binding: 3
+ google_vpc_access_connector: 2
modules: 47
random_id: 2
- resources: 259
+ resources: 265
diff --git a/tests/fast/stages/s2_networking_b_nva/simple.tfvars b/tests/fast/stages/s2_networking_b_nva/simple.tfvars
index 090774298..d4ca2fa9d 100644
--- a/tests/fast/stages/s2_networking_b_nva/simple.tfvars
+++ b/tests/fast/stages/s2_networking_b_nva/simple.tfvars
@@ -5,6 +5,7 @@ billing_account = {
id = "000000-111111-222222"
}
custom_roles = {
+ project_iam_viewer = "organizations/123456789012/roles/bar"
service_project_network_admin = "organizations/123456789012/roles/foo"
}
dns = {
@@ -13,9 +14,21 @@ dns = {
}
enable_cloud_nat = true
enable_test_instances = true
-essential_contacts = "gcp-network-admins@fast.example.com"
+environments = {
+ dev = {
+ is_default = false
+ name = "Development"
+ tag_name = "development"
+ }
+ prod = {
+ is_default = true
+ name = "Production"
+ tag_name = "production"
+ }
+}
+essential_contacts = "gcp-network-admins@fast.example.com"
folder_ids = {
- networking = null
+ networking = "folders/12345"
networking-dev = null
networking-prod = null
}
@@ -116,3 +129,7 @@ vpn_onprem_secondary_config = {
}
}
}
+tag_values = {
+ "environment/development" = "tagValues/12345"
+ "environment/production" = "tagValues/12346"
+}
diff --git a/tests/fast/stages/s2_networking_b_nva/simple.yaml b/tests/fast/stages/s2_networking_b_nva/simple.yaml
index 7303c2648..d8f362d8b 100644
--- a/tests/fast/stages/s2_networking_b_nva/simple.yaml
+++ b/tests/fast/stages/s2_networking_b_nva/simple.yaml
@@ -40,17 +40,17 @@ counts:
google_dns_response_policy: 1
google_dns_response_policy_rule: 39
google_essential_contacts_contact: 1
- google_folder: 1
google_monitoring_alert_policy: 2
google_monitoring_dashboard: 3
google_monitoring_monitored_project: 2
google_project: 3
- google_project_iam_binding: 4
- google_project_iam_member: 17
- google_project_service: 23
- google_project_service_identity: 17
+ google_project_iam_binding: 2
+ google_project_iam_member: 19
+ google_project_service: 25
+ google_project_service_identity: 19
google_storage_bucket_object: 2
+ google_tags_tag_binding: 3
google_vpc_access_connector: 2
modules: 43
random_id: 2
- resources: 237
+ resources: 243
diff --git a/tests/fast/stages/s2_networking_c_separate_envs/simple.tfvars b/tests/fast/stages/s2_networking_c_separate_envs/simple.tfvars
index e72ed28f8..74b8a4387 100644
--- a/tests/fast/stages/s2_networking_c_separate_envs/simple.tfvars
+++ b/tests/fast/stages/s2_networking_c_separate_envs/simple.tfvars
@@ -5,6 +5,7 @@ billing_account = {
id = "000000-111111-222222"
}
custom_roles = {
+ project_iam_viewer = "organizations/123456789012/roles/bar"
service_project_network_admin = "organizations/123456789012/roles/foo"
}
dns = {
@@ -12,10 +13,22 @@ dns = {
prod_resolvers = ["10.20.10.10"]
enable_logging = true
}
-enable_cloud_nat = true
+enable_cloud_nat = true
+environments = {
+ dev = {
+ is_default = false
+ name = "Development"
+ tag_name = "development"
+ }
+ prod = {
+ is_default = true
+ name = "Production"
+ tag_name = "production"
+ }
+}
essential_contacts = "gcp-network-admins@fast.example.com"
folder_ids = {
- networking = null
+ networking = "folders/12345"
networking-dev = null
networking-prod = null
}
@@ -37,6 +50,10 @@ organization = {
customer_id = "C00000000"
}
prefix = "fast2"
+tag_values = {
+ "environment/development" = "tagValues/12345"
+ "environment/production" = "tagValues/12346"
+}
vpn_onprem_dev_primary_config = {
peer_external_gateways = {
default = {
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 13ad54279..65cd1d33f 100644
--- a/tests/fast/stages/s2_networking_c_separate_envs/simple.yaml
+++ b/tests/fast/stages/s2_networking_c_separate_envs/simple.yaml
@@ -34,16 +34,16 @@ counts:
google_dns_response_policy: 2
google_dns_response_policy_rule: 78
google_essential_contacts_contact: 1
- google_folder: 1
google_monitoring_alert_policy: 4
google_monitoring_dashboard: 6
google_project: 2
- google_project_iam_binding: 4
- google_project_iam_member: 14
- google_project_service: 18
- google_project_service_identity: 14
+ google_project_iam_binding: 2
+ google_project_iam_member: 16
+ google_project_service: 20
+ google_project_service_identity: 16
google_storage_bucket_object: 2
+ google_tags_tag_binding: 2
google_vpc_access_connector: 2
modules: 22
random_id: 2
- resources: 206
+ resources: 211
diff --git a/tests/fast/stages/s2_security/simple.tfvars b/tests/fast/stages/s2_security/simple.tfvars
index 0dff49037..8713d2693 100644
--- a/tests/fast/stages/s2_security/simple.tfvars
+++ b/tests/fast/stages/s2_security/simple.tfvars
@@ -4,9 +4,25 @@ automation = {
billing_account = {
id = "000000-111111-222222"
}
+custom_roles = {
+ project_iam_viewer = "organizations/123456789012/roles/bar"
+ service_project_network_admin = "organizations/123456789012/roles/foo"
+}
+environments = {
+ dev = {
+ is_default = false
+ name = "Development"
+ tag_name = "development"
+ }
+ prod = {
+ is_default = true
+ name = "Production"
+ tag_name = "production"
+ }
+}
essential_contacts = "gcp-security-admins@fast.example.com"
folder_ids = {
- security = null
+ security = "folders/12345678"
}
organization = {
domain = "fast.example.com"
@@ -34,3 +50,32 @@ service_accounts = {
project-factory-dev = "foobar@iam.gserviceaccount.com"
project-factory-prod = "foobar@iam.gserviceaccount.com"
}
+stage_config = {
+ security = {
+ iam_delegated_principals = {
+ dev = [
+ "serviceAccount:fast2-dev-resman-gcve-0@fast2-prod-iac-core-0.iam.gserviceaccount.com",
+ "serviceAccount:fast2-dev-resman-pf-0@fast2-prod-iac-core-0.iam.gserviceaccount.com"
+ ]
+ prod = [
+ "serviceAccount:fast2-prod-resman-gcve-0@fast2-prod-iac-core-0.iam.gserviceaccount.com",
+ "serviceAccount:fast2-prod-resman-pf-0@fast2-prod-iac-core-0.iam.gserviceaccount.com"
+ ]
+ }
+ iam_viewer_principals = {
+ dev = [
+ "serviceAccount:fast2-dev-resman-gcve-0r@fast2-prod-iac-core-0.iam.gserviceaccount.com",
+ "serviceAccount:fast2-dev-resman-pf-0r@fast2-prod-iac-core-0.iam.gserviceaccount.com"
+ ]
+ prod = [
+ "serviceAccount:fast2-prod-resman-gcve-0r@fast2-prod-iac-core-0.iam.gserviceaccount.com",
+ "serviceAccount:fast2-prod-resman-pf-0r@fast2-prod-iac-core-0.iam.gserviceaccount.com"
+ ]
+ }
+ short_name = "net"
+ }
+}
+tag_values = {
+ "environment/development" = "tagValues/12345"
+ "environment/production" = "tagValues/12346"
+}
diff --git a/tests/fast/stages/s2_security/simple.yaml b/tests/fast/stages/s2_security/simple.yaml
index e98ac3805..5fbb91f0e 100644
--- a/tests/fast/stages/s2_security/simple.yaml
+++ b/tests/fast/stages/s2_security/simple.yaml
@@ -30,6 +30,7 @@ values:
timeouts: null
module.dev-sec-kms["europe"].google_kms_crypto_key.default["compute"]:
effective_labels:
+ goog-terraform-provisioned: 'true'
service: compute
labels:
service: compute
@@ -38,6 +39,7 @@ values:
rotation_period: 7776000s
skip_initial_version_creation: false
terraform_labels:
+ goog-terraform-provisioned: 'true'
service: compute
timeouts: null
module.dev-sec-kms["europe"].google_kms_crypto_key_iam_binding.authoritative["compute.roles/cloudkms.admin"]:
@@ -52,6 +54,7 @@ values:
timeouts: null
module.dev-sec-kms["europe-west1"].google_kms_crypto_key.default["compute"]:
effective_labels:
+ goog-terraform-provisioned: 'true'
service: compute
labels:
service: compute
@@ -60,6 +63,7 @@ values:
rotation_period: 7776000s
skip_initial_version_creation: false
terraform_labels:
+ goog-terraform-provisioned: 'true'
service: compute
timeouts: null
module.dev-sec-kms["europe-west1"].google_kms_crypto_key_iam_binding.authoritative["compute.roles/cloudkms.admin"]:
@@ -74,6 +78,7 @@ values:
timeouts: null
module.dev-sec-kms["europe-west3"].google_kms_crypto_key.default["compute"]:
effective_labels:
+ goog-terraform-provisioned: 'true'
service: compute
labels:
service: compute
@@ -82,6 +87,7 @@ values:
rotation_period: 7776000s
skip_initial_version_creation: false
terraform_labels:
+ goog-terraform-provisioned: 'true'
service: compute
timeouts: null
module.dev-sec-kms["europe-west3"].google_kms_crypto_key_iam_binding.authoritative["compute.roles/cloudkms.admin"]:
@@ -96,6 +102,7 @@ values:
timeouts: null
module.dev-sec-kms["global"].google_kms_crypto_key.default["compute"]:
effective_labels:
+ goog-terraform-provisioned: 'true'
service: compute
labels:
service: compute
@@ -104,6 +111,7 @@ values:
rotation_period: 7776000s
skip_initial_version_creation: false
terraform_labels:
+ goog-terraform-provisioned: 'true'
service: compute
timeouts: null
module.dev-sec-kms["global"].google_kms_crypto_key_iam_binding.authoritative["compute.roles/cloudkms.admin"]:
@@ -122,37 +130,17 @@ values:
deletion_policy: DELETE
effective_labels:
environment: dev
- team: security
- folder_id: null
+ goog-terraform-provisioned: 'true'
+ folder_id: '12345678'
labels:
environment: dev
- team: security
name: fast-dev-sec-core-0
org_id: null
project_id: fast-dev-sec-core-0
terraform_labels:
environment: dev
- team: security
+ goog-terraform-provisioned: 'true'
timeouts: null
- module.dev-sec-project.google_project_iam_binding.authoritative["roles/cloudkms.viewer"]:
- condition: []
- members:
- - serviceAccount:foobar@iam.gserviceaccount.com
- project: fast-dev-sec-core-0
- role: roles/cloudkms.viewer
- ? module.dev-sec-project.google_project_iam_member.bindings["kms_restricted_admin.serviceAccount:foobar@iam.gserviceaccount.com"]
- : condition:
- - description: Automation service account delegated grants.
- expression: 'api.getAttribute(''iam.googleapis.com/modifiedGrantsByRole'', []).hasOnly([''roles/cloudkms.cryptoKeyEncrypterDecrypter'',''roles/cloudkms.cryptoKeyEncrypterDecrypterViaDelegation''])
- &&
-
- resource.type == ''cloudkms.googleapis.com/CryptoKey''
-
- '
- title: kms_sa_delegated_grants
- member: serviceAccount:foobar@iam.gserviceaccount.com
- project: fast-dev-sec-core-0
- role: roles/cloudkms.admin
module.dev-sec-project.google_project_iam_member.service_agents["certificatemanager"]:
condition: []
project: fast-dev-sec-core-0
@@ -231,18 +219,19 @@ values:
project: fast-dev-sec-core-0
service: secretmanager.googleapis.com
timeouts: null
+ module.dev-sec-project.google_tags_tag_binding.binding["environment"]:
+ tag_value: tagValues/12345
+ timeouts: null
module.folder.google_essential_contacts_contact.contact["gcp-security-admins@fast.example.com"]:
email: gcp-security-admins@fast.example.com
language_tag: en
notification_category_subscriptions:
- ALL
- timeouts: null
- module.folder.google_folder.folder[0]:
- display_name: Security
- parent: organizations/123456789012
+ parent: folders/12345678
timeouts: null
module.prod-sec-kms["europe"].google_kms_crypto_key.default["compute"]:
effective_labels:
+ goog-terraform-provisioned: 'true'
service: compute
labels:
service: compute
@@ -251,6 +240,7 @@ values:
rotation_period: 7776000s
skip_initial_version_creation: false
terraform_labels:
+ goog-terraform-provisioned: 'true'
service: compute
timeouts: null
module.prod-sec-kms["europe"].google_kms_crypto_key_iam_binding.authoritative["compute.roles/cloudkms.admin"]:
@@ -265,6 +255,7 @@ values:
timeouts: null
module.prod-sec-kms["europe-west1"].google_kms_crypto_key.default["compute"]:
effective_labels:
+ goog-terraform-provisioned: 'true'
service: compute
labels:
service: compute
@@ -273,6 +264,7 @@ values:
rotation_period: 7776000s
skip_initial_version_creation: false
terraform_labels:
+ goog-terraform-provisioned: 'true'
service: compute
timeouts: null
module.prod-sec-kms["europe-west1"].google_kms_crypto_key_iam_binding.authoritative["compute.roles/cloudkms.admin"]:
@@ -287,6 +279,7 @@ values:
timeouts: null
module.prod-sec-kms["europe-west3"].google_kms_crypto_key.default["compute"]:
effective_labels:
+ goog-terraform-provisioned: 'true'
service: compute
labels:
service: compute
@@ -295,6 +288,7 @@ values:
rotation_period: 7776000s
skip_initial_version_creation: false
terraform_labels:
+ goog-terraform-provisioned: 'true'
service: compute
timeouts: null
module.prod-sec-kms["europe-west3"].google_kms_crypto_key_iam_binding.authoritative["compute.roles/cloudkms.admin"]:
@@ -309,6 +303,7 @@ values:
timeouts: null
module.prod-sec-kms["global"].google_kms_crypto_key.default["compute"]:
effective_labels:
+ goog-terraform-provisioned: 'true'
service: compute
labels:
service: compute
@@ -317,6 +312,7 @@ values:
rotation_period: 7776000s
skip_initial_version_creation: false
terraform_labels:
+ goog-terraform-provisioned: 'true'
service: compute
timeouts: null
module.prod-sec-kms["global"].google_kms_crypto_key_iam_binding.authoritative["compute.roles/cloudkms.admin"]:
@@ -335,37 +331,17 @@ values:
deletion_policy: DELETE
effective_labels:
environment: prod
- team: security
- folder_id: null
+ goog-terraform-provisioned: 'true'
+ folder_id: '12345678'
labels:
environment: prod
- team: security
name: fast-prod-sec-core-0
org_id: null
project_id: fast-prod-sec-core-0
terraform_labels:
environment: prod
- team: security
+ goog-terraform-provisioned: 'true'
timeouts: null
- module.prod-sec-project.google_project_iam_binding.authoritative["roles/cloudkms.viewer"]:
- condition: []
- members:
- - serviceAccount:foobar@iam.gserviceaccount.com
- project: fast-prod-sec-core-0
- role: roles/cloudkms.viewer
- ? module.prod-sec-project.google_project_iam_member.bindings["kms_restricted_admin.serviceAccount:foobar@iam.gserviceaccount.com"]
- : condition:
- - description: Automation service account delegated grants.
- expression: 'api.getAttribute(''iam.googleapis.com/modifiedGrantsByRole'', []).hasOnly([''roles/cloudkms.cryptoKeyEncrypterDecrypter'',''roles/cloudkms.cryptoKeyEncrypterDecrypterViaDelegation''])
- &&
-
- resource.type == ''cloudkms.googleapis.com/CryptoKey''
-
- '
- title: kms_sa_delegated_grants
- member: serviceAccount:foobar@iam.gserviceaccount.com
- project: fast-prod-sec-core-0
- role: roles/cloudkms.admin
module.prod-sec-project.google_project_iam_member.service_agents["certificatemanager"]:
condition: []
project: fast-prod-sec-core-0
@@ -444,33 +420,21 @@ values:
project: fast-prod-sec-core-0
service: secretmanager.googleapis.com
timeouts: null
+ module.prod-sec-project.google_tags_tag_binding.binding["environment"]:
+ tag_value: tagValues/12346
+ timeouts: null
counts:
google_essential_contacts_contact: 1
- google_folder: 1
google_kms_crypto_key: 8
google_kms_crypto_key_iam_binding: 8
google_kms_key_ring: 8
google_project: 2
- google_project_iam_binding: 2
- google_project_iam_member: 8
+ google_project_iam_binding: 4
+ google_project_iam_member: 6
google_project_service: 14
google_project_service_identity: 12
google_storage_bucket_object: 1
+ google_tags_tag_binding: 2
modules: 11
- resources: 65
-
-outputs:
- cas_configs:
- dev: {}
- prod: {}
- kms_keys: __missing__
- ngfw_tls_configs:
- tls_enabled: false
- tls_ip_ids_by_region:
- dev: {}
- prod: {}
- tfvars: __missing__
- trust_config_ids:
- dev: {}
- prod: {}
+ resources: 66
diff --git a/tests/fast/stages/s3_data_platform/simple.tfvars b/tests/fast/stages/s3_data_platform/simple.tfvars
deleted file mode 100644
index 2ec41d37a..000000000
--- a/tests/fast/stages/s3_data_platform/simple.tfvars
+++ /dev/null
@@ -1,25 +0,0 @@
-automation = {
- outputs_bucket = "test"
-}
-billing_account = {
- id = "012345-67890A-BCDEF0",
-}
-folder_ids = {
- data-platform-dev = "folders/12345678"
-}
-host_project_ids = {
- dev-spoke-0 = "fast-dev-net-spoke-0"
-}
-organization = {
- domain = "fast.example.com"
- id = 123456789012
- customer_id = "C00000000"
-}
-prefix = "fast"
-subnet_self_links = {
- dev-spoke-0 = {
- "europe-west1/dev-dataplatform-ew1" : "https://www.googleapis.com/compute/v1/projects/fast-dev-net-spoke-0/regions/europe-west1/subnetworks/dev-dataplatform-ew1",
- "europe-west1/dev-default-ew1" : "https://www.googleapis.com/compute/v1/projects/fast-dev-net-spoke-0/regions/europe-west1/subnetworks/dev-default-ew1"
- }
-}
-vpc_self_links = { dev-spoke-0 = "https://www.googleapis.com/compute/v1/projects/fast-dev-net-spoke-0/global/networks/dev-spoke-0" }
diff --git a/tests/fast/stages/s3_data_platform/simple.yaml b/tests/fast/stages/s3_data_platform/simple.yaml
deleted file mode 100644
index 419523081..000000000
--- a/tests/fast/stages/s3_data_platform/simple.yaml
+++ /dev/null
@@ -1,35 +0,0 @@
-# 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_artifact_registry_repository: 1
- google_bigquery_dataset: 4
- google_bigquery_default_service_account: 7
- google_composer_environment: 1
- google_compute_shared_vpc_service_project: 3
- google_data_catalog_policy_tag: 3
- google_data_catalog_taxonomy: 1
- google_project: 9
- google_project_iam_binding: 61
- google_project_iam_member: 52
- google_project_service: 114
- google_project_service_identity: 33
- google_pubsub_topic: 1
- google_service_account: 8
- google_service_account_iam_binding: 13
- google_storage_bucket: 9
- google_storage_bucket_object: 1
- google_storage_project_service_account: 7
- modules: 34
- resources: 328
diff --git a/tests/fast/stages/s3_gcve/simple.tfvars b/tests/fast/stages/s3_gcve/simple.tfvars
deleted file mode 100644
index b27af0975..000000000
--- a/tests/fast/stages/s3_gcve/simple.tfvars
+++ /dev/null
@@ -1,53 +0,0 @@
-automation = {
- federated_identity_pool = null
- federated_identity_providers = null
- project_id = "fast-prod-automation"
- project_number = 123456
- outputs_bucket = "test"
- service_accounts = {
- resman-r = "em-dev-gcve-0r@fast2-prod-iac-core-0.iam.gserviceaccount.com"
- }
-}
-
-billing_account = {
- id = "000000-111111-222222"
-}
-
-folder_ids = {
- gcve-prod = "folders/00000000000000"
-}
-
-groups_gcve = {
- gcp-gcve-admins = "gcp-gcve-admins",
- gcp-gcve-viewers = "gcp-gcve-viewers"
-}
-
-host_project_ids = {
- prod-spoke-0 = "prod-spoke-0"
-}
-
-organization = {
- domain = "fast.example.com"
- id = 123456789012
- customer_id = "C00000000"
-}
-
-prefix = "fast3"
-
-private_cloud_configs = {
- dev-pc = {
- cidr = "172.26.16.0/22"
- zone = "europe-west8-a"
- management_cluster_config = {
- name = "mgmt-cluster"
- node_count = 1
- node_type_id = "standard-72"
- }
- }
-}
-
-vpc_self_links = {
- "prod-spoke-0" = "https://www.googleapis.com/compute/v1/projects/em-prod-net-spoke-0/global/networks/prod-spoke-0",
-}
-
-
diff --git a/tests/fast/stages/s3_gcve/__init__.py b/tests/fast/stages/s3_gcve_dev/__init__.py
similarity index 100%
rename from tests/fast/stages/s3_gcve/__init__.py
rename to tests/fast/stages/s3_gcve_dev/__init__.py
diff --git a/tests/fast/stages/s3_gcve_dev/simple.tfvars b/tests/fast/stages/s3_gcve_dev/simple.tfvars
new file mode 100644
index 000000000..0f1461412
--- /dev/null
+++ b/tests/fast/stages/s3_gcve_dev/simple.tfvars
@@ -0,0 +1,39 @@
+billing_account = {
+ id = "000000-111111-222222"
+}
+
+environments = {
+ dev = {
+ name = "Development"
+ }
+}
+
+folder_ids = {
+ gcve-dev = "folders/00000000000000"
+}
+
+organization = {
+ domain = "fast.example.com"
+ id = 123456789012
+ customer_id = "C00000000"
+}
+
+prefix = "fast3"
+
+private_cloud_configs = {
+ dev-pc = {
+ cidr = "172.26.16.0/22"
+ zone = "europe-west8-a"
+ management_cluster_config = {
+ name = "mgmt-cluster"
+ node_count = 1
+ node_type_id = "standard-72"
+ }
+ }
+}
+
+vpc_self_links = {
+ "dev-spoke-0" = "projects/em-prod-net-spoke-0/global/networks/prod-spoke-0",
+}
+
+
diff --git a/tests/fast/stages/s3_gcve/simple.yaml b/tests/fast/stages/s3_gcve_dev/simple.yaml
similarity index 78%
rename from tests/fast/stages/s3_gcve/simple.yaml
rename to tests/fast/stages/s3_gcve_dev/simple.yaml
index c3c846a21..396b8675f 100644
--- a/tests/fast/stages/s3_gcve/simple.yaml
+++ b/tests/fast/stages/s3_gcve_dev/simple.yaml
@@ -14,13 +14,11 @@
counts:
google_project: 1
- google_project_iam_binding: 2
- google_project_iam_member: 1
- google_project_service: 1
- google_project_service_identity: 1
- google_storage_bucket_object: 1
+ google_project_iam_member: 3
+ google_project_service: 4
+ google_project_service_identity: 2
google_vmwareengine_network: 1
google_vmwareengine_network_peering: 2
google_vmwareengine_private_cloud: 1
- modules: 3
- resources: 11
+ modules: 2
+ resources: 14
diff --git a/tests/fast/stages/s3_gcve/tftest.yaml b/tests/fast/stages/s3_gcve_dev/tftest.yaml
similarity index 94%
rename from tests/fast/stages/s3_gcve/tftest.yaml
rename to tests/fast/stages/s3_gcve_dev/tftest.yaml
index 2f66f9b07..d8d581f6d 100644
--- a/tests/fast/stages/s3_gcve/tftest.yaml
+++ b/tests/fast/stages/s3_gcve_dev/tftest.yaml
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-module: fast/stages/3-gcve/prod
+module: fast/stages/3-gcve-dev
tests:
simple:
diff --git a/tests/fast/stages/s3_gke_multitenant/simple.tfvars b/tests/fast/stages/s3_gke_dev/simple.tfvars
similarity index 93%
rename from tests/fast/stages/s3_gke_multitenant/simple.tfvars
rename to tests/fast/stages/s3_gke_dev/simple.tfvars
index 1cafdd9ab..f7a8e54b3 100644
--- a/tests/fast/stages/s3_gke_multitenant/simple.tfvars
+++ b/tests/fast/stages/s3_gke_dev/simple.tfvars
@@ -1,6 +1,3 @@
-automation = {
- outputs_bucket = "test"
-}
billing_account = {
id = "012345-67890A-BCDEF0",
}
@@ -21,6 +18,11 @@ clusters = {
}
}
}
+environments = {
+ dev = {
+ name = "Development"
+ }
+}
nodepools = {
mycluster = {
mynodepool = {
diff --git a/tests/fast/stages/s3_gke_multitenant/simple.yaml b/tests/fast/stages/s3_gke_dev/simple.yaml
similarity index 93%
rename from tests/fast/stages/s3_gke_multitenant/simple.yaml
rename to tests/fast/stages/s3_gke_dev/simple.yaml
index c1fca496d..b18b091e4 100644
--- a/tests/fast/stages/s3_gke_multitenant/simple.yaml
+++ b/tests/fast/stages/s3_gke_dev/simple.yaml
@@ -23,6 +23,5 @@ counts:
google_project_service: 12
google_project_service_identity: 7
google_service_account: 1
- google_storage_bucket_object: 1
- modules: 6
- resources: 43
+ modules: 5
+ resources: 42
diff --git a/tests/fast/stages/s3_data_platform/tftest.yaml b/tests/fast/stages/s3_gke_dev/tftest.yaml
similarity index 93%
rename from tests/fast/stages/s3_data_platform/tftest.yaml
rename to tests/fast/stages/s3_gke_dev/tftest.yaml
index 245b313e0..14b8860e0 100644
--- a/tests/fast/stages/s3_data_platform/tftest.yaml
+++ b/tests/fast/stages/s3_gke_dev/tftest.yaml
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-module: fast/stages/3-data-platform/dev/
+module: fast/stages/3-gke-dev/
tests:
simple:
diff --git a/tests/modules/gcve_private_cloud/examples/additional-clusters.yaml b/tests/modules/gcve_private_cloud/examples/additional-clusters.yaml
index 841b4095d..7c9c38c3f 100644
--- a/tests/modules/gcve_private_cloud/examples/additional-clusters.yaml
+++ b/tests/modules/gcve_private_cloud/examples/additional-clusters.yaml
@@ -13,25 +13,28 @@
# limitations under the License.
values:
- module.gcve-pc.google_vmwareengine_cluster.vmw_engine_additional_clusters["test-cluster-one"]:
+ module.gcve-pc.google_vmwareengine_cluster.default["test-cluster-one"]:
name: gcve-pc-test-cluster-one
node_type_configs:
- custom_core_count: 28
node_count: 6
node_type_id: standard-72
- module.gcve-pc.google_vmwareengine_cluster.vmw_engine_additional_clusters["test-cluster-two"]:
+ timeouts: null
+ module.gcve-pc.google_vmwareengine_cluster.default["test-cluster-two"]:
name: gcve-pc-test-cluster-two
node_type_configs:
- custom_core_count: 28
node_count: 4
node_type_id: standard-72
- module.gcve-pc.google_vmwareengine_network.private_cloud_network[0]:
+ timeouts: null
+ module.gcve-pc.google_vmwareengine_network.default[0]:
description: Terraform-managed.
location: global
name: gcve-pc-default
project: gcve-test-project
+ timeouts: null
type: STANDARD
- module.gcve-pc.google_vmwareengine_network_peering.vmw_engine_network_peerings["transit-conn1"]:
+ module.gcve-pc.google_vmwareengine_network_peering.default["transit-conn1"]:
description: Managed by Terraform.
export_custom_routes: false
export_custom_routes_with_public_ip: false
@@ -41,7 +44,9 @@ values:
peer_network: projects/test-prj-gcve-01/global/networks/default
peer_network_type: STANDARD
project: gcve-test-project
- module.gcve-pc.google_vmwareengine_private_cloud.vmw_engine_private_clouds["pcc_one"]:
+ timeouts: null
+ module.gcve-pc.google_vmwareengine_private_cloud.default["pcc_one"]:
+ deletion_delay_hours: null
description: Managed by Terraform.
location: europe-west8-a
management_cluster:
@@ -50,10 +55,14 @@ values:
- custom_core_count: 0
node_count: 3
node_type_id: standard-72
+ stretched_cluster_config: []
name: gcve-pc-pcc_one
network_config:
- management_cidr: 192.168.0.0/24
project: gcve-test-project
+ send_deletion_delay_hours_if_zero: null
+ timeouts: null
+ type: null
counts:
google_vmwareengine_cluster: 2
diff --git a/tests/modules/gcve_private_cloud/examples/basic.yaml b/tests/modules/gcve_private_cloud/examples/basic.yaml
index 40803f020..afb411eab 100644
--- a/tests/modules/gcve_private_cloud/examples/basic.yaml
+++ b/tests/modules/gcve_private_cloud/examples/basic.yaml
@@ -13,13 +13,14 @@
# limitations under the License.
values:
- module.gcve-pc.google_vmwareengine_network.private_cloud_network[0]:
+ module.gcve-pc.google_vmwareengine_network.default[0]:
description: Terraform-managed.
location: global
name: gcve-pc-default
project: gcve-test-project
+ timeouts: null
type: STANDARD
- module.gcve-pc.google_vmwareengine_network_peering.vmw_engine_network_peerings["transit-conn1"]:
+ module.gcve-pc.google_vmwareengine_network_peering.default["transit-conn1"]:
description: Managed by Terraform.
export_custom_routes: false
export_custom_routes_with_public_ip: false
@@ -29,7 +30,9 @@ values:
peer_network: projects/test-prj-gcve-01/global/networks/default
peer_network_type: STANDARD
project: gcve-test-project
- module.gcve-pc.google_vmwareengine_private_cloud.vmw_engine_private_clouds["pcc_one"]:
+ timeouts: null
+ module.gcve-pc.google_vmwareengine_private_cloud.default["pcc_one"]:
+ deletion_delay_hours: null
description: Managed by Terraform.
location: europe-west8-a
management_cluster:
@@ -38,10 +41,14 @@ values:
- custom_core_count: 0
node_count: 3
node_type_id: standard-72
+ stretched_cluster_config: []
name: gcve-pc-pcc_one
network_config:
- management_cidr: 192.168.0.0/24
project: gcve-test-project
+ send_deletion_delay_hours_if_zero: null
+ timeouts: null
+ type: null
counts:
google_vmwareengine_network: 1
diff --git a/tests/modules/gcve_private_cloud/examples/custom-management.yaml b/tests/modules/gcve_private_cloud/examples/custom-management.yaml
index 6c7d7268a..831692091 100644
--- a/tests/modules/gcve_private_cloud/examples/custom-management.yaml
+++ b/tests/modules/gcve_private_cloud/examples/custom-management.yaml
@@ -13,13 +13,14 @@
# limitations under the License.
values:
- module.gcve-pc.google_vmwareengine_network.private_cloud_network[0]:
+ module.gcve-pc.google_vmwareengine_network.default[0]:
description: Terraform-managed.
location: global
name: gcve-pc-default
project: gcve-test-project
+ timeouts: null
type: STANDARD
- module.gcve-pc.google_vmwareengine_network_peering.vmw_engine_network_peerings["transit-conn1"]:
+ module.gcve-pc.google_vmwareengine_network_peering.default["transit-conn1"]:
description: Managed by Terraform.
export_custom_routes: false
export_custom_routes_with_public_ip: false
@@ -29,7 +30,9 @@ values:
peer_network: projects/test-prj-gcve-01/global/networks/default
peer_network_type: STANDARD
project: gcve-test-project
- module.gcve-pc.google_vmwareengine_private_cloud.vmw_engine_private_clouds["pcc_one"]:
+ timeouts: null
+ module.gcve-pc.google_vmwareengine_private_cloud.default["pcc_one"]:
+ deletion_delay_hours: null
description: Managed by Terraform.
location: europe-west8-a
management_cluster:
@@ -38,10 +41,14 @@ values:
- custom_core_count: 28
node_count: 6
node_type_id: standard-72
+ stretched_cluster_config: []
name: gcve-pc-pcc_one
network_config:
- management_cidr: 192.168.0.0/24
project: gcve-test-project
+ send_deletion_delay_hours_if_zero: null
+ timeouts: null
+ type: null
counts:
google_vmwareengine_network: 1
diff --git a/tests/modules/gcve_private_cloud/examples/network-policy.yaml b/tests/modules/gcve_private_cloud/examples/network-policy.yaml
index bfd3133de..64ed0653d 100644
--- a/tests/modules/gcve_private_cloud/examples/network-policy.yaml
+++ b/tests/modules/gcve_private_cloud/examples/network-policy.yaml
@@ -13,13 +13,14 @@
# limitations under the License.
values:
- module.gcve-pc.google_vmwareengine_network.private_cloud_network[0]:
+ module.gcve-pc.google_vmwareengine_network.default[0]:
description: Terraform-managed.
location: global
name: gcve-pc-default
project: gcve-test-project
+ timeouts: null
type: STANDARD
- module.gcve-pc.google_vmwareengine_network_policy.vmw_engine_network_policies["ew8"]:
+ module.gcve-pc.google_vmwareengine_network_policy.default["ew8"]:
description: Terraform-managed.
edge_services_cidr: 192.168.100.0/26
external_ip:
@@ -29,7 +30,9 @@ values:
location: europe-west8
name: gcve-pc-ew8
project: gcve-test-project
- module.gcve-pc.google_vmwareengine_private_cloud.vmw_engine_private_clouds["pcc_one"]:
+ timeouts: null
+ module.gcve-pc.google_vmwareengine_private_cloud.default["pcc_one"]:
+ deletion_delay_hours: null
description: Managed by Terraform.
location: europe-west8-a
management_cluster:
@@ -38,10 +41,14 @@ values:
- custom_core_count: 0
node_count: 3
node_type_id: standard-72
+ stretched_cluster_config: []
name: gcve-pc-pcc_one
network_config:
- management_cidr: 192.168.0.0/24
project: gcve-test-project
+ send_deletion_delay_hours_if_zero: null
+ timeouts: null
+ type: null
counts:
google_vmwareengine_network: 1
diff --git a/tests/modules/organization/test_plan_org_policies_modules.py b/tests/modules/organization/test_plan_org_policies_modules.py
index b225ba1ec..16e6822cd 100644
--- a/tests/modules/organization/test_plan_org_policies_modules.py
+++ b/tests/modules/organization/test_plan_org_policies_modules.py
@@ -34,7 +34,7 @@ def test_policy_implementation():
'@@ -17 +17 @@\n',
'-# tfdoc:file:description Project-level organization policies.\n',
'+# tfdoc:file:description Folder-level organization policies.\n',
- '@@ -79,2 +79,2 @@\n',
+ '@@ -80,2 +80,2 @@\n',
'- name = "projects/${local.project.project_id}/policies/${each.value}"\n',
'- parent = "projects/${local.project.project_id}"\n',
'+ name = "${local.folder_id}/policies/${each.value}"\n',
@@ -49,12 +49,12 @@ def test_policy_implementation():
'@@ -17 +17 @@\n',
'-# tfdoc:file:description Folder-level organization policies.\n',
'+# tfdoc:file:description Organization-level organization policies.\n',
- '@@ -79,2 +79,2 @@\n',
+ '@@ -80,2 +80,2 @@\n',
'- name = "${local.folder_id}/policies/${each.value}"\n',
'- parent = local.folder_id\n',
'+ name = "${var.organization_id}/policies/${each.value}"\n',
'+ parent = var.organization_id\n',
- '@@ -155,0 +156,9 @@\n',
+ '@@ -156,0 +157,9 @@\n',
'+ depends_on = [\n',
'+ google_organization_iam_binding.authoritative,\n',
'+ google_organization_iam_binding.bindings,\n',
diff --git a/tools/changelog.py b/tools/changelog.py
index cbf1f2abf..ef24066e5 100755
--- a/tools/changelog.py
+++ b/tools/changelog.py
@@ -12,101 +12,126 @@
# 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.
+'''Changelog maintenance.
+
+This script allows adding or replacing individual release sections in our
+CHANGELOG.md file.
+
+It works on a set of simple principles
+
+- a release is identified by two boundaries, the release for which we want to
+ capture PRs (`release_to` or end release) and the release preceding it
+ (`release_from` or start release)
+- the end release can be null, to capture unreleased merged PRs (the
+ 'Unreleased' block in changelog)
+- the start release can be null, to start capturing from the last published
+ release (again to populate the 'Unreleased' block)
+- merged PRs between the start and end times are captured and used to populate
+ the release block
+- PRs are grouped by their `on:` labels, and flagged as containing incompatible
+ changes if they have one of the `breaks:` labels
+- draft PRs or PRs merged against a base different from the one specified via
+ the `merged_to` argument (defaulting to `master`) are ignored
+- the unreleased block can optionally be marked with a release name via the
+ `release_as` argument to prepare for a new release
+
+Example usage:
+
+- update the Unreleased section after PRs have been merged, both start and end
+ releases use defaults, only PRs to `master` are tracked
+ ```
+ ./tools/changelog.py --token=$TOKEN --write
+ ```
+- update an existing release on the master branch
+ ```
+ ./tools/changelog.py --token=$TOKEN --write \
+ --release-from=v34.0.0 --release-to=v35.0.0
+ ```
+- create a new release on the master branch
+ ```
+ ./tools/changelog.py --token=$TOKEN --write \
+ --release-from=v35.0.0 --release-as=v36.0.0
+ ```
+- create an rc release on the fast-dev branch capturing only branch-merged PRs
+ ```
+ ./tools/changelog.py --token=$TOKEN --write \
+ --release-from=v35.0.0 --release-as=v36.0.0-rc1 --merged-to=fast-dev
+ ```
+- create an rc release on the fast-dev branch also capturing master merged PRs
+ e.g. when releasing an rc2 with fast-dev aligned on master
+ ```
+ ./tools/changelog.py --token=$TOKEN --write \
+ --release-from=v35.0.0 --release-as=v36.0.0-rc1 \
+ --merged-to=fast-dev --merged-to=master
+ ```
+'''
import click
import collections
+import datetime
+import functools
+import logging
+import requests
-import ghapi.all
import iso8601
+HEADING = (
+ '# Changelog\n\n'
+ 'All notable changes to this project will be documented in this file.\n'
+ '\n')
LINK_MARKER = ''
ORG = 'GoogleCloudPlatform'
REPO = 'cloud-foundation-fabric'
+API_URL = f'https://api.github.com/repos/{ORG}/{REPO}'
URL = f'https://github.com/{ORG}/{REPO}'
+CHANGE_URL = f'[{{name}}]: {URL}/compare/v{{release_from}}...{{release_to}}'
-PullRequest = collections.namedtuple('PullRequest',
- 'id author title merged_at labels')
FileRelease = collections.namedtuple('FileRelease',
- 'name published since content')
-GitRelease = collections.namedtuple('GitRelease', 'name published since pulls')
-Section = collections.namedtuple('Section', 'text')
+ 'name published content link',
+ defaults=([], None))
+PullRequest = collections.namedtuple('PullRequest',
+ 'id base author title merged_at labels')
class Error(Exception):
pass
-def _paginate(method, **kw):
- 'Paginate GitHub API call.'
- page = 1
- while True:
- result = method(page=page, per_page=100, **kw)
- for item in result:
- yield item
- if len(result) < 100:
- break
- page += 1
+@functools.cache
+def _http(token):
+ 'HTTP requests session with authentication header.'
+ session = requests.Session()
+ session.headers.update({'Authorization': f'Bearer {token}'})
+ return session
-def changelog_load(path):
- 'Parse changelog file and return structured data.'
- releases = []
+def _strip_relname(name):
+ if name is None:
+ return 'Unreleased'
+ if name.startswith('['):
+ name = name[1:-1]
+ if name.startswith('v'):
+ name = name[1:]
+ return name
+
+
+def fetch(token, path, **kw):
+ 'Fetch request and JSON decode response.'
try:
- with open(path) as f:
- for l in f.readlines():
- l = l.strip()
- if l.startswith(LINK_MARKER):
- break
- if l.startswith('## '):
- name, _, date = l[3:].partition(' - ')
- releases.append(FileRelease(name[1:-1], date, None, []))
- elif releases:
- releases[-1].content.append(l)
- return releases
- except (IOError, OSError) as e:
- raise Error(f'Cannot open {path}: {e.args[0]}')
+ resp = _http(token).get(f'{API_URL}/{path}', **kw)
+ except requests.HTTPError as e:
+ raise Error(f'HTTP error: {e}')
+ if resp.status_code != 200:
+ raise Error(f'HTTP status {resp.status_code} for {path}')
+ return resp.json()
-def changelog_dumps(file_releases, git_releases=None):
- 'Return formatted changelog from structured data, overriding versions.'
- git_releases = git_releases or {}
- buffer = [
- ('# Changelog\n\n'
- 'All notable changes to this project will be documented in this file.\n'
- '\n')
- ]
- ref_buffer = ['']
- for i, release in enumerate(file_releases):
- name, published, _, items = release
- prev_name = file_releases[i +
- 1].name if i + 1 < len(file_releases) else '0.1'
- if name != 'Unreleased':
- buffer.append(f'## [{name}] - {published}')
- ref_buffer.append(f'[{name}]: {URL}/compare/v{prev_name}...v{name}')
- else:
- buffer.append(f'## [{name}]')
- ref_buffer.append(f'[Unreleased]: {URL}/compare/v{prev_name}...HEAD')
- release = git_releases.get(name, git_releases.get(f'v{name}'))
- if release:
- buffer.append(f'')
- pulls = group_pulls(release.pulls)
- for k in sorted(pulls.keys(), key=lambda s: s or ''):
- if k is not None:
- buffer.append(f'### {k}\n')
- for pull in pulls[k]:
- buffer.append(format_pull(pull))
- buffer.append('')
- else:
- buffer.append('\n'.join(items))
- return '\n'.join(buffer + ref_buffer + [''])
-
-
-def format_pull(pull):
+def format_pull(pull, group=None):
'Format pull request.'
url = 'https://github.com'
pull_url = f'{url}/{ORG}/{REPO}/pull'
prefix = ''
- if 'incompatible change' in pull.labels:
+ if f'breaks:{group}' in pull.labels or 'incompatible change' in pull.labels:
prefix = '**incompatible change:** '
return (f'- [[#{pull.id}]({pull_url}/{pull.id})] '
f'{prefix}'
@@ -114,7 +139,69 @@ def format_pull(pull):
f'([{pull.author}]({url}/{pull.author})) ')
+def format_release(pull_groups, release_as, release_to, release_from, date_to,
+ date_from):
+ 'Format release changelog heading and text.'
+ if release_as:
+ # if we're releasing date to is today
+ date_to = datetime.date.today()
+ comment = f''
+ if release_to is None and not release_as:
+ buffer = [f'## [{release_as or "Unreleased"}] {comment}']
+ else:
+ buffer = [(f'## [{_strip_relname(release_to or release_as)}] - '
+ f'{date_to.strftime("%Y-%m-%d")} {comment}')]
+ for group in sorted(pull_groups.keys(), key=lambda s: s or ''):
+ if group is not None:
+ buffer.append(f'### {group.upper()}\n')
+ for pull in pull_groups[group]:
+ buffer.append(format_pull(pull, group))
+ buffer.append('')
+ return '\n'.join(buffer)
+
+
+def get_pulls(token, date_from, date_to, merged_to):
+ 'Get and normalize pull requests from the Github API.'
+ url = 'pulls?state=closed&sort=updated&direction=desc&per_page=100'
+ page = 1
+ lookbehinds = 0
+ while True:
+ pulls = fetch(token, f'{url}&page={page}')
+ unmerged = 0
+ for r in pulls:
+ pull_id = r['number']
+ merged_at = r['merged_at']
+ if merged_at is None:
+ unmerged += 1
+ continue
+ pull = PullRequest(pull_id, r['base']['ref'], r['user']['login'],
+ r['title'], iso8601.parse_date(merged_at),
+ [l['name'].lower() for l in r['labels']])
+ if pull.base not in merged_to or pull.merged_at <= date_from:
+ unmerged += 1
+ continue
+ if date_to and pull.merged_at >= date_to:
+ continue
+ yield pull
+ if len(pulls) < 100:
+ break
+ elif unmerged == 100:
+ if lookbehinds >= 1:
+ break
+ lookbehinds += 1
+ page += 1
+
+
+def get_release_date(token, name=None):
+ 'Get published date for a specific release or the latest release.'
+ path = f'releases/tags/{name}' if name else f'releases/latest'
+ release = fetch(token, path)
+ if not release.get('draft'):
+ return iso8601.parse_date(release['published_at'])
+
+
def group_pulls(pulls):
+ 'Group pull requests by on: label.'
pulls.sort(key=lambda p: p.merged_at, reverse=True)
groups = {None: []}
for pull in pulls:
@@ -123,91 +210,118 @@ def group_pulls(pulls):
groups[None].append(pull)
continue
for label in labels:
- group = groups.setdefault(label.upper(), [])
+ group = groups.setdefault(label, [])
group.append(pull)
return groups
-def get_api(token, owner=ORG, name=REPO):
- 'Get GitHub API object.'
- return ghapi.all.GhApi(owner=owner, repo=name, token=token)
+def load_changelog(filename):
+ 'Return structured data from changelog file.'
+ releases = {}
+ links = None
+ name = None
+ try:
+ with open(filename) as f:
+ for l in f.readlines():
+ l = l.strip()
+ if l.startswith(LINK_MARKER):
+ links = {}
+ continue
+ if l.startswith('## '):
+ if l[4:].startswith('Unreleased'):
+ name, date = 'Unreleased', ''
+ else:
+ name, _, date = l[3:].partition(' - ')
+ name = _strip_relname(name)
+ if not date.strip():
+ date = datetime.date.today()
+ else:
+ date = datetime.datetime.strptime(date.split()[0],
+ '%Y-%m-%d').date()
+ releases[name] = FileRelease(name, date, [l])
+ elif name and links is None:
+ releases[name].content.append(l)
+ elif l.startswith('['):
+ name, _, _ = l.partition(':')
+ links[_strip_relname(name)] = l
+ except (IOError, OSError) as e:
+ raise Error(f'Cannot open {filename}: {e.args[0]}')
+ return releases, links
-def get_pulls(api):
- 'Get all pull requests (GH sometimes forgets pulls with filters).'
- pulls = []
- # this should be done on the fly with sort='updated', direction='desc'
- # if the API could be trusted (they cannot)
- for p in _paginate(api.pulls.list, base='master', state='closed'):
- try:
- merged_at = iso8601.parse_date(p['merged_at'])
- except iso8601.ParseError:
- continue
- pulls.append(
- PullRequest(p['number'], p['user']['login'], p['title'], merged_at,
- [l['name'] for l in p['labels']]))
- pulls.sort(key=lambda p: p.merged_at, reverse=True)
- return pulls
-
-
-def get_release_pulls(api, releases):
- 'Get and add pull requests for releases.'
- i = 0
- for p in get_pulls(api):
- if releases[i].published and p.merged_at >= releases[i].published:
- continue
- if releases[i].since and p.merged_at <= releases[i].since:
- i += 1
- if i == len(releases):
- break
- releases[i].pulls.append(p)
- return releases
-
-
-def get_releases(api, filter_names=None):
- 'Get releases with optional filter on release names.'
- Buffer = collections.namedtuple('Buffer', 'name published')
- buffer = Buffer('Unreleased', None)
- for r in _paginate(api.repos.list_releases):
- published = iso8601.parse_date(r['published_at'])
- if not filter_names or buffer.name in filter_names:
- yield GitRelease(buffer.name, buffer.published, published, [])
- buffer = Buffer(r['name'], published)
- if buffer and (not filter_names or buffer.name in filter_names):
- yield GitRelease(buffer.name, buffer.published, None, [])
+def write_changelog(releases, links, rel_changes, release_as, release_to,
+ release_from, filename='CHANGELOG.md'):
+ 'Inject the pull request data and write changelog to file.'
+ rel_buffer, link_buffer = [], []
+ release_to = _strip_relname(release_to)
+ sorted_releases = sorted(releases.values(), reverse=True,
+ key=lambda r: r.published)
+ if release_as:
+ # inject an empty 'Unreleased' block as the current one will be replaced
+ rel_buffer.append('## Unreleased\n')
+ rel_link = CHANGE_URL.format(name='Unreleased', release_from=release_as,
+ release_to='HEAD')
+ link_buffer.append(rel_link)
+ for rel in sorted_releases:
+ rel_link = links.get(rel.name)
+ if rel_link is None:
+ raise Error(f"no link found for {rel.name}")
+ if rel.name == release_to:
+ rel_buffer.append(rel_changes)
+ if release_as:
+ rel_link = CHANGE_URL.format(name=release_as, release_from=release_from,
+ release_to=release_as)
+ else:
+ rel_buffer.append('\n'.join(rel.content))
+ link_buffer.append(rel_link)
+ open(filename, 'w').write(
+ '\n'.join([HEADING] + rel_buffer +
+ [''] + link_buffer))
@click.command
-@click.option('--all-releases', is_flag=True, default=False,
- help='All releases.')
+@click.option('--merged-to', required=False, default=('master',), multiple=True,
+ help='Only include PRs merged to these branches.')
+@click.option('--release-as', required=False, default=None,
+ help='Use this name for the Unreleased section as a new release.')
@click.option(
- '--release', required=False, default=['Unreleased'], multiple=True,
- help='Release to replace, specify multiple times for more than one version.'
+ '--release-from', required=False, default=None,
+ help='Lower bound of the comparison, defaults to previous full release.')
+@click.option(
+ '--release-to', required=False, default=None, help=
+ 'Release to replace and use as upper bound of the comparison. Leave unspecified for a new release.'
)
@click.option('--token', required=True, envvar='GH_TOKEN',
help='GitHub API token.')
@click.option('--write', '-w', is_flag=True, required=False, default=False,
help='Write modified changelog file.')
-@click.argument('changelog', required=False, default='CHANGELOG.md',
+@click.option('--verbose', '-v', is_flag=True, default=False,
+ help='Print information about the running operations')
+@click.argument('changelog-file', required=False, default='CHANGELOG.md',
type=click.Path(exists=True))
-def main(token, changelog='CHANGELOG.md', all_releases=False, release=None,
- write=False):
- api = get_api(token)
- release = [] if all_releases else release
- releases = [r for r in get_releases(api, release)]
- releases = {r.name: r for r in get_release_pulls(api, releases)}
+def main(token, changelog_file='CHANGELOG.md', merged_to=None, release_as=None,
+ release_from=None, release_to=None, write=False, verbose=False):
+ logging.basicConfig(level=logging.INFO if verbose else logging.WARNING)
+ if release_as is not None and release_to is not None:
+ raise SystemExit('Only one of `release_as` and `release_to` can be used.')
try:
- changelog_releases = changelog_load(changelog)
- result = changelog_dumps(changelog_releases, releases)
+ date_from = get_release_date(token, release_from)
+ logging.info(f'release date from: {date_from}')
+ date_to = None if not release_to else get_release_date(token, release_to)
+ logging.info(f'release date to: {date_to}')
+ pulls = list(get_pulls(token, date_from, date_to, merged_to or ('master',)))
+ logging.info(f'number of pulls: {len(pulls)}')
+ pull_groups = group_pulls(pulls)
+ rel_changes = format_release(pull_groups, release_as, release_to,
+ release_from, date_to, date_from)
+ if not write:
+ print(rel_changes)
+ raise SystemExit(0)
+ releases, links = load_changelog(changelog_file)
+ write_changelog(releases, links, rel_changes, release_as, release_to,
+ release_from, changelog_file)
except Error as e:
- raise SystemExit(f'Cannot read or generate changelog: {e.args[0]}')
- if not write:
- print(result)
- else:
- try:
- open(changelog, 'w').write(result)
- except (IOError, OSError) as e:
- raise SystemExit('Cannot write to changelog file.')
+ raise SystemExit(f'Error running command: {e}')
if __name__ == '__main__':
diff --git a/tools/lockfile/versions.tf b/tools/lockfile/versions.tf
index 08cda2815..3018c9bf9 100644
--- a/tools/lockfile/versions.tf
+++ b/tools/lockfile/versions.tf
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# Fabric release: v35.1.0
+# Fabric release: v36.0.0
terraform {
required_version = ">= 1.7.4"
diff --git a/tools/tfdoc.py b/tools/tfdoc.py
index 85e6fbd5b..04e7db91d 100755
--- a/tools/tfdoc.py
+++ b/tools/tfdoc.py
@@ -73,7 +73,7 @@ FILE_RE_RESOURCES = re.compile(r'(?sm)resource\s+"([^"]+)"')
HEREDOC_RE = re.compile(r'(?sm)^<<\-?END(\s*.*?)\s*END$')
MARK_BEGIN = ''
MARK_END = ''
-MARK_OPTS_RE = re.compile(r'(?sm)')
+MARK_OPTS_RE = re.compile(r'(?sm)')
OUT_ENUM = enum.Enum('O', 'OPEN ATTR ATTR_DATA CLOSE COMMENT TXT SKIP')
OUT_RE = re.compile(r'''(?smx)
# output open
@@ -193,6 +193,8 @@ def create_tfref(module_path, files=False, show_extra=False, exclude_files=None,
opts = get_tfref_opts(readme)
files = opts.get('files', files)
show_extra = opts.get('show_extra', show_extra)
+ if 'exclude' in opts:
+ exclude_files = (exclude_files or []) + [opts['exclude']]
abspath = os.path.abspath(module_path)
try:
if os.path.dirname(abspath).endswith('/modules'):
@@ -346,7 +348,7 @@ def get_tfref_opts(readme):
try:
for o in m.group(1).split():
k, v = o.split(':')
- opts[k] = bool(int(v))
+ opts[k] = v if k == 'exclude' else bool(int(v))
except (TypeError, ValueError) as e:
raise SystemExit(f'incorrect option mark: {e}')
return opts
@@ -513,7 +515,10 @@ def render_toc(readme, toc):
def main(module_path=None, exclude_file=None, files=False, replace=True,
show_extra=True, toc_only=False):
'Program entry point.'
- readme_path = os.path.join(module_path, 'README.md')
+ if toc_only and module_path.endswith('.md'):
+ readme_path = module_path
+ else:
+ readme_path = os.path.join(module_path, 'README.md')
readme = get_readme(readme_path)
if not toc_only:
doc = create_tfref(module_path, files, show_extra, exclude_file, readme)