From b80132a61881a98dbd00944b8a14efbf9469563b Mon Sep 17 00:00:00 2001 From: Elia <79325566+eliamaldini@users.noreply.github.com> Date: Wed, 3 Apr 2024 17:25:12 +0200 Subject: [PATCH] FAST GCVE stage (#2191) * GCVE stage prerequisites * fix gcve prereq * gcve stage first deploy * Updated readme filex * docs updated * some fixes after testing * updated readme files * elia fix * gcve net admin custom role * gcve net admin custom role * elia fix * ven peering deploy * elia fix * added blueprint and stage tests * Edits to Readme files * typo in outputs * clean-up * gcve stage tests fix * readme fix * fix sorting * fix copyrights and readme file * fix test * fix copyright * fixed gcve feature flag cond. * removed validation * fixed typo * fixed typo * fixed gcve tests * fixed typo * fixed typo * fixed sorting * fixed sorting --------- Co-authored-by: Konrad Schieban --- blueprints/gcve/pc-minimal/README.md | 106 ++++++++ blueprints/gcve/pc-minimal/diagram.png | Bin 0 -> 47499 bytes blueprints/gcve/pc-minimal/gcve-pc.tf | 58 +++++ blueprints/gcve/pc-minimal/main.tf | 39 +++ blueprints/gcve/pc-minimal/output.tf | 40 +++ blueprints/gcve/pc-minimal/variables.tf | 122 +++++++++ fast/stages/0-bootstrap/README.md | 30 +-- .../data/custom-roles/gcve_network_admin.yaml | 21 ++ fast/stages/0-bootstrap/variables.tf | 1 + fast/stages/1-resman/README.md | 55 ++-- fast/stages/1-resman/billing.tf | 2 + fast/stages/1-resman/branch-gcve.tf | 199 ++++++++++++++ fast/stages/1-resman/branch-networking.tf | 6 + fast/stages/1-resman/cicd-gcve.tf | 245 ++++++++++++++++++ fast/stages/1-resman/main.tf | 28 +- fast/stages/1-resman/organization.tf | 1 + fast/stages/1-resman/outputs.tf | 75 ++++++ fast/stages/1-resman/variables.tf | 14 + fast/stages/2-networking-a-peering/README.md | 17 +- fast/stages/2-networking-a-peering/net-dev.tf | 27 +- .../stages/2-networking-a-peering/net-prod.tf | 27 +- .../2-networking-a-peering/variables.tf | 10 + fast/stages/2-networking-b-vpn/README.md | 17 +- fast/stages/2-networking-b-vpn/net-dev.tf | 27 +- fast/stages/2-networking-b-vpn/net-prod.tf | 27 +- fast/stages/2-networking-b-vpn/variables.tf | 10 + fast/stages/2-networking-c-nva/README.md | 23 +- fast/stages/2-networking-c-nva/net-dev.tf | 10 +- fast/stages/2-networking-c-nva/net-prod.tf | 10 +- fast/stages/2-networking-c-nva/variables.tf | 10 + .../2-networking-d-separate-envs/README.md | 19 +- .../2-networking-d-separate-envs/net-dev.tf | 10 +- .../2-networking-d-separate-envs/net-prod.tf | 10 +- .../2-networking-d-separate-envs/variables.tf | 10 + fast/stages/2-networking-e-nva-bgp/README.md | 27 +- fast/stages/2-networking-e-nva-bgp/net-dev.tf | 10 +- .../stages/2-networking-e-nva-bgp/net-prod.tf | 10 +- .../2-networking-e-nva-bgp/variables.tf | 10 + fast/stages/3-gcve/README.md | 34 +++ fast/stages/3-gcve/diagram0.png | Bin 0 -> 55573 bytes fast/stages/3-gcve/diagram1.png | Bin 0 -> 71892 bytes fast/stages/3-gcve/prod/README.md | 134 ++++++++++ fast/stages/3-gcve/prod/main.tf | 59 +++++ fast/stages/3-gcve/prod/outputs.tf | 70 +++++ fast/stages/3-gcve/prod/variables.tf | 139 ++++++++++ modules/gcve-private-cloud/README.md | 1 + modules/gcve-private-cloud/main.tf | 2 + modules/gcve-private-cloud/outputs.tf | 5 + tests/fast/stages/s0_bootstrap/checklist.yaml | 4 +- tests/fast/stages/s0_bootstrap/simple.yaml | 5 +- tests/fast/stages/s1_resman/checklist.tfvars | 1 + tests/fast/stages/s1_resman/checklist.yaml | 6 +- tests/fast/stages/s1_resman/simple.tfvars | 1 + tests/fast/stages/s1_resman/simple.yaml | 6 +- tests/fast/stages/s3_gcve_minimal/__init__.py | 13 + .../fast/stages/s3_gcve_minimal/simple.tfvars | 53 ++++ tests/fast/stages/s3_gcve_minimal/simple.yaml | 25 ++ tests/fast/stages/s3_gcve_minimal/tftest.yaml | 22 ++ 58 files changed, 1779 insertions(+), 164 deletions(-) create mode 100644 blueprints/gcve/pc-minimal/README.md create mode 100644 blueprints/gcve/pc-minimal/diagram.png create mode 100644 blueprints/gcve/pc-minimal/gcve-pc.tf create mode 100644 blueprints/gcve/pc-minimal/main.tf create mode 100644 blueprints/gcve/pc-minimal/output.tf create mode 100644 blueprints/gcve/pc-minimal/variables.tf create mode 100644 fast/stages/0-bootstrap/data/custom-roles/gcve_network_admin.yaml create mode 100644 fast/stages/1-resman/branch-gcve.tf create mode 100644 fast/stages/1-resman/cicd-gcve.tf create mode 100644 fast/stages/3-gcve/README.md create mode 100644 fast/stages/3-gcve/diagram0.png create mode 100644 fast/stages/3-gcve/diagram1.png create mode 100644 fast/stages/3-gcve/prod/README.md create mode 100644 fast/stages/3-gcve/prod/main.tf create mode 100644 fast/stages/3-gcve/prod/outputs.tf create mode 100644 fast/stages/3-gcve/prod/variables.tf create mode 100644 tests/fast/stages/s3_gcve_minimal/__init__.py create mode 100644 tests/fast/stages/s3_gcve_minimal/simple.tfvars create mode 100644 tests/fast/stages/s3_gcve_minimal/simple.yaml create mode 100644 tests/fast/stages/s3_gcve_minimal/tftest.yaml diff --git a/blueprints/gcve/pc-minimal/README.md b/blueprints/gcve/pc-minimal/README.md new file mode 100644 index 00000000..a749b787 --- /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 single region private cloud +

+ +The blueprint manages: +- project creation +- project-level organization policy definitions +- billing setup (billing account attachment) +- API/services enablement +- IAM role assignment for groups +- VMware Engine private clouds creation +- [VMware Engine Network](https://cloud.google.com/vmware-engine/docs/networking/vmware-engine-network#standard_networks) creation +- VPC attachment (Optional) + +### User groups + +Based on our GCP best practices, a GCVE private cloud relies on user groups to assign roles to human identities. These are the specific groups bound to the main GCVE [predefined roles](https://cloud.google.com/vmware-engine/docs/iam#vmware-engine-roles): +- *VMware Engine Administrators*. They have full access to the VMWare Engine Service. +- *VMware Engine Viewers*. They have read-only access to the VMware Engine Service. + + +### Network + +This blueprints expects the user to provision a VPC upfront, either from one of the FAST networking stages (e.g. [Networking with separated single environment](../../../fast/stages/2-networking-d-separate-envs)) or from an external source. +The blueprint can optionally configure the [VMware Engine Network peering](https://cloud.google.com/vmware-engine/docs/networking/peer-vpc-network) on the peer VPC by granting the following permissions on the project that hosts the VPC: +- vmwareengine.networkPeerings.create +- vmwareengine.networkPeerings.get +- vmwareengine.networkPeerings.list +- vmwareengine.operations.get +The permissions can be assigned through the predefined role *vmwareengine.vmwareengineAdmin*. Anyway the creation of a dedicated custom roile is strogly recommended to comply with the least privilege principle. + +## Basic usage + +The following example shows how to deploy a CGVE private cloud and connect it to a VPC + +```hcl +module "gcve-pc" { + source = "./fabric/blueprints/gcve/pc-minimal" + billing_account_id = "000000-000000-000000" + folder_id = "folders/000000000000" + project_id = "myprojectid" + groups = { + gcp-gcve-admins = "group:gcp-gcve-admins@acme.com" + gcp-gcve-viewers = "group:gcp-gcve-viewers@acme.com" + } + + prefix = "myprefix" + + network_peerings = { + dev-spoke-ven = { + peer_network = "projects/spokeproject/regions/europe-west1/subnetworks/dev-default-ew1" + peer_project_id = "peerprojectid" + } + } + + private_cloud_configs = { + dev-pc = { + cidr = "172.26.16.0/22" + zone = "europe-west1-a" + management_cluster_config = { + name = "mgmt-cluster" + node_count = 1 + node_type_id = "standard-72" + } + } + } +} +# tftest modules=3 resources=7 +``` + + + +## Files + +| name | description | modules | resources | +|---|---|---|---| +| [gcve-pc.tf](./gcve-pc.tf) | GCVE private cloud. | 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 0000000000000000000000000000000000000000..78ae82b24d7e881e72d0845f70951cf5f8884027 GIT binary patch literal 47499 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

e7 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�%&j;bcxGcOFY?#?4EiJp$|6FQ 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 VT=m_q+$V#7C-qEpD|8%V{|{P#GV1^U literal 0 HcmV?d00001 diff --git a/blueprints/gcve/pc-minimal/gcve-pc.tf b/blueprints/gcve/pc-minimal/gcve-pc.tf new file mode 100644 index 00000000..2cbd1e1e --- /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 00000000..2d9f5c8e --- /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 00000000..ba6f2ebf --- /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 00000000..fa0c99e6 --- /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 1e80e285..3b3d6ce6 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 00000000..255ac781 --- /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 d8536fc2..5493f5d6 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 a84c704f..628280ac 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 c1870842..64b87c26 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 00000000..43b73762 --- /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 48bb88dc..5bb641c6 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 00000000..7cadd653 --- /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 9d85a33f..19d2e8c5 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 90ded30e..6c380c89 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 8d229e68..38aa35c4 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 3987e81f..02ec155a 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 27272d0e..d8a686ca 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 bce5883c..7f7e0e77 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 66236c2b..dd4b532f 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 fc8255f3..46639d39 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 708c9e94..6aa86f44 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 bce5883c..7f7e0e77 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 66236c2b..dd4b532f 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 fc8255f3..46639d39 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 31428b42..ab387b2a 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 739d012e..28b218b0 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 fa9042e2..81af9967 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 2b4d8ac6..30654d6c 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 8a8e838c..44c90731 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 24c9d4fa..5d880e08 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 eea26bf1..af740c4f 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 f1cb47e8..8beb8320 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 1e81f9bf..3c9b2b98 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 3b3c3efe..277ff8fc 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 7e9d7e34..8ed524ba 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 f92eefcd..8fd60c8b 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 00000000..258fd9b9 --- /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 +

+ Standalone Shared VPC for a sigle region GCVE deployment +

+ +#### Separate VPC Environments for individual dedicated GCVE deployments +

+ Separate VPC Environments for individual dedicated GCVE deployments +

+ + + + \ No newline at end of file diff --git a/fast/stages/3-gcve/diagram0.png b/fast/stages/3-gcve/diagram0.png new file mode 100644 index 0000000000000000000000000000000000000000..fa1ee52f3e36c9cd88083aede3297d53b8361f56 GIT binary patch literal 55573 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�-bO-xJ- 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 RbrJh!MY(ITg_myx{XhN?Y+3*S literal 0 HcmV?d00001 diff --git a/fast/stages/3-gcve/prod/README.md b/fast/stages/3-gcve/prod/README.md new file mode 100644 index 00000000..4088ba45 --- /dev/null +++ b/fast/stages/3-gcve/prod/README.md @@ -0,0 +1,134 @@ +# GCVE Private Clouds for Production Environment + +This stage provides the Terraform content for the creation and management of multiple GCVE private clouds which are connected to an existing network. The network infrastructure needs to be deployed before executing this stage by executing the respective Fabric FAST stage (`2-networking-*`). This stage can be replicated for complex GCVE designs requiring a separate management of the network infrastructure (VEN) and the access domain or for other constraints which make you decide to have indipendent GCVE environments (e.g dev/prod, region or team serparation). + +## Design overview and choices + +> A more comprehensive description of the GCVE architecture and approach can be found in the [GCVE Private Cloud Minimal blueprint](../../../../blueprints/gcve/pc-minimal/). The blueprint is wrapped and configured here to leverage the FAST flow. + +The GCVE stage creates a project and all the expected resources in a well-defined context, usually an ad-hoc folder managed by the resource management stage. Resources are organized by environment within this folder. + + +## How to run this stage + +This stage is meant to be executed after the FAST "foundational" stages: bootstrap, resource management, security and networking stages. + +It is also possible to run this stage in isolation. Refer to the *[Running in isolation](#running-in-isolation)* section below for details. + +Before running this stage, you need to make sure you have the correct credentials and permissions, and localize variables by assigning values that match your configuration. + +### Provider and Terraform variables + +As all other FAST stages, the [mechanism used to pass variable values and pre-built provider files from one stage to the next](../../0-bootstrap/README.md#output-files-and-cross-stage-variables) is also leveraged here. + +The commands to link or copy the provider and terraform variable files can be easily derived from the `stage-links.sh` script in the FAST root folder, passing it a single argument with the local output files folder (if configured) or the GCS output bucket in the automation project (derived from stage 0 outputs). The following examples demonstrate both cases, and the resulting commands that then need to be copy/pasted and run. + +```bash +../../../stage-links.sh ~/fast-config + +# copy and paste the following commands for '3-gcve' + +ln -s ~/fast-config/providers/3-gcve-dev-providers.tf ./ +ln -s ~/fast-config/tfvars/0-globals.auto.tfvars.json ./ +ln -s ~/fast-config/tfvars/0-bootstrap.auto.tfvars.json ./ +ln -s ~/fast-config/tfvars/1-resman.auto.tfvars.json ./ +ln -s ~/fast-config/tfvars/2-networking.auto.tfvars.json ./ +``` + +```bash +../../../stage-links.sh gs://xxx-prod-iac-core-outputs-0 + +# copy and paste the following commands for '3-gcve' + +gcloud alpha storage cp gs://xxx-prod-iac-core-outputs-0/providers/3-gcve-dev-providers.tf ./ +gcloud alpha storage cp gs://xxx-prod-iac-core-outputs-0/tfvars/0-globals.auto.tfvars.json ./ +gcloud alpha storage cp gs://xxx-prod-iac-core-outputs-0/tfvars/0-bootstrap.auto.tfvars.json ./ +gcloud alpha storage cp gs://xxx-prod-iac-core-outputs-0/tfvars/1-resman.auto.tfvars.json ./ +gcloud alpha storage cp gs://xxx-prod-iac-core-outputs-0/tfvars/2-networking.auto.tfvars.json ./ +``` + +### Impersonating the automation service account + +The preconfigured provider file uses impersonation to run with this stage's automation service account's credentials. The `gcp-devops` and `organization-admins` groups have the necessary IAM bindings in place to do that, so make sure the current user is a member of one of those groups. + +### Variable configuration + +Variables in this stage -- like most other FAST stages -- are broadly divided into three separate sets: + +- variables which refer to global values for the whole organization (org id, billing account id, prefix, etc.), which are pre-populated via the `0-globals.auto.tfvars.json` file linked or copied above +- variables which refer to resources managed by previous stage, which are prepopulated here via the `*.auto.tfvars.json` files linked or copied above +- and finally variables that optionally control this stage's behaviour and customizations, and can to be set in a custom `terraform.tfvars` file + +The full list can be found in the [Variables](#variables) table at the bottom of this document. + +### Running the stage + +Once provider and variable values are in place and the correct user is configured, the stage can be run: + +```bash +terraform init +terraform apply +``` + +### Running in isolation + +This stage can be run in isolation by providing the necessary variables, but it's really meant to be used as part of the FAST flow after the "foundational stages" ([`0-bootstrap`](../../0-bootstrap), [`1-resman`](../../1-resman), [`2-networking`](../../2-networking-b-vpn). + +When running in isolation, the following roles are needed on the principal used to apply Terraform: + +- on the organization or network folder level + - `roles/xpnAdmin` or a custom role which includes the following permissions + - `"compute.organizations.enableXpnResource"`, + - `"compute.organizations.disableXpnResource"`, + - `"compute.subnetworks.setIamPolicy"`, +- on each folder where projects are created + - `"roles/logging.admin"` + - `"roles/owner"` + - `"roles/resourcemanager.folderAdmin"` + - `"roles/resourcemanager.projectCreator"` +- on the host project for the Shared VPC + - `"roles/browser"` + - `"roles/compute.viewer"` +- on the organization or billing account + - `roles/billing.admin` + +The VPC host project, VPC and subnets should already exist. + + + +## Files + +| name | description | modules | resources | +|---|---|---|---| +| [main.tf](./main.tf) | GCVE private cloud for development environment. | 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 00000000..98531493 --- /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 00000000..5c97be02 --- /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 00000000..ee48c970 --- /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 1c4da1e5..1cc8029c 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 7585109c..3f2e1ad4 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 06b444c3..832efc8b 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 c6f64409..466efd2f 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 0d7174df..ab916dd5 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 9d0a4a70..bf3dd68e 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 7deb24f4..a5f4d964 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 d8bce3ae..63decb4f 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 c4d09672..b0fea5a7 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 00000000..7ba50f93 --- /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 00000000..b27af097 --- /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 00000000..eb10f3c1 --- /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 00000000..f1342a6f --- /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