diff --git a/blueprints/gcve/pc-minimal/README.md b/blueprints/gcve/pc-minimal/README.md new file mode 100644 index 000000000..a749b787f --- /dev/null +++ b/blueprints/gcve/pc-minimal/README.md @@ -0,0 +1,106 @@ +# 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 indipendent 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/diagram.png b/blueprints/gcve/pc-minimal/diagram.png
new file mode 100644
index 000000000..78ae82b24
Binary files /dev/null and b/blueprints/gcve/pc-minimal/diagram.png differ
diff --git a/blueprints/gcve/pc-minimal/gcve-pc.tf b/blueprints/gcve/pc-minimal/gcve-pc.tf
new file mode 100644
index 000000000..2cbd1e1e2
--- /dev/null
+++ b/blueprints/gcve/pc-minimal/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.
+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
new file mode 100644
index 000000000..2d9f5c8ef
--- /dev/null
+++ b/blueprints/gcve/pc-minimal/main.tf
@@ -0,0 +1,39 @@
+/**
+ * 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/gcve/pc-minimal/output.tf b/blueprints/gcve/pc-minimal/output.tf
new file mode 100644
index 000000000..ba6f2ebfe
--- /dev/null
+++ b/blueprints/gcve/pc-minimal/output.tf
@@ -0,0 +1,40 @@
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# 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.
+
+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
+}
diff --git a/blueprints/gcve/pc-minimal/variables.tf b/blueprints/gcve/pc-minimal/variables.tf
new file mode 100644
index 000000000..fa0c99e69
--- /dev/null
+++ b/blueprints/gcve/pc-minimal/variables.tf
@@ -0,0 +1,122 @@
+/**
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+variable "billing_account_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))
+ 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 "network_peerings" {
+ description = "The network peerings between users' VPCs and the VMware Engine networks. The key is the peering name suffix."
+ 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)
+ }), {})
+ description = optional(string, "Managed by Terraform.")
+ peer_project_id = optional(string)
+ peer_to_vmware_engine_network = 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."
+ }
+}
+
+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_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
+}
diff --git a/fast/stages/0-bootstrap/README.md b/fast/stages/0-bootstrap/README.md
index 1e80e2852..3b3d6ce60 100644
--- a/fast/stages/0-bootstrap/README.md
+++ b/fast/stages/0-bootstrap/README.md
@@ -626,26 +626,26 @@ The `fast_features` variable consists of 4 toggles:
| name | description | type | required | default | producer |
|---|---|:---:|:---:|:---:|:---:|
| [billing_account](variables.tf#L17) | Billing account id. If billing account is not part of the same org set `is_org_level` to `false`. To disable handling of billing IAM roles set `no_iam` to `true`. | object({…}) | ✓ | | |
-| [organization](variables.tf#L229) | Organization details. | object({…}) | ✓ | | |
-| [prefix](variables.tf#L244) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | |
+| [organization](variables.tf#L230) | Organization details. | object({…}) | ✓ | | |
+| [prefix](variables.tf#L245) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | |
| [bootstrap_user](variables.tf#L27) | Email of the nominal user running this stage for the first time. | string | | null | |
| [cicd_repositories](variables.tf#L33) | CI/CD repository configuration. Identity providers reference keys in the `federated_identity_providers` variable. Set to null to disable, or set individual repositories to null if not needed. | object({…}) | | null | |
| [custom_roles](variables.tf#L79) | Map of role names => list of permissions to additionally create at the organization level. | map(list(string)) | | {} | |
| [essential_contacts](variables.tf#L86) | Email used for essential contacts, unset if null. | string | | null | |
| [factories_config](variables.tf#L92) | Configuration for the resource factories or external data. | object({…}) | | {} | |
-| [fast_features](variables.tf#L104) | Selective control for top-level FAST features. | object({…}) | | {} | |
-| [group_iam](variables.tf#L117) | Organization-level authoritative IAM binding for groups, in {GROUP_EMAIL => [ROLES]} format. Group emails need to be static. Can be used in combination with the `iam` variable. | map(list(string)) | | {} | |
-| [groups](variables.tf#L124) | 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#L140) | Organization-level custom IAM settings in role => [principal] format. | map(list(string)) | | {} | |
-| [iam_bindings_additive](variables.tf#L147) | Organization-level custom additive IAM bindings. Keys are arbitrary. | map(object({…})) | | {} | |
-| [iam_by_principals](variables.tf#L162) | 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#L169) | Optional locations for GCS, BigQuery, and logging buckets created here. | object({…}) | | {} | |
-| [log_sinks](variables.tf#L183) | Org-level log sinks, in name => {type, filter} format. | map(object({…})) | | {…} | |
-| [org_policies_config](variables.tf#L212) | Organization policies customization. | object({…}) | | {} | |
-| [outputs_location](variables.tf#L238) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable. | string | | null | |
-| [project_parent_ids](variables.tf#L253) | Optional parents for projects created here in folders/nnnnnnn format. Null values will use the organization as parent. | object({…}) | | {} | |
-| [workforce_identity_providers](variables.tf#L264) | Workforce Identity Federation pools. | map(object({…})) | | {} | |
-| [workload_identity_providers](variables.tf#L280) | Workload Identity Federation pools. The `cicd_repositories` variable references keys here. | map(object({…})) | | {} | |
+| [fast_features](variables.tf#L104) | Selective control for top-level FAST features. | object({…}) | | {} | |
+| [group_iam](variables.tf#L118) | Organization-level authoritative IAM binding for groups, in {GROUP_EMAIL => [ROLES]} format. Group emails need to be static. Can be used in combination with the `iam` variable. | map(list(string)) | | {} | |
+| [groups](variables.tf#L125) | 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#L141) | Organization-level custom IAM settings in role => [principal] format. | map(list(string)) | | {} | |
+| [iam_bindings_additive](variables.tf#L148) | Organization-level custom additive IAM bindings. Keys are arbitrary. | map(object({…})) | | {} | |
+| [iam_by_principals](variables.tf#L163) | 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#L170) | Optional locations for GCS, BigQuery, and logging buckets created here. | object({…}) | | {} | |
+| [log_sinks](variables.tf#L184) | Org-level log sinks, in name => {type, filter} format. | map(object({…})) | | {…} | |
+| [org_policies_config](variables.tf#L213) | Organization policies customization. | object({…}) | | {} | |
+| [outputs_location](variables.tf#L239) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable. | string | | null | |
+| [project_parent_ids](variables.tf#L254) | Optional parents for projects created here in folders/nnnnnnn format. Null values will use the organization as parent. | object({…}) | | {} | |
+| [workforce_identity_providers](variables.tf#L265) | Workforce Identity Federation pools. | map(object({…})) | | {} | |
+| [workload_identity_providers](variables.tf#L281) | Workload Identity Federation pools. The `cicd_repositories` variable references keys here. | map(object({…})) | | {} | |
## Outputs
diff --git a/fast/stages/0-bootstrap/data/custom-roles/gcve_network_admin.yaml b/fast/stages/0-bootstrap/data/custom-roles/gcve_network_admin.yaml
new file mode 100644
index 000000000..255ac781e
--- /dev/null
+++ b/fast/stages/0-bootstrap/data/custom-roles/gcve_network_admin.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.
+
+name: gcveNetworkAdmin
+includedPermissions:
+ - vmwareengine.networkPeerings.create
+ - vmwareengine.networkPeerings.delete
+ - vmwareengine.networkPeerings.get
+ - vmwareengine.networkPeerings.list
+ - vmwareengine.operations.get
diff --git a/fast/stages/0-bootstrap/variables.tf b/fast/stages/0-bootstrap/variables.tf
index d8536fc26..5493f5d62 100644
--- a/fast/stages/0-bootstrap/variables.tf
+++ b/fast/stages/0-bootstrap/variables.tf
@@ -105,6 +105,7 @@ variable "fast_features" {
description = "Selective control for top-level FAST features."
type = object({
data_platform = optional(bool, false)
+ gcve = optional(bool, false)
gke = optional(bool, false)
project_factory = optional(bool, false)
sandbox = optional(bool, false)
diff --git a/fast/stages/1-resman/README.md b/fast/stages/1-resman/README.md
index a84c704f9..628280ac7 100644
--- a/fast/stages/1-resman/README.md
+++ b/fast/stages/1-resman/README.md
@@ -327,6 +327,7 @@ Due to its simplicity, this stage lends itself easily to customizations: adding
|---|---|---|---|
| [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-project-factory.tf](./branch-project-factory.tf) | Project factory stage resources. | gcs · iam-service-account | |
@@ -336,6 +337,7 @@ Due to its simplicity, this stage lends itself easily to customizations: adding
| [branch-tenants.tf](./branch-tenants.tf) | Lightweight tenant resources. | folder · gcs · iam-service-account · project | |
| [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 · source-repository | |
+| [cicd-gcve.tf](./cicd-gcve.tf) | CI/CD resources for the GCVE branch. | iam-service-account · source-repository | |
| [cicd-gke.tf](./cicd-gke.tf) | CI/CD resources for the GKE multitenant branch. | iam-service-account · source-repository | |
| [cicd-networking.tf](./cicd-networking.tf) | CI/CD resources for the networking branch. | iam-service-account · source-repository | |
| [cicd-project-factory.tf](./cicd-project-factory.tf) | CI/CD resources for the teams branch. | iam-service-account · source-repository | |
@@ -356,35 +358,36 @@ Due to its simplicity, this stage lends itself easily to customizations: adding
|---|---|:---:|:---:|:---:|:---:|
| [automation](variables.tf#L20) | Automation resources created by the bootstrap stage. | object({…}) | ✓ | | 0-bootstrap |
| [billing_account](variables.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 |
-| [organization](variables.tf#L213) | Organization details. | object({…}) | ✓ | | 0-bootstrap |
-| [prefix](variables.tf#L229) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 0-bootstrap |
-| [cicd_repositories](variables.tf#L53) | 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.tf#L135) | Custom roles defined at the org level, in key => id format. | object({…}) | | null | 0-bootstrap |
-| [factories_config](variables.tf#L145) | Configuration for the resource factories or external data. | object({…}) | | {} | |
-| [fast_features](variables.tf#L154) | Selective control for top-level FAST features. | object({…}) | | {} | 0-0-bootstrap |
-| [groups](variables.tf#L168) | 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.tf#L183) | Optional locations for GCS, BigQuery, and logging buckets created here. | object({…}) | | {…} | 0-bootstrap |
-| [org_policy_tags](variables.tf#L201) | Resource management tags for organization policy exceptions. | object({…}) | | {} | 0-bootstrap |
-| [outputs_location](variables.tf#L223) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable. | string | | null | |
-| [tag_names](variables.tf#L240) | Customized names for resource management tags. | object({…}) | | {} | |
-| [tags](variables.tf#L255) | Custome secure tags by key name. The `iam` attribute behaves like the similarly named one at module level. | map(object({…})) | | {} | |
-| [team_folders](variables.tf#L276) | Team folders to be created. Format is described in a code comment. | map(object({…})) | | null | |
-| [tenants](variables.tf#L292) | Lightweight tenant definitions. | map(object({…})) | | {} | |
-| [tenants_config](variables.tf#L308) | Lightweight tenants shared configuration. Roles will be assigned to tenant admin group and service accounts. | object({…}) | | {} | |
+| [organization](variables.tf#L227) | Organization details. | object({…}) | ✓ | | 0-bootstrap |
+| [prefix](variables.tf#L243) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 0-bootstrap |
+| [cicd_repositories](variables.tf#L53) | 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.tf#L147) | Custom roles defined at the org level, in key => id format. | object({…}) | | null | 0-bootstrap |
+| [factories_config](variables.tf#L158) | Configuration for the resource factories or external data. | object({…}) | | {} | |
+| [fast_features](variables.tf#L167) | Selective control for top-level FAST features. | object({…}) | | {} | 0-0-bootstrap |
+| [groups](variables.tf#L182) | 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.tf#L197) | Optional locations for GCS, BigQuery, and logging buckets created here. | object({…}) | | {…} | 0-bootstrap |
+| [org_policy_tags](variables.tf#L215) | Resource management tags for organization policy exceptions. | object({…}) | | {} | 0-bootstrap |
+| [outputs_location](variables.tf#L237) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable. | string | | null | |
+| [tag_names](variables.tf#L254) | Customized names for resource management tags. | object({…}) | | {} | |
+| [tags](variables.tf#L269) | Custome secure tags by key name. The `iam` attribute behaves like the similarly named one at module level. | map(object({…})) | | {} | |
+| [team_folders](variables.tf#L290) | Team folders to be created. Format is described in a code comment. | map(object({…})) | | null | |
+| [tenants](variables.tf#L306) | Lightweight tenant definitions. | map(object({…})) | | {} | |
+| [tenants_config](variables.tf#L322) | Lightweight tenants shared configuration. Roles will be assigned to tenant admin group and service accounts. | object({…}) | | {} | |
## Outputs
| name | description | sensitive | consumers |
|---|---|:---:|---|
-| [cicd_repositories](outputs.tf#L337) | WIF configuration for CI/CD repositories. | | |
-| [dataplatform](outputs.tf#L351) | Data for the Data Platform stage. | | |
-| [gke_multitenant](outputs.tf#L367) | Data for the GKE multitenant stage. | | 03-gke-multitenant |
-| [networking](outputs.tf#L388) | Data for the networking stage. | | |
-| [project_factories](outputs.tf#L397) | Data for the project factories stage. | | |
-| [providers](outputs.tf#L412) | Terraform provider files for this stage and dependent stages. | ✓ | 02-networking · 02-security · 03-dataplatform · xx-sandbox · xx-teams |
-| [sandbox](outputs.tf#L419) | Data for the sandbox stage. | | xx-sandbox |
-| [security](outputs.tf#L433) | Data for the networking stage. | | 02-security |
-| [team_cicd_repositories](outputs.tf#L443) | WIF configuration for Team CI/CD repositories. | | |
-| [teams](outputs.tf#L457) | Data for the teams stage. | | |
-| [tfvars](outputs.tf#L469) | Terraform variable files for the following stages. | ✓ | |
+| [cicd_repositories](outputs.tf#L391) | WIF configuration for CI/CD repositories. | | |
+| [dataplatform](outputs.tf#L405) | Data for the Data Platform stage. | | |
+| [gcve](outputs.tf#L421) | Data for the GCVE stage. | | 03-gke-multitenant |
+| [gke_multitenant](outputs.tf#L442) | Data for the GKE multitenant stage. | | 03-gke-multitenant |
+| [networking](outputs.tf#L463) | Data for the networking stage. | | |
+| [project_factories](outputs.tf#L472) | Data for the project factories stage. | | |
+| [providers](outputs.tf#L487) | Terraform provider files for this stage and dependent stages. | ✓ | 02-networking · 02-security · 03-dataplatform · xx-sandbox · xx-teams |
+| [sandbox](outputs.tf#L494) | Data for the sandbox stage. | | xx-sandbox |
+| [security](outputs.tf#L508) | Data for the networking stage. | | 02-security |
+| [team_cicd_repositories](outputs.tf#L518) | WIF configuration for Team CI/CD repositories. | | |
+| [teams](outputs.tf#L532) | Data for the teams stage. | | |
+| [tfvars](outputs.tf#L544) | Terraform variable files for the following stages. | ✓ | |
diff --git a/fast/stages/1-resman/billing.tf b/fast/stages/1-resman/billing.tf
index c18708424..64b87c265 100644
--- a/fast/stages/1-resman/billing.tf
+++ b/fast/stages/1-resman/billing.tf
@@ -27,6 +27,8 @@ locals {
local.branch_optional_sa_lists.dp-prod,
local.branch_optional_sa_lists.gke-dev,
local.branch_optional_sa_lists.gke-prod,
+ local.branch_optional_sa_lists.gcve-dev,
+ local.branch_optional_sa_lists.gcve-prod,
local.branch_optional_sa_lists.pf-dev,
local.branch_optional_sa_lists.pf-prod,
)
diff --git a/fast/stages/1-resman/branch-gcve.tf b/fast/stages/1-resman/branch-gcve.tf
new file mode 100644
index 000000000..43b737626
--- /dev/null
+++ b/fast/stages/1-resman/branch-gcve.tf
@@ -0,0 +1,199 @@
+/**
+ * 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 GCVE stage resources.
+
+module "branch-gcve-folder" {
+ source = "../../../modules/folder"
+ count = var.fast_features.gcve ? 1 : 0
+ parent = "organizations/${var.organization.id}"
+ name = "GCVE"
+ tag_bindings = {
+ context = try(
+ module.organization.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(
+ module.organization.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(
+ module.organization.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
+ storage_class = local.gcs_storage_class
+ 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
+ storage_class = local.gcs_storage_class
+ 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-networking.tf b/fast/stages/1-resman/branch-networking.tf
index 48bb88dcf..5bb641c61 100644
--- a/fast/stages/1-resman/branch-networking.tf
+++ b/fast/stages/1-resman/branch-networking.tf
@@ -54,14 +54,17 @@ module "branch-network-prod-folder" {
(local.custom_roles.service_project_network_admin) = concat(
local.branch_optional_sa_lists.dp-prod,
local.branch_optional_sa_lists.gke-prod,
+ local.branch_optional_sa_lists.gcve-prod,
local.branch_optional_sa_lists.pf-prod,
)
# read-only (plan) automation service accounts
"roles/compute.networkViewer" = concat(
local.branch_optional_r_sa_lists.dp-prod,
local.branch_optional_r_sa_lists.gke-prod,
+ local.branch_optional_r_sa_lists.gcve-prod,
local.branch_optional_r_sa_lists.pf-prod,
)
+ (local.custom_roles.gcve_network_admin) = local.branch_optional_sa_lists.gcve-prod
}
tag_bindings = {
environment = try(
@@ -80,14 +83,17 @@ module "branch-network-dev-folder" {
(local.custom_roles.service_project_network_admin) = concat(
local.branch_optional_sa_lists.dp-dev,
local.branch_optional_sa_lists.gke-dev,
+ local.branch_optional_sa_lists.gcve-dev,
local.branch_optional_sa_lists.pf-dev,
)
# read-only (plan) automation service accounts
"roles/compute.networkViewer" = concat(
local.branch_optional_r_sa_lists.dp-prod,
local.branch_optional_r_sa_lists.gke-prod,
+ local.branch_optional_r_sa_lists.gcve-dev,
local.branch_optional_r_sa_lists.pf-prod,
)
+ (local.custom_roles.gcve_network_admin) = local.branch_optional_sa_lists.gcve-dev
}
tag_bindings = {
environment = try(
diff --git a/fast/stages/1-resman/cicd-gcve.tf b/fast/stages/1-resman/cicd-gcve.tf
new file mode 100644
index 000000000..7cadd653a
--- /dev/null
+++ b/fast/stages/1-resman/cicd-gcve.tf
@@ -0,0 +1,245 @@
+/**
+ * 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 CI/CD resources for the GCVE branch.
+
+# source repositories
+
+module "branch-gcve-dev-cicd-repo" {
+ source = "../../../modules/source-repository"
+ for_each = (
+ try(local.cicd_repositories.gcve_dev.type, null) == "sourcerepo"
+ ? { 0 = local.cicd_repositories.gcve_dev }
+ : {}
+ )
+ project_id = var.automation.project_id
+ name = each.value.name
+ iam = {
+ "roles/source.admin" = compact([
+ try(module.branch-gcve-dev-sa.0.iam_email, "")
+ ])
+ "roles/source.reader" = compact([
+ try(module.branch-gcve-dev-sa-cicd.0.iam_email, "")
+ ])
+ }
+ triggers = {
+ fast-03-gcve-dev = {
+ filename = ".cloudbuild/workflow.yaml"
+ included_files = [
+ "**/*json", "**/*tf", "**/*yaml", ".cloudbuild/workflow.yaml"
+ ]
+ service_account = module.branch-gcve-dev-sa-cicd.0.id
+ substitutions = {}
+ template = {
+ project_id = null
+ branch_name = each.value.branch
+ repo_name = each.value.name
+ tag_name = null
+ }
+ }
+ }
+ depends_on = [module.branch-gcve-dev-sa-cicd]
+}
+
+module "branch-gcve-prod-cicd-repo" {
+ source = "../../../modules/source-repository"
+ for_each = (
+ try(local.cicd_repositories.gcve_prod.type, null) == "sourcerepo"
+ ? { 0 = local.cicd_repositories.gcve_prod }
+ : {}
+ )
+ project_id = var.automation.project_id
+ name = each.value.name
+ iam = {
+ "roles/source.admin" = [module.branch-gcve-prod-sa.0.iam_email]
+ "roles/source.reader" = [module.branch-gcve-prod-sa-cicd.0.iam_email]
+ }
+ triggers = {
+ fast-03-gcve-prod = {
+ filename = ".cloudbuild/workflow.yaml"
+ included_files = [
+ "**/*json", "**/*tf", "**/*yaml", ".cloudbuild/workflow.yaml"
+ ]
+ service_account = module.branch-gcve-prod-sa-cicd.0.id
+ substitutions = {}
+ template = {
+ project_id = null
+ branch_name = each.value.branch
+ repo_name = each.value.name
+ tag_name = null
+ }
+ }
+ }
+ depends_on = [module.branch-gcve-prod-sa-cicd]
+}
+
+# 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 = (
+ each.value.type == "sourcerepo"
+ # used directly from the cloud build trigger for source repos
+ ? {
+ "roles/iam.serviceAccountUser" = local.automation_resman_sa_iam
+ }
+ # impersonated via workload identity federation for external repos
+ : {
+ "roles/iam.workloadIdentityUser" = [
+ each.value.branch == null
+ ? format(
+ local.identity_providers[each.value.identity_provider].principal_repo,
+ var.automation.federated_identity_pool,
+ each.value.name
+ )
+ : format(
+ local.identity_providers[each.value.identity_provider].principal_branch,
+ var.automation.federated_identity_pool,
+ each.value.name,
+ each.value.branch
+ )
+ ]
+ }
+ )
+ iam_project_roles = {
+ (var.automation.project_id) = ["roles/logging.logWriter"]
+ }
+ iam_storage_roles = {
+ (var.automation.outputs_bucket) = ["roles/storage.objectViewer"]
+ }
+}
+
+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 = (
+ each.value.type == "sourcerepo"
+ # used directly from the cloud build trigger for source repos
+ ? {
+ "roles/iam.serviceAccountUser" = local.automation_resman_sa_iam
+ }
+ # impersonated via workload identity federation for external repos
+ : {
+ "roles/iam.workloadIdentityUser" = [
+ each.value.branch == null
+ ? format(
+ local.identity_providers[each.value.identity_provider].principal_repo,
+ var.automation.federated_identity_pool,
+ each.value.name
+ )
+ : format(
+ local.identity_providers[each.value.identity_provider].principal_branch,
+ var.automation.federated_identity_pool,
+ each.value.name,
+ each.value.branch
+ )
+ ]
+ }
+ )
+ iam_project_roles = {
+ (var.automation.project_id) = ["roles/logging.logWriter"]
+ }
+ iam_storage_roles = {
+ (var.automation.outputs_bucket) = ["roles/storage.objectViewer"]
+ }
+}
+
+# read-only (plan) 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 = (
+ each.value.type == "sourcerepo"
+ # build trigger for read-only SA is optionally defined by users
+ ? {}
+ # impersonated via workload identity federation for external repos
+ : {
+ "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 = (
+ each.value.type == "sourcerepo"
+ # build trigger for read-only SA is optionally defined by users
+ ? {}
+ # impersonated via workload identity federation for external repos
+ : {
+ "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/main.tf b/fast/stages/1-resman/main.tf
index 9d85a33f2..19d2e8c5c 100644
--- a/fast/stages/1-resman/main.tf
+++ b/fast/stages/1-resman/main.tf
@@ -26,20 +26,24 @@ locals {
)
# service accounts that receive additional grants on networking/security
branch_optional_sa_lists = {
- dp-dev = compact([try(module.branch-dp-dev-sa.0.iam_email, "")])
- dp-prod = compact([try(module.branch-dp-prod-sa.0.iam_email, "")])
- gke-dev = compact([try(module.branch-gke-dev-sa.0.iam_email, "")])
- gke-prod = compact([try(module.branch-gke-prod-sa.0.iam_email, "")])
- pf-dev = compact([try(module.branch-pf-dev-sa.0.iam_email, "")])
- pf-prod = compact([try(module.branch-pf-prod-sa.0.iam_email, "")])
+ dp-dev = compact([try(module.branch-dp-dev-sa.0.iam_email, "")])
+ dp-prod = compact([try(module.branch-dp-prod-sa.0.iam_email, "")])
+ gcve-dev = compact([try(module.branch-gcve-dev-sa.0.iam_email, "")])
+ gcve-prod = compact([try(module.branch-gcve-prod-sa.0.iam_email, "")])
+ gke-dev = compact([try(module.branch-gke-dev-sa.0.iam_email, "")])
+ gke-prod = compact([try(module.branch-gke-prod-sa.0.iam_email, "")])
+ pf-dev = compact([try(module.branch-pf-dev-sa.0.iam_email, "")])
+ pf-prod = compact([try(module.branch-pf-prod-sa.0.iam_email, "")])
}
branch_optional_r_sa_lists = {
- dp-dev = compact([try(module.branch-dp-dev-r-sa.0.iam_email, "")])
- dp-prod = compact([try(module.branch-dp-prod-r-sa.0.iam_email, "")])
- gke-dev = compact([try(module.branch-gke-dev-r-sa.0.iam_email, "")])
- gke-prod = compact([try(module.branch-gke-prod-r-sa.0.iam_email, "")])
- pf-dev = compact([try(module.branch-pf-dev-r-sa.0.iam_email, "")])
- pf-prod = compact([try(module.branch-pf-prod-r-sa.0.iam_email, "")])
+ dp-dev = compact([try(module.branch-dp-dev-r-sa.0.iam_email, "")])
+ dp-prod = compact([try(module.branch-dp-prod-r-sa.0.iam_email, "")])
+ gcve-dev = compact([try(module.branch-gcve-dev-r-sa.0.iam_email, "")])
+ gcve-prod = compact([try(module.branch-gcve-prod-r-sa.0.iam_email, "")])
+ gke-dev = compact([try(module.branch-gke-dev-r-sa.0.iam_email, "")])
+ gke-prod = compact([try(module.branch-gke-prod-r-sa.0.iam_email, "")])
+ pf-dev = compact([try(module.branch-pf-dev-r-sa.0.iam_email, "")])
+ pf-prod = compact([try(module.branch-pf-prod-r-sa.0.iam_email, "")])
}
# normalize CI/CD repositories
cicd_repositories = {
diff --git a/fast/stages/1-resman/organization.tf b/fast/stages/1-resman/organization.tf
index 90ded30e4..6c380c893 100644
--- a/fast/stages/1-resman/organization.tf
+++ b/fast/stages/1-resman/organization.tf
@@ -50,6 +50,7 @@ module "organization" {
values = {
data = {}
gke = {}
+ gcve = {}
networking = {}
sandbox = {}
security = {}
diff --git a/fast/stages/1-resman/outputs.tf b/fast/stages/1-resman/outputs.tf
index 8d229e68b..38aa35c4c 100644
--- a/fast/stages/1-resman/outputs.tf
+++ b/fast/stages/1-resman/outputs.tf
@@ -39,6 +39,28 @@ locals {
}
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)
@@ -125,6 +147,8 @@ locals {
{
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)
@@ -226,6 +250,32 @@ locals {
sa = module.branch-gke-prod-r-sa.0.email
})
},
+ !var.fast_features.gcve ? {} : {
+ "3-gcve-dev" = templatefile(local._tpl_providers, {
+ 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" = templatefile(local._tpl_providers, {
+ 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" = templatefile(local._tpl_providers, {
+ 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" = templatefile(local._tpl_providers, {
+ 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.project_factory ? {} : {
"3-project-factory-dev" = templatefile(local._tpl_providers, {
backend_extra = null
@@ -286,6 +336,10 @@ locals {
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)
@@ -364,6 +418,27 @@ output "dataplatform" {
}
}
+output "gcve" {
+ # tfdoc:output:consumers 03-gke-multitenant
+ 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."
diff --git a/fast/stages/1-resman/variables.tf b/fast/stages/1-resman/variables.tf
index 3987e81f3..02ec155a2 100644
--- a/fast/stages/1-resman/variables.tf
+++ b/fast/stages/1-resman/variables.tf
@@ -77,6 +77,18 @@ variable "cicd_repositories" {
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)
+ }))
networking = optional(object({
name = string
type = string
@@ -136,6 +148,7 @@ 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
service_project_network_admin = string
storage_viewer = string
})
@@ -157,6 +170,7 @@ variable "fast_features" {
type = object({
data_platform = optional(bool, false)
gke = optional(bool, false)
+ gcve = optional(bool, false)
project_factory = optional(bool, false)
sandbox = optional(bool, false)
teams = optional(bool, false)
diff --git a/fast/stages/2-networking-a-peering/README.md b/fast/stages/2-networking-a-peering/README.md
index 27272d0ec..d8a686caf 100644
--- a/fast/stages/2-networking-a-peering/README.md
+++ b/fast/stages/2-networking-a-peering/README.md
@@ -389,21 +389,22 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS
|---|---|:---:|:---:|:---:|:---:|
| [automation](variables.tf#L42) | Automation resources created by the bootstrap stage. | object({…}) | ✓ | | 0-bootstrap |
| [billing_account](variables.tf#L50) | 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.tf#L116) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | object({…}) | ✓ | | 1-resman |
-| [organization](variables.tf#L126) | Organization details. | object({…}) | ✓ | | 0-bootstrap |
-| [prefix](variables.tf#L142) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 0-bootstrap |
+| [folder_ids](variables.tf#L126) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | object({…}) | ✓ | | 1-resman |
+| [organization](variables.tf#L136) | Organization details. | object({…}) | ✓ | | 0-bootstrap |
+| [prefix](variables.tf#L152) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 0-bootstrap |
| [alert_config](variables.tf#L17) | Configuration for monitoring alerts. | object({…}) | | {…} | |
| [custom_roles](variables.tf#L63) | Custom roles defined at the org level, in key => id format. | object({…}) | | null | 0-bootstrap |
| [dns](variables.tf#L72) | DNS configuration. | object({…}) | | {} | |
| [enable_cloud_nat](variables.tf#L82) | Deploy Cloud NAT. | bool | | false | |
| [essential_contacts](variables.tf#L89) | Email used for essential contacts, unset if null. | string | | null | |
| [factories_config](variables.tf#L95) | Configuration for network resource factories. | object({…}) | | {…} | |
-| [outputs_location](variables.tf#L136) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string | | null | |
+| [fast_features](variables.tf#L116) | Selective control for top-level FAST features. | object({…}) | | {} | 0-0-bootstrap |
+| [outputs_location](variables.tf#L146) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string | | null | |
| [peering_configs](variables-peerings.tf#L19) | Peering configurations. | object({…}) | | {} | |
-| [psa_ranges](variables.tf#L153) | IP ranges used for Private Service Access (CloudSQL, etc.). | object({…}) | | null | |
-| [regions](variables.tf#L172) | Region definitions. | object({…}) | | {…} | |
-| [service_accounts](variables.tf#L184) | Automation service accounts in name => email format. | object({…}) | | null | 1-resman |
-| [vpn_onprem_primary_config](variables.tf#L198) | VPN gateway configuration for onprem interconnection in the primary region. | object({…}) | | null | |
+| [psa_ranges](variables.tf#L163) | IP ranges used for Private Service Access (CloudSQL, etc.). | object({…}) | | null | |
+| [regions](variables.tf#L182) | Region definitions. | object({…}) | | {…} | |
+| [service_accounts](variables.tf#L194) | Automation service accounts in name => email format. | object({…}) | | null | 1-resman |
+| [vpn_onprem_primary_config](variables.tf#L208) | VPN gateway configuration for onprem interconnection in the primary region. | object({…}) | | null | |
## Outputs
diff --git a/fast/stages/2-networking-a-peering/net-dev.tf b/fast/stages/2-networking-a-peering/net-dev.tf
index bce5883c1..7f7e0e772 100644
--- a/fast/stages/2-networking-a-peering/net-dev.tf
+++ b/fast/stages/2-networking-a-peering/net-dev.tf
@@ -22,16 +22,23 @@ module "dev-spoke-project" {
name = "dev-net-spoke-0"
parent = var.folder_ids.networking-dev
prefix = var.prefix
- services = [
- "container.googleapis.com",
- "compute.googleapis.com",
- "dns.googleapis.com",
- "iap.googleapis.com",
- "networkmanagement.googleapis.com",
- "servicenetworking.googleapis.com",
- "stackdriver.googleapis.com",
- "vpcaccess.googleapis.com"
- ]
+ services = concat(
+ [
+ "container.googleapis.com",
+ "compute.googleapis.com",
+ "dns.googleapis.com",
+ "iap.googleapis.com",
+ "networkmanagement.googleapis.com",
+ "servicenetworking.googleapis.com",
+ "stackdriver.googleapis.com",
+ "vpcaccess.googleapis.com"
+ ],
+ (
+ var.fast_features.gcve
+ ? ["vmwareengine.googleapis.com"]
+ : []
+ )
+ )
shared_vpc_host_config = {
enabled = true
}
diff --git a/fast/stages/2-networking-a-peering/net-prod.tf b/fast/stages/2-networking-a-peering/net-prod.tf
index 66236c2be..dd4b532f4 100644
--- a/fast/stages/2-networking-a-peering/net-prod.tf
+++ b/fast/stages/2-networking-a-peering/net-prod.tf
@@ -22,16 +22,23 @@ module "prod-spoke-project" {
name = "prod-net-spoke-0"
parent = var.folder_ids.networking-prod
prefix = var.prefix
- services = [
- "container.googleapis.com",
- "compute.googleapis.com",
- "dns.googleapis.com",
- "iap.googleapis.com",
- "networkmanagement.googleapis.com",
- "servicenetworking.googleapis.com",
- "stackdriver.googleapis.com",
- "vpcaccess.googleapis.com"
- ]
+ services = concat(
+ [
+ "container.googleapis.com",
+ "compute.googleapis.com",
+ "dns.googleapis.com",
+ "iap.googleapis.com",
+ "networkmanagement.googleapis.com",
+ "servicenetworking.googleapis.com",
+ "stackdriver.googleapis.com",
+ "vpcaccess.googleapis.com"
+ ],
+ (
+ var.fast_features.gcve
+ ? ["vmwareengine.googleapis.com"]
+ : []
+ )
+ )
shared_vpc_host_config = {
enabled = true
}
diff --git a/fast/stages/2-networking-a-peering/variables.tf b/fast/stages/2-networking-a-peering/variables.tf
index fc8255f33..46639d39f 100644
--- a/fast/stages/2-networking-a-peering/variables.tf
+++ b/fast/stages/2-networking-a-peering/variables.tf
@@ -113,6 +113,16 @@ variable "factories_config" {
}
}
+variable "fast_features" {
+ # tfdoc:variable:source 0-0-bootstrap
+ description = "Selective control for top-level FAST features."
+ type = object({
+ gcve = optional(bool, false)
+ })
+ default = {}
+ nullable = false
+}
+
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."
diff --git a/fast/stages/2-networking-b-vpn/README.md b/fast/stages/2-networking-b-vpn/README.md
index 708c9e942..6aa86f449 100644
--- a/fast/stages/2-networking-b-vpn/README.md
+++ b/fast/stages/2-networking-b-vpn/README.md
@@ -413,21 +413,22 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS
|---|---|:---:|:---:|:---:|:---:|
| [automation](variables.tf#L42) | Automation resources created by the bootstrap stage. | object({…}) | ✓ | | 0-bootstrap |
| [billing_account](variables.tf#L50) | 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.tf#L116) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | object({…}) | ✓ | | 1-resman |
-| [organization](variables.tf#L126) | Organization details. | object({…}) | ✓ | | 0-bootstrap |
-| [prefix](variables.tf#L142) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 0-bootstrap |
+| [folder_ids](variables.tf#L126) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | object({…}) | ✓ | | 1-resman |
+| [organization](variables.tf#L136) | Organization details. | object({…}) | ✓ | | 0-bootstrap |
+| [prefix](variables.tf#L152) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 0-bootstrap |
| [alert_config](variables.tf#L17) | Configuration for monitoring alerts. | object({…}) | | {…} | |
| [custom_roles](variables.tf#L63) | Custom roles defined at the org level, in key => id format. | object({…}) | | null | 0-bootstrap |
| [dns](variables.tf#L72) | DNS configuration. | object({…}) | | {} | |
| [enable_cloud_nat](variables.tf#L82) | Deploy Cloud NAT. | bool | | false | |
| [essential_contacts](variables.tf#L89) | Email used for essential contacts, unset if null. | string | | null | |
| [factories_config](variables.tf#L95) | Configuration for network resource factories. | object({…}) | | {…} | |
-| [outputs_location](variables.tf#L136) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string | | null | |
-| [psa_ranges](variables.tf#L153) | IP ranges used for Private Service Access (CloudSQL, etc.). | object({…}) | | null | |
-| [regions](variables.tf#L172) | Region definitions. | object({…}) | | {…} | |
-| [service_accounts](variables.tf#L184) | Automation service accounts in name => email format. | object({…}) | | null | 1-resman |
+| [fast_features](variables.tf#L116) | Selective control for top-level FAST features. | object({…}) | | {} | 0-0-bootstrap |
+| [outputs_location](variables.tf#L146) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string | | null | |
+| [psa_ranges](variables.tf#L163) | IP ranges used for Private Service Access (CloudSQL, etc.). | object({…}) | | null | |
+| [regions](variables.tf#L182) | Region definitions. | object({…}) | | {…} | |
+| [service_accounts](variables.tf#L194) | Automation service accounts in name => email format. | object({…}) | | null | 1-resman |
| [vpn_configs](variables-vpn.tf#L17) | Hub to spokes VPN configurations. | object({…}) | | {} | |
-| [vpn_onprem_primary_config](variables.tf#L198) | VPN gateway configuration for onprem interconnection in the primary region. | object({…}) | | null | |
+| [vpn_onprem_primary_config](variables.tf#L208) | VPN gateway configuration for onprem interconnection in the primary region. | object({…}) | | null | |
## Outputs
diff --git a/fast/stages/2-networking-b-vpn/net-dev.tf b/fast/stages/2-networking-b-vpn/net-dev.tf
index bce5883c1..7f7e0e772 100644
--- a/fast/stages/2-networking-b-vpn/net-dev.tf
+++ b/fast/stages/2-networking-b-vpn/net-dev.tf
@@ -22,16 +22,23 @@ module "dev-spoke-project" {
name = "dev-net-spoke-0"
parent = var.folder_ids.networking-dev
prefix = var.prefix
- services = [
- "container.googleapis.com",
- "compute.googleapis.com",
- "dns.googleapis.com",
- "iap.googleapis.com",
- "networkmanagement.googleapis.com",
- "servicenetworking.googleapis.com",
- "stackdriver.googleapis.com",
- "vpcaccess.googleapis.com"
- ]
+ services = concat(
+ [
+ "container.googleapis.com",
+ "compute.googleapis.com",
+ "dns.googleapis.com",
+ "iap.googleapis.com",
+ "networkmanagement.googleapis.com",
+ "servicenetworking.googleapis.com",
+ "stackdriver.googleapis.com",
+ "vpcaccess.googleapis.com"
+ ],
+ (
+ var.fast_features.gcve
+ ? ["vmwareengine.googleapis.com"]
+ : []
+ )
+ )
shared_vpc_host_config = {
enabled = true
}
diff --git a/fast/stages/2-networking-b-vpn/net-prod.tf b/fast/stages/2-networking-b-vpn/net-prod.tf
index 66236c2be..dd4b532f4 100644
--- a/fast/stages/2-networking-b-vpn/net-prod.tf
+++ b/fast/stages/2-networking-b-vpn/net-prod.tf
@@ -22,16 +22,23 @@ module "prod-spoke-project" {
name = "prod-net-spoke-0"
parent = var.folder_ids.networking-prod
prefix = var.prefix
- services = [
- "container.googleapis.com",
- "compute.googleapis.com",
- "dns.googleapis.com",
- "iap.googleapis.com",
- "networkmanagement.googleapis.com",
- "servicenetworking.googleapis.com",
- "stackdriver.googleapis.com",
- "vpcaccess.googleapis.com"
- ]
+ services = concat(
+ [
+ "container.googleapis.com",
+ "compute.googleapis.com",
+ "dns.googleapis.com",
+ "iap.googleapis.com",
+ "networkmanagement.googleapis.com",
+ "servicenetworking.googleapis.com",
+ "stackdriver.googleapis.com",
+ "vpcaccess.googleapis.com"
+ ],
+ (
+ var.fast_features.gcve
+ ? ["vmwareengine.googleapis.com"]
+ : []
+ )
+ )
shared_vpc_host_config = {
enabled = true
}
diff --git a/fast/stages/2-networking-b-vpn/variables.tf b/fast/stages/2-networking-b-vpn/variables.tf
index fc8255f33..46639d39f 100644
--- a/fast/stages/2-networking-b-vpn/variables.tf
+++ b/fast/stages/2-networking-b-vpn/variables.tf
@@ -113,6 +113,16 @@ variable "factories_config" {
}
}
+variable "fast_features" {
+ # tfdoc:variable:source 0-0-bootstrap
+ description = "Selective control for top-level FAST features."
+ type = object({
+ gcve = optional(bool, false)
+ })
+ default = {}
+ nullable = false
+}
+
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."
diff --git a/fast/stages/2-networking-c-nva/README.md b/fast/stages/2-networking-c-nva/README.md
index 31428b42a..ab387b2a3 100644
--- a/fast/stages/2-networking-c-nva/README.md
+++ b/fast/stages/2-networking-c-nva/README.md
@@ -458,23 +458,24 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS
|---|---|:---:|:---:|:---:|:---:|
| [automation](variables.tf#L42) | Automation resources created by the bootstrap stage. | object({…}) | ✓ | | 0-bootstrap |
| [billing_account](variables.tf#L50) | 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.tf#L116) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | object({…}) | ✓ | | 1-resman |
-| [organization](variables.tf#L149) | Organization details. | object({…}) | ✓ | | 0-bootstrap |
-| [prefix](variables.tf#L165) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 0-bootstrap |
+| [folder_ids](variables.tf#L126) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | object({…}) | ✓ | | 1-resman |
+| [organization](variables.tf#L159) | Organization details. | object({…}) | ✓ | | 0-bootstrap |
+| [prefix](variables.tf#L175) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 0-bootstrap |
| [alert_config](variables.tf#L17) | Configuration for monitoring alerts. | object({…}) | | {…} | |
| [custom_roles](variables.tf#L63) | Custom roles defined at the org level, in key => id format. | object({…}) | | null | 0-bootstrap |
| [dns](variables.tf#L72) | DNS configuration. | object({…}) | | {} | |
| [enable_cloud_nat](variables.tf#L82) | Deploy Cloud NAT. | bool | | false | |
| [essential_contacts](variables.tf#L89) | Email used for essential contacts, unset if null. | string | | null | |
| [factories_config](variables.tf#L95) | Configuration for network resource factories. | object({…}) | | {…} | |
-| [gcp_ranges](variables.tf#L126) | GCP address ranges in name => range format. | map(string) | | {…} | |
-| [onprem_cidr](variables.tf#L141) | Onprem addresses in name => range format. | map(string) | | {…} | |
-| [outputs_location](variables.tf#L159) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string | | null | |
-| [psa_ranges](variables.tf#L176) | IP ranges used for Private Service Access (e.g. CloudSQL). Ranges is in name => range format. | object({…}) | | null | |
-| [regions](variables.tf#L195) | Region definitions. | object({…}) | | {…} | |
-| [service_accounts](variables.tf#L207) | Automation service accounts in name => email format. | object({…}) | | null | 1-resman |
-| [vpn_onprem_primary_config](variables.tf#L221) | VPN gateway configuration for onprem interconnection in the primary region. | object({…}) | | null | |
-| [vpn_onprem_secondary_config](variables.tf#L264) | VPN gateway configuration for onprem interconnection in the secondary region. | object({…}) | | null | |
+| [fast_features](variables.tf#L116) | Selective control for top-level FAST features. | object({…}) | | {} | 0-0-bootstrap |
+| [gcp_ranges](variables.tf#L136) | GCP address ranges in name => range format. | map(string) | | {…} | |
+| [onprem_cidr](variables.tf#L151) | Onprem addresses in name => range format. | map(string) | | {…} | |
+| [outputs_location](variables.tf#L169) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string | | null | |
+| [psa_ranges](variables.tf#L186) | IP ranges used for Private Service Access (e.g. CloudSQL). Ranges is in name => range format. | object({…}) | | null | |
+| [regions](variables.tf#L205) | Region definitions. | object({…}) | | {…} | |
+| [service_accounts](variables.tf#L217) | Automation service accounts in name => email format. | object({…}) | | null | 1-resman |
+| [vpn_onprem_primary_config](variables.tf#L231) | VPN gateway configuration for onprem interconnection in the primary region. | object({…}) | | null | |
+| [vpn_onprem_secondary_config](variables.tf#L274) | VPN gateway configuration for onprem interconnection in the secondary region. | object({…}) | | null | |
## Outputs
diff --git a/fast/stages/2-networking-c-nva/net-dev.tf b/fast/stages/2-networking-c-nva/net-dev.tf
index 739d012ee..28b218b0a 100644
--- a/fast/stages/2-networking-c-nva/net-dev.tf
+++ b/fast/stages/2-networking-c-nva/net-dev.tf
@@ -22,7 +22,7 @@ module "dev-spoke-project" {
name = "dev-net-spoke-0"
parent = var.folder_ids.networking-dev
prefix = var.prefix
- services = [
+ services = concat([
"container.googleapis.com",
"compute.googleapis.com",
"dns.googleapis.com",
@@ -31,7 +31,13 @@ module "dev-spoke-project" {
"servicenetworking.googleapis.com",
"stackdriver.googleapis.com",
"vpcaccess.googleapis.com"
- ]
+ ],
+ (
+ var.fast_features.gcve
+ ? ["vmwareengine.googleapis.com"]
+ : []
+ )
+ )
shared_vpc_host_config = {
enabled = true
}
diff --git a/fast/stages/2-networking-c-nva/net-prod.tf b/fast/stages/2-networking-c-nva/net-prod.tf
index fa9042e2e..81af9967a 100644
--- a/fast/stages/2-networking-c-nva/net-prod.tf
+++ b/fast/stages/2-networking-c-nva/net-prod.tf
@@ -22,7 +22,7 @@ module "prod-spoke-project" {
name = "prod-net-spoke-0"
parent = var.folder_ids.networking-prod
prefix = var.prefix
- services = [
+ services = concat([
"container.googleapis.com",
"compute.googleapis.com",
"dns.googleapis.com",
@@ -31,7 +31,13 @@ module "prod-spoke-project" {
"servicenetworking.googleapis.com",
"stackdriver.googleapis.com",
"vpcaccess.googleapis.com"
- ]
+ ],
+ (
+ var.fast_features.gcve
+ ? ["vmwareengine.googleapis.com"]
+ : []
+ )
+ )
shared_vpc_host_config = {
enabled = true
}
diff --git a/fast/stages/2-networking-c-nva/variables.tf b/fast/stages/2-networking-c-nva/variables.tf
index 2b4d8ac6f..30654d6cd 100644
--- a/fast/stages/2-networking-c-nva/variables.tf
+++ b/fast/stages/2-networking-c-nva/variables.tf
@@ -113,6 +113,16 @@ variable "factories_config" {
}
}
+variable "fast_features" {
+ # tfdoc:variable:source 0-0-bootstrap
+ description = "Selective control for top-level FAST features."
+ type = object({
+ gcve = optional(bool, false)
+ })
+ default = {}
+ nullable = false
+}
+
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."
diff --git a/fast/stages/2-networking-d-separate-envs/README.md b/fast/stages/2-networking-d-separate-envs/README.md
index 8a8e838c1..44c907314 100644
--- a/fast/stages/2-networking-d-separate-envs/README.md
+++ b/fast/stages/2-networking-d-separate-envs/README.md
@@ -332,21 +332,22 @@ Regions are defined via the `regions` variable which sets up a mapping between t
|---|---|:---:|:---:|:---:|:---:|
| [automation](variables.tf#L42) | Automation resources created by the bootstrap stage. | object({…}) | ✓ | | 0-bootstrap |
| [billing_account](variables.tf#L50) | 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.tf#L117) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | object({…}) | ✓ | | 1-resman |
-| [organization](variables.tf#L127) | Organization details. | object({…}) | ✓ | | 0-bootstrap |
-| [prefix](variables.tf#L143) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 0-bootstrap |
+| [folder_ids](variables.tf#L127) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | object({…}) | ✓ | | 1-resman |
+| [organization](variables.tf#L137) | Organization details. | object({…}) | ✓ | | 0-bootstrap |
+| [prefix](variables.tf#L153) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 0-bootstrap |
| [alert_config](variables.tf#L17) | Configuration for monitoring alerts. | object({…}) | | {…} | |
| [custom_roles](variables.tf#L63) | Custom roles defined at the org level, in key => id format. | object({…}) | | null | 0-bootstrap |
| [dns](variables.tf#L72) | DNS configuration. | object({…}) | | {} | |
| [enable_cloud_nat](variables.tf#L83) | Deploy Cloud NAT. | bool | | false | |
| [essential_contacts](variables.tf#L90) | Email used for essential contacts, unset if null. | string | | null | |
| [factories_config](variables.tf#L96) | Configuration for network resource factories. | object({…}) | | {…} | |
-| [outputs_location](variables.tf#L137) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string | | null | |
-| [psa_ranges](variables.tf#L154) | IP ranges used for Private Service Access (e.g. CloudSQL). | object({…}) | | null | |
-| [regions](variables.tf#L173) | Region definitions. | object({…}) | | {…} | |
-| [service_accounts](variables.tf#L183) | Automation service accounts in name => email format. | object({…}) | | null | 1-resman |
-| [vpn_onprem_dev_primary_config](variables.tf#L197) | VPN gateway configuration for onprem interconnection from dev in the primary region. | object({…}) | | null | |
-| [vpn_onprem_prod_primary_config](variables.tf#L240) | VPN gateway configuration for onprem interconnection from prod in the primary region. | object({…}) | | null | |
+| [fast_features](variables.tf#L117) | Selective control for top-level FAST features. | object({…}) | | {} | 0-0-bootstrap |
+| [outputs_location](variables.tf#L147) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string | | null | |
+| [psa_ranges](variables.tf#L164) | IP ranges used for Private Service Access (e.g. CloudSQL). | object({…}) | | null | |
+| [regions](variables.tf#L183) | Region definitions. | object({…}) | | {…} | |
+| [service_accounts](variables.tf#L193) | Automation service accounts in name => email format. | object({…}) | | null | 1-resman |
+| [vpn_onprem_dev_primary_config](variables.tf#L207) | VPN gateway configuration for onprem interconnection from dev in the primary region. | object({…}) | | null | |
+| [vpn_onprem_prod_primary_config](variables.tf#L250) | VPN gateway configuration for onprem interconnection from prod in the primary region. | object({…}) | | null | |
## Outputs
diff --git a/fast/stages/2-networking-d-separate-envs/net-dev.tf b/fast/stages/2-networking-d-separate-envs/net-dev.tf
index 24c9d4fa3..5d880e085 100644
--- a/fast/stages/2-networking-d-separate-envs/net-dev.tf
+++ b/fast/stages/2-networking-d-separate-envs/net-dev.tf
@@ -22,7 +22,7 @@ module "dev-spoke-project" {
name = "dev-net-spoke-0"
parent = var.folder_ids.networking-dev
prefix = var.prefix
- services = [
+ services = concat([
"container.googleapis.com",
"compute.googleapis.com",
"dns.googleapis.com",
@@ -31,7 +31,13 @@ module "dev-spoke-project" {
"servicenetworking.googleapis.com",
"stackdriver.googleapis.com",
"vpcaccess.googleapis.com"
- ]
+ ],
+ (
+ var.fast_features.gcve
+ ? ["vmwareengine.googleapis.com"]
+ : []
+ )
+ )
shared_vpc_host_config = {
enabled = true
service_projects = []
diff --git a/fast/stages/2-networking-d-separate-envs/net-prod.tf b/fast/stages/2-networking-d-separate-envs/net-prod.tf
index eea26bf13..af740c4fb 100644
--- a/fast/stages/2-networking-d-separate-envs/net-prod.tf
+++ b/fast/stages/2-networking-d-separate-envs/net-prod.tf
@@ -22,7 +22,7 @@ module "prod-spoke-project" {
name = "prod-net-spoke-0"
parent = var.folder_ids.networking-prod
prefix = var.prefix
- services = [
+ services = concat([
"container.googleapis.com",
"compute.googleapis.com",
"dns.googleapis.com",
@@ -31,7 +31,13 @@ module "prod-spoke-project" {
"servicenetworking.googleapis.com",
"stackdriver.googleapis.com",
"vpcaccess.googleapis.com"
- ]
+ ],
+ (
+ var.fast_features.gcve
+ ? ["vmwareengine.googleapis.com"]
+ : []
+ )
+ )
shared_vpc_host_config = {
enabled = true
service_projects = []
diff --git a/fast/stages/2-networking-d-separate-envs/variables.tf b/fast/stages/2-networking-d-separate-envs/variables.tf
index f1cb47e8d..8beb83204 100644
--- a/fast/stages/2-networking-d-separate-envs/variables.tf
+++ b/fast/stages/2-networking-d-separate-envs/variables.tf
@@ -114,6 +114,16 @@ variable "factories_config" {
}
}
+variable "fast_features" {
+ # tfdoc:variable:source 0-0-bootstrap
+ description = "Selective control for top-level FAST features."
+ type = object({
+ gcve = optional(bool, false)
+ })
+ default = {}
+ nullable = false
+}
+
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."
diff --git a/fast/stages/2-networking-e-nva-bgp/README.md b/fast/stages/2-networking-e-nva-bgp/README.md
index 1e81f9bfb..3c9b2b98a 100644
--- a/fast/stages/2-networking-e-nva-bgp/README.md
+++ b/fast/stages/2-networking-e-nva-bgp/README.md
@@ -484,25 +484,26 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS
|---|---|:---:|:---:|:---:|:---:|
| [automation](variables.tf#L42) | Automation resources created by the bootstrap stage. | object({…}) | ✓ | | 0-bootstrap |
| [billing_account](variables.tf#L50) | 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.tf#L116) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | object({…}) | ✓ | | 1-resman |
-| [organization](variables.tf#L160) | Organization details. | object({…}) | ✓ | | 0-bootstrap |
-| [prefix](variables.tf#L176) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 0-bootstrap |
+| [folder_ids](variables.tf#L126) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | object({…}) | ✓ | | 1-resman |
+| [organization](variables.tf#L170) | Organization details. | object({…}) | ✓ | | 0-bootstrap |
+| [prefix](variables.tf#L186) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 0-bootstrap |
| [alert_config](variables.tf#L17) | Configuration for monitoring alerts. | object({…}) | | {…} | |
| [custom_roles](variables.tf#L63) | Custom roles defined at the org level, in key => id format. | object({…}) | | null | 0-bootstrap |
| [dns](variables.tf#L72) | DNS configuration. | object({…}) | | {} | |
| [enable_cloud_nat](variables.tf#L82) | Deploy Cloud NAT. | bool | | false | |
| [essential_contacts](variables.tf#L89) | Email used for essential contacts, unset if null. | string | | null | |
| [factories_config](variables.tf#L95) | Configuration for network resource factories. | object({…}) | | {…} | |
-| [gcp_ranges](variables.tf#L126) | GCP address ranges in name => range format. | map(string) | | {…} | |
-| [ncc_asn](variables.tf#L141) | The NCC Cloud Routers ASN configuration. | map(number) | | {…} | |
-| [onprem_cidr](variables.tf#L152) | Onprem addresses in name => range format. | map(string) | | {…} | |
-| [outputs_location](variables.tf#L170) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string | | null | |
-| [psa_ranges](variables.tf#L187) | IP ranges used for Private Service Access (e.g. CloudSQL). Ranges is in name => range format. | object({…}) | | null | |
-| [regions](variables.tf#L206) | Region definitions. | object({…}) | | {…} | |
-| [service_accounts](variables.tf#L218) | Automation service accounts in name => email format. | object({…}) | | null | 1-resman |
-| [vpn_onprem_primary_config](variables.tf#L232) | VPN gateway configuration for onprem interconnection in the primary region. | object({…}) | | null | |
-| [vpn_onprem_secondary_config](variables.tf#L275) | VPN gateway configuration for onprem interconnection in the secondary region. | object({…}) | | null | |
-| [zones](variables.tf#L318) | Zones in which NVAs are deployed. | list(string) | | ["b", "c"] | |
+| [fast_features](variables.tf#L116) | Selective control for top-level FAST features. | object({…}) | | {} | 0-0-bootstrap |
+| [gcp_ranges](variables.tf#L136) | GCP address ranges in name => range format. | map(string) | | {…} | |
+| [ncc_asn](variables.tf#L151) | The NCC Cloud Routers ASN configuration. | map(number) | | {…} | |
+| [onprem_cidr](variables.tf#L162) | Onprem addresses in name => range format. | map(string) | | {…} | |
+| [outputs_location](variables.tf#L180) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string | | null | |
+| [psa_ranges](variables.tf#L197) | IP ranges used for Private Service Access (e.g. CloudSQL). Ranges is in name => range format. | object({…}) | | null | |
+| [regions](variables.tf#L216) | Region definitions. | object({…}) | | {…} | |
+| [service_accounts](variables.tf#L228) | Automation service accounts in name => email format. | object({…}) | | null | 1-resman |
+| [vpn_onprem_primary_config](variables.tf#L242) | VPN gateway configuration for onprem interconnection in the primary region. | object({…}) | | null | |
+| [vpn_onprem_secondary_config](variables.tf#L285) | VPN gateway configuration for onprem interconnection in the secondary region. | object({…}) | | null | |
+| [zones](variables.tf#L328) | Zones in which NVAs are deployed. | list(string) | | ["b", "c"] | |
## Outputs
diff --git a/fast/stages/2-networking-e-nva-bgp/net-dev.tf b/fast/stages/2-networking-e-nva-bgp/net-dev.tf
index 3b3c3efe2..277ff8fc3 100644
--- a/fast/stages/2-networking-e-nva-bgp/net-dev.tf
+++ b/fast/stages/2-networking-e-nva-bgp/net-dev.tf
@@ -22,7 +22,7 @@ module "dev-spoke-project" {
name = "dev-net-spoke-0"
parent = var.folder_ids.networking-dev
prefix = var.prefix
- services = [
+ services = concat([
"compute.googleapis.com",
"dns.googleapis.com",
"iap.googleapis.com",
@@ -30,7 +30,13 @@ module "dev-spoke-project" {
"servicenetworking.googleapis.com",
"stackdriver.googleapis.com",
"vpcaccess.googleapis.com"
- ]
+ ],
+ (
+ var.fast_features.gcve
+ ? ["vmwareengine.googleapis.com"]
+ : []
+ )
+ )
shared_vpc_host_config = {
enabled = true
}
diff --git a/fast/stages/2-networking-e-nva-bgp/net-prod.tf b/fast/stages/2-networking-e-nva-bgp/net-prod.tf
index 7e9d7e34a..8ed524bad 100644
--- a/fast/stages/2-networking-e-nva-bgp/net-prod.tf
+++ b/fast/stages/2-networking-e-nva-bgp/net-prod.tf
@@ -22,7 +22,7 @@ module "prod-spoke-project" {
name = "prod-net-spoke-0"
parent = var.folder_ids.networking-prod
prefix = var.prefix
- services = [
+ services = concat([
"compute.googleapis.com",
"dns.googleapis.com",
"iap.googleapis.com",
@@ -30,7 +30,13 @@ module "prod-spoke-project" {
"servicenetworking.googleapis.com",
"stackdriver.googleapis.com",
"vpcaccess.googleapis.com"
- ]
+ ],
+ (
+ var.fast_features.gcve
+ ? ["vmwareengine.googleapis.com"]
+ : []
+ )
+ )
shared_vpc_host_config = {
enabled = true
}
diff --git a/fast/stages/2-networking-e-nva-bgp/variables.tf b/fast/stages/2-networking-e-nva-bgp/variables.tf
index f92eefcd5..8fd60c8ba 100644
--- a/fast/stages/2-networking-e-nva-bgp/variables.tf
+++ b/fast/stages/2-networking-e-nva-bgp/variables.tf
@@ -113,6 +113,16 @@ variable "factories_config" {
}
}
+variable "fast_features" {
+ # tfdoc:variable:source 0-0-bootstrap
+ description = "Selective control for top-level FAST features."
+ type = object({
+ gcve = optional(bool, false)
+ })
+ default = {}
+ nullable = false
+}
+
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."
diff --git a/fast/stages/3-gcve/README.md b/fast/stages/3-gcve/README.md
new file mode 100644
index 000000000..258fd9b92
--- /dev/null
+++ b/fast/stages/3-gcve/README.md
@@ -0,0 +1,34 @@
+# 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."
+
+## TOC
+
+
+- [TOC](#toc)
+- [Deployment Patterns](#deployment-patterns)
+ - [Single Region](#single-region)
+ - [Standalone VPC for a sigle region GCVE deployment](#standalone-vpc-for-a-sigle-region-gcve-deployment)
+ - [Separate VPC Environments for individual dedicated GCVE deployments](#separate-vpc-environments-for-individual-dedicated-gcve-deployments)
+
+
+## Deployment Patterns
+### Single Region
+#### Standalone VPC for a sigle region GCVE deployment
+
+
+
+
+
pc-minimal | |
+| [outputs.tf](./outputs.tf) | Output variables. | | google_storage_bucket_object · local_file |
+| [variables.tf](./variables.tf) | Module variables. | | |
+
+## Variables
+
+| name | description | type | required | default | producer |
+|---|---|:---:|:---:|:---:|:---:|
+| [automation](variables.tf#L17) | Automation resources created by the bootstrap stage. | object({…}) | ✓ | | 0-bootstrap |
+| [billing_account](variables.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.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.tf#L59) | Host project for the shared VPC. | object({…}) | ✓ | | 2-networking |
+| [organization](variables.tf#L80) | Organization details. | object({…}) | ✓ | | 00-globals |
+| [prefix](variables.tf#L96) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 0-bootstrap |
+| [private_cloud_configs](variables.tf#L102) | The VMware private cloud configurations. The key is the unique private cloud name suffix. | map(object({…})) | ✓ | | |
+| [vpc_self_links](variables.tf#L131) | Self link for the shared VPC. | object({…}) | ✓ | | 2-networking |
+| [groups_gcve](variables.tf#L46) | GCVE groups. | object({…}) | | {…} | |
+| [iam](variables.tf#L67) | Project-level authoritative IAM bindings for users and service accounts in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | |
+| [labels](variables.tf#L74) | Project-level labels. | map(string) | | {} | |
+| [outputs_location](variables.tf#L90) | Path where providers, tfvars files, and lists for the following stages are written. Leave empty to disable. | string | | null | |
+| [project_services](variables.tf#L124) | 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
new file mode 100644
index 000000000..985314939
--- /dev/null
+++ b/fast/stages/3-gcve/prod/main.tf
@@ -0,0 +1,59 @@
+/**
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+# tfdoc:file:description 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
new file mode 100644
index 000000000..5c97be028
--- /dev/null
+++ b/fast/stages/3-gcve/prod/outputs.tf
@@ -0,0 +1,70 @@
+# 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
new file mode 100644
index 000000000..ee48c9707
--- /dev/null
+++ b/fast/stages/3-gcve/prod/variables.tf
@@ -0,0 +1,139 @@
+/**
+ * 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 "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 = "Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created."
+ type = object({
+ gcve-prod = string
+ })
+}
+
+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 "host_project_ids" {
+ # tfdoc:variable:source 2-networking
+ description = "Host project for the shared VPC."
+ type = object({
+ prod-spoke-0 = string
+ })
+}
+
+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 "organization" {
+ # tfdoc:variable:source 00-globals
+ description = "Organization details."
+ type = object({
+ domain = string
+ id = number
+ customer_id = string
+ })
+}
+
+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 "prefix" {
+ # tfdoc:variable:source 0-bootstrap
+ description = "Prefix used for resources that need unique names. Use 9 characters or less."
+ type = string
+}
+
+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
+}
+
+variable "vpc_self_links" {
+ # tfdoc:variable:source 2-networking
+ description = "Self link for the shared VPC."
+ type = object({
+ prod-spoke-0 = string
+ })
+}
+
+
diff --git a/modules/gcve-private-cloud/README.md b/modules/gcve-private-cloud/README.md
index 1c4da1e53..1cc8029c4 100644
--- a/modules/gcve-private-cloud/README.md
+++ b/modules/gcve-private-cloud/README.md
@@ -160,4 +160,5 @@ module "gcve-pc" {
| [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. | |
diff --git a/modules/gcve-private-cloud/main.tf b/modules/gcve-private-cloud/main.tf
index 7585109c1..3f2e1ad4a 100644
--- a/modules/gcve-private-cloud/main.tf
+++ b/modules/gcve-private-cloud/main.tf
@@ -92,6 +92,8 @@ resource "google_vmwareengine_private_cloud" "vmw_engine_private_clouds" {
name = "${var.prefix}-${each.key}"
description = each.value.description
+ 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
diff --git a/modules/gcve-private-cloud/outputs.tf b/modules/gcve-private-cloud/outputs.tf
index 06b444c36..832efc8b2 100644
--- a/modules/gcve-private-cloud/outputs.tf
+++ b/modules/gcve-private-cloud/outputs.tf
@@ -33,3 +33,8 @@ output "vmw_engine_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
+}
diff --git a/tests/fast/stages/s0_bootstrap/checklist.yaml b/tests/fast/stages/s0_bootstrap/checklist.yaml
index c6f644094..466efd2fc 100644
--- a/tests/fast/stages/s0_bootstrap/checklist.yaml
+++ b/tests/fast/stages/s0_bootstrap/checklist.yaml
@@ -364,7 +364,7 @@ counts:
google_logging_project_bucket_config: 3
google_org_policy_policy: 20
google_organization_iam_binding: 27
- google_organization_iam_custom_role: 6
+ google_organization_iam_custom_role: 7
google_organization_iam_member: 35
google_project: 3
google_project_iam_binding: 19
@@ -381,4 +381,4 @@ counts:
google_tags_tag_key: 1
google_tags_tag_value: 1
modules: 17
- resources: 192
+ resources: 193
diff --git a/tests/fast/stages/s0_bootstrap/simple.yaml b/tests/fast/stages/s0_bootstrap/simple.yaml
index 0d7174df6..ab916dd50 100644
--- a/tests/fast/stages/s0_bootstrap/simple.yaml
+++ b/tests/fast/stages/s0_bootstrap/simple.yaml
@@ -43,7 +43,7 @@ counts:
google_logging_project_bucket_config: 3
google_org_policy_policy: 20
google_organization_iam_binding: 27
- google_organization_iam_custom_role: 6
+ google_organization_iam_custom_role: 7
google_organization_iam_member: 22
google_project: 3
google_project_iam_binding: 19
@@ -61,10 +61,11 @@ counts:
google_tags_tag_value: 1
local_file: 7
modules: 16
- resources: 183
+ resources: 184
outputs:
custom_roles:
+ gcve_network_admin: organizations/123456789012/roles/gcveNetworkAdmin
organization_admin_viewer: organizations/123456789012/roles/organizationAdminViewer
organization_iam_admin: organizations/123456789012/roles/organizationIamAdmin
service_project_network_admin: organizations/123456789012/roles/serviceProjectNetworkAdmin
diff --git a/tests/fast/stages/s1_resman/checklist.tfvars b/tests/fast/stages/s1_resman/checklist.tfvars
index 9d0a4a70b..bf3dd68e0 100644
--- a/tests/fast/stages/s1_resman/checklist.tfvars
+++ b/tests/fast/stages/s1_resman/checklist.tfvars
@@ -13,6 +13,7 @@ billing_account = {
}
custom_roles = {
# organization_iam_admin = "organizations/123456789012/roles/organizationIamAdmin",
+ gcve_network_admin = "organizations/123456789012/roles/gcveNetworkAdmin"
service_project_network_admin = "organizations/123456789012/roles/xpnServiceAdmin"
storage_viewer = "organizations/123456789012/roles/storageViewer"
}
diff --git a/tests/fast/stages/s1_resman/checklist.yaml b/tests/fast/stages/s1_resman/checklist.yaml
index 7deb24f43..a5f4d9644 100644
--- a/tests/fast/stages/s1_resman/checklist.yaml
+++ b/tests/fast/stages/s1_resman/checklist.yaml
@@ -416,7 +416,7 @@ values:
counts:
google_folder: 57
- google_folder_iam_binding: 67
+ google_folder_iam_binding: 69
google_organization_iam_member: 5
google_project_iam_member: 4
google_service_account: 4
@@ -427,6 +427,6 @@ counts:
google_storage_bucket_object: 5
google_tags_tag_binding: 5
google_tags_tag_key: 3
- google_tags_tag_value: 9
+ google_tags_tag_value: 10
modules: 64
- resources: 173
+ resources: 176
diff --git a/tests/fast/stages/s1_resman/simple.tfvars b/tests/fast/stages/s1_resman/simple.tfvars
index d8bce3ae6..63decb4f7 100644
--- a/tests/fast/stages/s1_resman/simple.tfvars
+++ b/tests/fast/stages/s1_resman/simple.tfvars
@@ -13,6 +13,7 @@ billing_account = {
}
custom_roles = {
# organization_iam_admin = "organizations/123456789012/roles/organizationIamAdmin",
+ gcve_network_admin = "organizations/123456789012/roles/gcveNetworkAdmin"
service_project_network_admin = "organizations/123456789012/roles/xpnServiceAdmin"
storage_viewer = "organizations/123456789012/roles/storageViewer"
}
diff --git a/tests/fast/stages/s1_resman/simple.yaml b/tests/fast/stages/s1_resman/simple.yaml
index c4d096720..b0fea5a7b 100644
--- a/tests/fast/stages/s1_resman/simple.yaml
+++ b/tests/fast/stages/s1_resman/simple.yaml
@@ -14,7 +14,7 @@
counts:
google_folder: 5
- google_folder_iam_binding: 19
+ google_folder_iam_binding: 21
google_organization_iam_member: 5
google_project_iam_member: 4
google_service_account: 4
@@ -25,6 +25,6 @@ counts:
google_storage_bucket_object: 5
google_tags_tag_binding: 5
google_tags_tag_key: 3
- google_tags_tag_value: 9
+ google_tags_tag_value: 10
modules: 12
- resources: 73
+ resources: 76
diff --git a/tests/fast/stages/s3_gcve_minimal/__init__.py b/tests/fast/stages/s3_gcve_minimal/__init__.py
new file mode 100644
index 000000000..7ba50f933
--- /dev/null
+++ b/tests/fast/stages/s3_gcve_minimal/__init__.py
@@ -0,0 +1,13 @@
+# 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.
diff --git a/tests/fast/stages/s3_gcve_minimal/simple.tfvars b/tests/fast/stages/s3_gcve_minimal/simple.tfvars
new file mode 100644
index 000000000..b27af0975
--- /dev/null
+++ b/tests/fast/stages/s3_gcve_minimal/simple.tfvars
@@ -0,0 +1,53 @@
+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_minimal/simple.yaml b/tests/fast/stages/s3_gcve_minimal/simple.yaml
new file mode 100644
index 000000000..eb10f3c1e
--- /dev/null
+++ b/tests/fast/stages/s3_gcve_minimal/simple.yaml
@@ -0,0 +1,25 @@
+# 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_project: 1
+ google_project_iam_binding: 2
+ google_project_service: 1
+ google_storage_bucket_object: 1
+ google_vmwareengine_network: 1
+ google_vmwareengine_network_peering: 2
+ google_vmwareengine_private_cloud: 1
+ modules: 3
+ resources: 9
+
diff --git a/tests/fast/stages/s3_gcve_minimal/tftest.yaml b/tests/fast/stages/s3_gcve_minimal/tftest.yaml
new file mode 100644
index 000000000..f1342a6f1
--- /dev/null
+++ b/tests/fast/stages/s3_gcve_minimal/tftest.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.
+
+module: fast/stages/3-gcve/prod
+
+tests:
+ simple:
+ tfvars:
+ - simple.tfvars
+ inventory:
+ - simple.yaml