diff --git a/CHANGELOG.md b/CHANGELOG.md index ac785d99a9..8a34721182 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ All notable changes to this project will be documented in this file. ### BLUEPRINTS +- [[#2243](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2243)] Added new attributes Apigee organization and bumped up providers version ([apichick](https://github.com/apichick)) +- [[#2239](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2239)] Update README.md ([vicenteg](https://github.com/vicenteg)) +- [[#2230](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2230)] docs: :memo: fix error in phpIPAM terraform config by updating VPC pe… ([PapaPeskwo](https://github.com/PapaPeskwo)) - [[#2227](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2227)] Bump golang.org/x/net from 0.17.0 to 0.23.0 in /blueprints/cloud-operations/unmanaged-instances-healthcheck/function/healthchecker ([dependabot[bot]](https://github.com/dependabot[bot])) - [[#2228](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2228)] Bump golang.org/x/net from 0.17.0 to 0.23.0 in /blueprints/cloud-operations/unmanaged-instances-healthcheck/function/restarter ([dependabot[bot]](https://github.com/dependabot[bot])) - [[#2226](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2226)] fix cloud sql PSA after module upgrade ([simonebruzzechesse](https://github.com/simonebruzzechesse)) @@ -29,6 +32,12 @@ All notable changes to this project will be documented in this file. ### FAST +- [[#2267](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2267)] Fix 0-bootstrap iam_by_principals not taking into account all principals ([wiktorn](https://github.com/wiktorn)) +- [[#2263](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2263)] Update docs - gcp-network-admins -> gcp-vpc-network-admins ([wiktorn](https://github.com/wiktorn)) +- [[#2260](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2260)] Remove data source from folder module ([ludoo](https://github.com/ludoo)) +- [[#2253](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2253)] Misc FAST fixes ([juliocc](https://github.com/juliocc)) +- [[#2235](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2235)] Update FAST logging ([juliocc](https://github.com/juliocc)) +- [[#2233](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2233)] Fix permissions for branch network dev - read sa ([LucaPrete](https://github.com/LucaPrete)) - [[#2221](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2221)] Enable TFLint in FAST stages ([juliocc](https://github.com/juliocc)) - [[#2220](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2220)] Add tflint to pipelines ([juliocc](https://github.com/juliocc)) - [[#2218](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2218)] **incompatible change:** Allow multiple PSA service providers in net-vpc module ([ludoo](https://github.com/ludoo)) @@ -46,6 +55,26 @@ All notable changes to this project will be documented in this file. ### MODULES +- [[#2270](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2270)] Cloud function CMEK key support ([luigi-bitonti](https://github.com/luigi-bitonti)) +- [[#2272](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2272)] New Bindplane cloud-config-container setup ([simonebruzzechesse](https://github.com/simonebruzzechesse)) +- [[#2269](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2269)] Implement the full IAM interface for tags ([ludoo](https://github.com/ludoo)) +- [[#2268](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2268)] Add logging settings to folder module ([ludoo](https://github.com/ludoo)) +- [[#2242](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2242)] CloudSQL PSC Endpoints support ([wiktorn](https://github.com/wiktorn)) +- [[#2265](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2265)] Fix failing E2E net-vpc test ([wiktorn](https://github.com/wiktorn)) +- [[#2264](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2264)] Fix bug from output typo in new project-factory module ([JanCVanB](https://github.com/JanCVanB)) +- [[#2262](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2262)] Make Simple NVA route IAP traffic through NIC 0 ([juliocc](https://github.com/juliocc)) +- [[#2261](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2261)] Add Hybrid NAT support ([juliocc](https://github.com/juliocc)) +- [[#2260](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2260)] Remove data source from folder module ([ludoo](https://github.com/ludoo)) +- [[#2247](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2247)] Fix workstation-cluster module for private deployment ([simonebruzzechesse](https://github.com/simonebruzzechesse)) +- [[#2252](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2252)] Add support for labels to GKE backup plans ([ludoo](https://github.com/ludoo)) +- [[#2251](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2251)] Fix factory ingress policy services in vpc-sc module ([ludoo](https://github.com/ludoo)) +- [[#2248](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2248)] Added missing identity when connectors API is enabled ([jnahelou](https://github.com/jnahelou)) +- [[#2246](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2246)] Fixed issue with service networking DNS peering ([apichick](https://github.com/apichick)) +- [[#2243](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2243)] Added new attributes Apigee organization and bumped up providers version ([apichick](https://github.com/apichick)) +- [[#2244](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2244)] **incompatible change:** Removed BFD settings from net-vpn-ha module as it is not supported ([apichick](https://github.com/apichick)) +- [[#2241](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2241)] Use default labels on pubsub subscription when no override is provided ([wiktorn](https://github.com/wiktorn)) +- [[#2238](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2238)] fix: allow disabling node autoprovisioning ([kumadee](https://github.com/kumadee)) +- [[#2234](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2234)] Added build environment variables in cloud function v1 ([luigi-bitonti](https://github.com/luigi-bitonti)) - [[#2229](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2229)] **incompatible change:** Refactor vpc-sc support in project module, add support for dry run ([ludoo](https://github.com/ludoo)) - [[#2226](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2226)] fix cloud sql PSA after module upgrade ([simonebruzzechesse](https://github.com/simonebruzzechesse)) - [[#2224](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2224)] added missing option for exclusion scope ([cmalpe](https://github.com/cmalpe)) diff --git a/blueprints/data-solutions/data-playground/README.md b/blueprints/data-solutions/data-playground/README.md index a2eceeba91..ef490ab27c 100644 --- a/blueprints/data-solutions/data-playground/README.md +++ b/blueprints/data-solutions/data-playground/README.md @@ -1,6 +1,6 @@ # Data Playground -This blueprint creates a minimum viable architecture for a data experimentation project with the needed APIs enabled, VPC and Firewall set in place, BigQuesy dataset, GCS bucket and an AI notebook to get started. +This blueprint creates a minimum viable architecture for a data experimentation project with the needed APIs enabled, VPC and Firewall set in place, BigQuery dataset, GCS bucket and an AI notebook to get started. This is the high level diagram: diff --git a/blueprints/gke/patterns/autopilot-cluster/versions.tf b/blueprints/gke/patterns/autopilot-cluster/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/blueprints/gke/patterns/autopilot-cluster/versions.tf +++ b/blueprints/gke/patterns/autopilot-cluster/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/blueprints/gke/patterns/batch/versions.tf b/blueprints/gke/patterns/batch/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/blueprints/gke/patterns/batch/versions.tf +++ b/blueprints/gke/patterns/batch/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/blueprints/gke/patterns/kafka/versions.tf b/blueprints/gke/patterns/kafka/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/blueprints/gke/patterns/kafka/versions.tf +++ b/blueprints/gke/patterns/kafka/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/blueprints/gke/patterns/mysql/versions.tf b/blueprints/gke/patterns/mysql/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/blueprints/gke/patterns/mysql/versions.tf +++ b/blueprints/gke/patterns/mysql/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/blueprints/gke/patterns/redis-cluster/versions.tf b/blueprints/gke/patterns/redis-cluster/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/blueprints/gke/patterns/redis-cluster/versions.tf +++ b/blueprints/gke/patterns/redis-cluster/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/default-versions.tf b/default-versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/default-versions.tf +++ b/default-versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/fast/stages-multitenant/0-bootstrap-tenant/README.md b/fast/stages-multitenant/0-bootstrap-tenant/README.md index 9e3a74d84a..a1b3ba367b 100644 --- a/fast/stages-multitenant/0-bootstrap-tenant/README.md +++ b/fast/stages-multitenant/0-bootstrap-tenant/README.md @@ -208,7 +208,7 @@ This configuration is possible but unsupported and only exists for development p | [custom_roles](variables.tf#L95) | Custom roles defined at the organization level, in key => id format. | object({…}) | | null | 0-bootstrap | | [fast_features](variables.tf#L105) | Selective control for top-level FAST features. | object({…}) | | {} | 0-bootstrap | | [federated_identity_providers](variables.tf#L119) | Workload Identity Federation pools. The `cicd_repositories` variable references keys here. | map(object({…})) | | {} | | -| [groups](variables.tf#L133) | 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 | +| [groups](variables.tf#L133) | 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 | | [iam](variables.tf#L146) | Tenant-level custom IAM settings in role => [principal] format. | map(list(string)) | | {} | | | [iam_bindings_additive](variables.tf#L152) | Individual additive IAM bindings. Keys are arbitrary. | map(object({…})) | | {} | | | [iam_by_principals](variables.tf#L167) | 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)) | | {} | | diff --git a/fast/stages-multitenant/0-bootstrap-tenant/variables.tf b/fast/stages-multitenant/0-bootstrap-tenant/variables.tf index 74daa0a9f1..5fa964beee 100644 --- a/fast/stages-multitenant/0-bootstrap-tenant/variables.tf +++ b/fast/stages-multitenant/0-bootstrap-tenant/variables.tf @@ -1,5 +1,5 @@ /** - * Copyright 2023 Google LLC + * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -136,7 +136,7 @@ variable "groups" { description = "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." type = object({ gcp-devops = optional(string, "gcp-devops") - gcp-network-admins = optional(string, "gcp-network-admins") + gcp-network-admins = optional(string, "gcp-vpc-network-admins") gcp-security-admins = optional(string, "gcp-security-admins") }) nullable = false diff --git a/fast/stages/0-bootstrap/README.md b/fast/stages/0-bootstrap/README.md index 83031f5d2a..758eac468f 100644 --- a/fast/stages/0-bootstrap/README.md +++ b/fast/stages/0-bootstrap/README.md @@ -39,6 +39,7 @@ Use the following diagram as a simple high level reference for the following sec - [Log sinks and log destinations](#log-sinks-and-log-destinations) - [Names and naming convention](#names-and-naming-convention) - [Workload Identity Federation](#workload-identity-federation) + - [Project folders](#project-folders) - [CI/CD repositories](#cicd-repositories) - [Toggling features](#toggling-features) - [Files](#files) @@ -138,7 +139,9 @@ Because of limitations of API availability, manual steps have to be followed to ### Organization-level logging -We create organization-level log sinks early in the bootstrap process to ensure a proper audit trail is in place from the very beginning. By default, we provide log filters to capture [Cloud Audit Logs](https://cloud.google.com/logging/docs/audit), [VPC Service Controls violations](https://cloud.google.com/vpc-service-controls/docs/troubleshooting#vpc-sc-errors) and [Workspace Logs](https://cloud.google.com/logging/docs/audit/configure-gsuite-audit-logs) into logging buckets in the top-level audit logging project. +We create organization-level log sinks early in the bootstrap process to ensure a proper audit trail is in place from the very beginning. By default, we provide log filters to capture [Cloud Audit Logs](https://cloud.google.com/logging/docs/audit), [VPC Service Controls violations](https://cloud.google.com/vpc-service-controls/docs/troubleshooting#vpc-sc-errors) and [Workspace Logs](https://cloud.google.com/logging/docs/audit/configure-gsuite-audit-logs) into logging buckets in the top-level audit logging project. + +An organization-level sink captures IAM data access logs, including authentication and impersonation events for service accounts. To manage logging costs, the default configuration enables IAM data access logging only within the automation project (where sensitive service accounts reside). For enhanced security across the entire organization, consider enabling these logs at the organization level. The [Customizations](#log-sinks-and-log-destinations) section explains how to change the logs captured and their destination. @@ -273,7 +276,7 @@ Before the first run, the following IAM groups must exist to allow IAM bindings - `gcp-billing-admins` - `gcp-devops` -- `gcp-network-admins` +- `gcp-vpc-network-admins` - `gcp-organization-admins` - `gcp-security-admins` @@ -531,6 +534,18 @@ workload_identity_providers = { } ``` +### Project folders + +By default this stage creates all its projects directly under the orgaization node. If desired, projects can be moved under a folder using the `project_parent_ids` variable. + +```tfvars +project_parent_ids = { + automation = "folders/1234567890" + billing = "folders/9876543210" + logging = "folders/1234567890" +} +``` + ### CI/CD repositories FAST is designed to directly support running in automated workflows from separate repositories for each stage. The `cicd_repositories` variable allows you to configure impersonation from external repositories leveraging Workload identity Federation, and pre-configures a FAST workflow file that can be used to validate and apply the code in each repository. @@ -593,9 +608,10 @@ The remaining configuration is manual, as it regards the repositories themselves Some FAST features can be enabled or disabled using the `fast_features` variables. While this variable is not directly used in the bootstrap stage, it can instruct the following stages to create certain resources only if needed. -The `fast_features` variable consists of 4 toggles: +The `fast_features` variable consists of 6 toggles: - **`data_platform`** controls the creation of required resources (folders, service accounts, buckets, IAM bindings) to deploy the [3-data-platform](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/tree/master/fast/stages/3-data-platform) stage +- **`gcve`** controls the creation of required resources (folders, service accounts, buckets, IAM bindings) to deploy the [3-gcve](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/tree/master/fast/stages/3-gcve) stage - **`gke`** controls the creation of required resources (folders, service accounts, buckets, IAM bindings) to deploy the [3-gke-multitenant](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/tree/master/fast/stages/3-gke-multitenant) stage - **`project_factory`** controls the creation of required resources (folders, service accounts, buckets, IAM bindings) to deploy the [3-project-factory](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/tree/master/fast/stages/3-project-factory) stage - **`sandbox`** controls the creation of a "Sandbox" top level folder with relaxed policies, intended for sandbox environments where users can experiment @@ -626,25 +642,25 @@ 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#L223) | Organization details. | object({…}) | ✓ | | | -| [prefix](variables.tf#L238) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | | +| [organization](variables.tf#L241) | Organization details. | object({…}) | ✓ | | | +| [prefix](variables.tf#L256) | 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({…}) | | {} | | -| [groups](variables.tf#L118) | 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({…}) | | {} | | +| [groups](variables.tf#L118) | 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#L134) | Organization-level custom IAM settings in role => [principal] format. | map(list(string)) | | {} | | | [iam_bindings_additive](variables.tf#L141) | Organization-level custom additive IAM bindings. Keys are arbitrary. | map(object({…})) | | {} | | | [iam_by_principals](variables.tf#L156) | Authoritative IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid cycle errors. Merged internally with the `iam` variable. | map(list(string)) | | {} | | | [locations](variables.tf#L163) | Optional locations for GCS, BigQuery, and logging buckets created here. | object({…}) | | {} | | -| [log_sinks](variables.tf#L177) | Org-level log sinks, in name => {type, filter} format. | map(object({…})) | | {…} | | -| [org_policies_config](variables.tf#L206) | Organization policies customization. | object({…}) | | {} | | -| [outputs_location](variables.tf#L232) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable. | string | | null | | -| [project_parent_ids](variables.tf#L247) | Optional parents for projects created here in folders/nnnnnnn format. Null values will use the organization as parent. | object({…}) | | {} | | -| [workforce_identity_providers](variables.tf#L258) | Workforce Identity Federation pools. | map(object({…})) | | {} | | -| [workload_identity_providers](variables.tf#L274) | Workload Identity Federation pools. The `cicd_repositories` variable references keys here. | map(object({…})) | | {} | | +| [log_sinks](variables.tf#L177) | Org-level log sinks, in name => {type, filter} format. | map(object({…})) | | {…} | | +| [org_policies_config](variables.tf#L224) | Organization policies customization. | object({…}) | | {} | | +| [outputs_location](variables.tf#L250) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable. | string | | null | | +| [project_parent_ids](variables.tf#L265) | Optional parents for projects created here in folders/nnnnnnn format. Null values will use the organization as parent. | object({…}) | | {} | | +| [workforce_identity_providers](variables.tf#L276) | Workforce Identity Federation pools. | map(object({…})) | | {} | | +| [workload_identity_providers](variables.tf#L292) | Workload Identity Federation pools. The `cicd_repositories` variable references keys here. | map(object({…})) | | {} | | ## Outputs diff --git a/fast/stages/0-bootstrap/automation.tf b/fast/stages/0-bootstrap/automation.tf index 6200deab38..8463ff16b6 100644 --- a/fast/stages/0-bootstrap/automation.tf +++ b/fast/stages/0-bootstrap/automation.tf @@ -156,6 +156,24 @@ module "automation-project" { "container.googleapis.com", ] ) + + # Enable IAM data access logs to capture impersonation and service + # account token generation events. This is implemented within the + # automation project to limit log volume. For heightened security, + # consider enabling it at the organization level. A log sink within + # the organization will collect and store these logs in a logging + # bucket. See + # https://cloud.google.com/iam/docs/audit-logging#audited_operations + logging_data_access = { + "iam.googleapis.com" = { + # ADMIN_READ captures impersonation and token generation/exchanges + ADMIN_READ = [] + # enable DATA_WRITE if you want to capture configuration changes + # to IAM-related resources (roles, deny policies, service + # accounts, identity pools, etc) + # DATA_WRITE = [] + } + } } # output files bucket diff --git a/fast/stages/0-bootstrap/organization.tf b/fast/stages/0-bootstrap/organization.tf index f91b4e8c14..fdd08937a7 100644 --- a/fast/stages/0-bootstrap/organization.tf +++ b/fast/stages/0-bootstrap/organization.tf @@ -138,8 +138,14 @@ module "organization" { organization_id = module.organization-logging.id # human (groups) IAM bindings iam_by_principals = { - for k, v in local.iam_principals : - k => distinct(concat(v, lookup(var.iam_by_principals, k, []))) + for key in distinct(concat( + keys(local.iam_principals), + keys(var.iam_by_principals), + )) : + key => distinct(concat( + lookup(local.iam_principals, key, []), + lookup(var.iam_by_principals, key, []), + )) } # machine (service accounts) IAM bindings iam = merge( diff --git a/fast/stages/0-bootstrap/variables.tf b/fast/stages/0-bootstrap/variables.tf index 64978dc30f..09c0e08567 100644 --- a/fast/stages/0-bootstrap/variables.tf +++ b/fast/stages/0-bootstrap/variables.tf @@ -121,7 +121,7 @@ variable "groups" { type = object({ gcp-billing-admins = optional(string, "gcp-billing-admins") gcp-devops = optional(string, "gcp-devops") - gcp-network-admins = optional(string, "gcp-network-admins") + gcp-network-admins = optional(string, "gcp-vpc-network-admins") gcp-organization-admins = optional(string, "gcp-organization-admins") gcp-security-admins = optional(string, "gcp-security-admins") # aliased to gcp-devops as the checklist does not create it @@ -182,15 +182,33 @@ variable "log_sinks" { })) default = { audit-logs = { - filter = "logName:\"/logs/cloudaudit.googleapis.com%2Factivity\" OR logName:\"/logs/cloudaudit.googleapis.com%2Fsystem_event\" OR protoPayload.metadata.@type=\"type.googleapis.com/google.cloud.audit.TransparencyLog\"" + filter = <<-FILTER + log_id("cloudaudit.googleapis.com/activity") OR + log_id("cloudaudit.googleapis.com/system_event") OR + log_id("cloudaudit.googleapis.com/policy") OR + log_id("cloudaudit.googleapis.com/access_transparency") + FILTER + type = "logging" + } + iam = { + filter = <<-FILTER + protoPayload.serviceName="iamcredentials.googleapis.com" OR + protoPayload.serviceName="iam.googleapis.com" OR + protoPayload.serviceName="sts.googleapis.com" + FILTER type = "logging" } vpc-sc = { - filter = "protoPayload.metadata.@type=\"type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata\"" + filter = <<-FILTER + protoPayload.metadata.@type="type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata" + FILTER type = "logging" } workspace-audit-logs = { - filter = "logName:\"/logs/cloudaudit.googleapis.com%2Fdata_access\" and protoPayload.serviceName:\"login.googleapis.com\"" + filter = <<-FILTER + log_id("cloudaudit.googleapis.com/data_access") AND + protoPayload.serviceName="login.googleapis.com" + FILTER type = "logging" } } diff --git a/fast/stages/1-resman/README.md b/fast/stages/1-resman/README.md index 6b7836fd8b..5ac024870b 100644 --- a/fast/stages/1-resman/README.md +++ b/fast/stages/1-resman/README.md @@ -358,21 +358,21 @@ 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#L232) | Organization details. | object({…}) | ✓ | | 0-bootstrap | -| [prefix](variables.tf#L248) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 0-bootstrap | +| [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#L159) | Configuration for the resource factories or external data. | object({…}) | | {} | | | [fast_features](variables.tf#L168) | Selective control for top-level FAST features. | object({…}) | | {} | 0-0-bootstrap | | [folder_iam](variables.tf#L183) | Authoritative IAM for top-level folders. | object({…}) | | {} | | -| [groups](variables.tf#L199) | 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#L214) | Optional locations for GCS, BigQuery, and logging buckets created here. | object({…}) | | {…} | 0-bootstrap | -| [outputs_location](variables.tf#L242) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable. | string | | null | | -| [tag_names](variables.tf#L259) | Customized names for resource management tags. | object({…}) | | {} | | -| [tags](variables.tf#L274) | Custom secure tags by key name. The `iam` attribute behaves like the similarly named one at module level. | map(object({…})) | | {} | | -| [team_folders](variables.tf#L295) | Team folders to be created. Format is described in a code comment. | map(object({…})) | | null | | -| [tenants](variables.tf#L311) | Lightweight tenant definitions. | map(object({…})) | | {} | | -| [tenants_config](variables.tf#L327) | Lightweight tenants shared configuration. Roles will be assigned to tenant admin group and service accounts. | object({…}) | | {} | | +| [groups](variables.tf#L199) | 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#L214) | Optional locations for GCS, BigQuery, and logging buckets created here. | 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) | Custom 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 @@ -380,7 +380,7 @@ Due to its simplicity, this stage lends itself easily to customizations: adding |---|---|:---:|---| | [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 | +| [gcve](outputs.tf#L421) | Data for the GCVE stage. | | 03-gcve | | [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. | | | diff --git a/fast/stages/1-resman/branch-networking.tf b/fast/stages/1-resman/branch-networking.tf index e57a874ff6..e886234bdb 100644 --- a/fast/stages/1-resman/branch-networking.tf +++ b/fast/stages/1-resman/branch-networking.tf @@ -101,10 +101,10 @@ module "branch-network-dev-folder" { ) # 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.dp-dev, + local.branch_optional_r_sa_lists.gke-dev, local.branch_optional_r_sa_lists.gcve-dev, - local.branch_optional_r_sa_lists.pf-prod, + local.branch_optional_r_sa_lists.pf-dev, ) (local.custom_roles.gcve_network_admin) = local.branch_optional_sa_lists.gcve-dev } diff --git a/fast/stages/1-resman/outputs.tf b/fast/stages/1-resman/outputs.tf index 31e9590203..de411b9115 100644 --- a/fast/stages/1-resman/outputs.tf +++ b/fast/stages/1-resman/outputs.tf @@ -419,7 +419,7 @@ output "dataplatform" { } output "gcve" { - # tfdoc:output:consumers 03-gke-multitenant + # tfdoc:output:consumers 03-gcve description = "Data for the GCVE stage." value = ( var.fast_features.gcve diff --git a/fast/stages/1-resman/variables.tf b/fast/stages/1-resman/variables.tf index 8417466730..3256b9bb74 100644 --- a/fast/stages/1-resman/variables.tf +++ b/fast/stages/1-resman/variables.tf @@ -203,7 +203,7 @@ variable "groups" { type = object({ gcp-billing-admins = optional(string, "gcp-billing-admins") gcp-devops = optional(string, "gcp-devops") - gcp-network-admins = optional(string, "gcp-network-admins") + gcp-network-admins = optional(string, "gcp-vpc-network-admins") gcp-organization-admins = optional(string, "gcp-organization-admins") gcp-security-admins = optional(string, "gcp-security-admins") }) @@ -215,18 +215,13 @@ variable "locations" { # tfdoc:variable:source 0-bootstrap description = "Optional locations for GCS, BigQuery, and logging buckets created here." type = object({ - bq = string - gcs = string - logging = string - pubsub = list(string) + bq = optional(string, "EU") + gcs = optional(string, "EU") + logging = optional(string, "global") + pubsub = optional(list(string), []) }) - default = { - bq = "EU" - gcs = "EU" - logging = "global" - pubsub = [] - } nullable = false + default = {} } variable "organization" { diff --git a/fast/stages/2-networking-a-peering/data/hierarchical-ingress-rules.yaml b/fast/stages/2-networking-a-peering/data/hierarchical-ingress-rules.yaml index 93d42fbee8..e444dd3f0b 100644 --- a/fast/stages/2-networking-a-peering/data/hierarchical-ingress-rules.yaml +++ b/fast/stages/2-networking-a-peering/data/hierarchical-ingress-rules.yaml @@ -11,14 +11,14 @@ # - rfc1918 allow-healthchecks: - description: Enable HTTP and HTTPS healthchecks + description: Enable SSH, HTTP and HTTPS healthchecks priority: 1001 match: source_ranges: - healthchecks layer4_configs: - protocol: tcp - ports: ["80", "443"] + ports: ["22", "80", "443"] allow-ssh-from-iap: description: Enable SSH from IAP diff --git a/fast/stages/2-networking-b-vpn/data/hierarchical-ingress-rules.yaml b/fast/stages/2-networking-b-vpn/data/hierarchical-ingress-rules.yaml index 0504f376c8..817be2e99d 100644 --- a/fast/stages/2-networking-b-vpn/data/hierarchical-ingress-rules.yaml +++ b/fast/stages/2-networking-b-vpn/data/hierarchical-ingress-rules.yaml @@ -11,14 +11,14 @@ # - rfc1918 allow-healthchecks: - description: Enable HTTP and HTTPS healthchecks + description: Enable SSH, HTTP and HTTPS healthchecks priority: 1001 match: source_ranges: - healthchecks layer4_configs: - protocol: tcp - ports: ["80", "443"] + ports: ["22", "80", "443"] allow-ssh-from-iap: description: Enable SSH from IAP diff --git a/fast/stages/2-networking-c-nva/data/hierarchical-ingress-rules.yaml b/fast/stages/2-networking-c-nva/data/hierarchical-ingress-rules.yaml index 0504f376c8..817be2e99d 100644 --- a/fast/stages/2-networking-c-nva/data/hierarchical-ingress-rules.yaml +++ b/fast/stages/2-networking-c-nva/data/hierarchical-ingress-rules.yaml @@ -11,14 +11,14 @@ # - rfc1918 allow-healthchecks: - description: Enable HTTP and HTTPS healthchecks + description: Enable SSH, HTTP and HTTPS healthchecks priority: 1001 match: source_ranges: - healthchecks layer4_configs: - protocol: tcp - ports: ["80", "443"] + ports: ["22", "80", "443"] allow-ssh-from-iap: description: Enable SSH from IAP diff --git a/fast/stages/2-networking-d-separate-envs/data/hierarchical-ingress-rules.yaml b/fast/stages/2-networking-d-separate-envs/data/hierarchical-ingress-rules.yaml index 0504f376c8..817be2e99d 100644 --- a/fast/stages/2-networking-d-separate-envs/data/hierarchical-ingress-rules.yaml +++ b/fast/stages/2-networking-d-separate-envs/data/hierarchical-ingress-rules.yaml @@ -11,14 +11,14 @@ # - rfc1918 allow-healthchecks: - description: Enable HTTP and HTTPS healthchecks + description: Enable SSH, HTTP and HTTPS healthchecks priority: 1001 match: source_ranges: - healthchecks layer4_configs: - protocol: tcp - ports: ["80", "443"] + ports: ["22", "80", "443"] allow-ssh-from-iap: description: Enable SSH from IAP diff --git a/fast/stages/2-networking-e-nva-bgp/data/hierarchical-ingress-rules.yaml b/fast/stages/2-networking-e-nva-bgp/data/hierarchical-ingress-rules.yaml index 0504f376c8..817be2e99d 100644 --- a/fast/stages/2-networking-e-nva-bgp/data/hierarchical-ingress-rules.yaml +++ b/fast/stages/2-networking-e-nva-bgp/data/hierarchical-ingress-rules.yaml @@ -11,14 +11,14 @@ # - rfc1918 allow-healthchecks: - description: Enable HTTP and HTTPS healthchecks + description: Enable SSH, HTTP and HTTPS healthchecks priority: 1001 match: source_ranges: - healthchecks layer4_configs: - protocol: tcp - ports: ["80", "443"] + ports: ["22", "80", "443"] allow-ssh-from-iap: description: Enable SSH from IAP diff --git a/modules/__experimental_deprecated/alloydb-instance/versions.tf b/modules/__experimental_deprecated/alloydb-instance/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/__experimental_deprecated/alloydb-instance/versions.tf +++ b/modules/__experimental_deprecated/alloydb-instance/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/__experimental_deprecated/net-neg/versions.tf b/modules/__experimental_deprecated/net-neg/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/__experimental_deprecated/net-neg/versions.tf +++ b/modules/__experimental_deprecated/net-neg/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/__experimental_deprecated/project-iam-magic/versions.tf b/modules/__experimental_deprecated/project-iam-magic/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/__experimental_deprecated/project-iam-magic/versions.tf +++ b/modules/__experimental_deprecated/project-iam-magic/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/analytics-hub/versions.tf b/modules/analytics-hub/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/analytics-hub/versions.tf +++ b/modules/analytics-hub/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/api-gateway/versions.tf b/modules/api-gateway/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/api-gateway/versions.tf +++ b/modules/api-gateway/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/apigee/README.md b/modules/apigee/README.md index 24c6f4166a..ebae675f31 100644 --- a/modules/apigee/README.md +++ b/modules/apigee/README.md @@ -359,13 +359,13 @@ module "apigee" { | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [project_id](variables.tf#L126) | Project ID. | string | ✓ | | +| [project_id](variables.tf#L130) | Project ID. | string | ✓ | | | [addons_config](variables.tf#L17) | Addons configuration. | object({…}) | | null | | [endpoint_attachments](variables.tf#L29) | Endpoint attachments. | map(object({…})) | | {} | | [envgroups](variables.tf#L39) | Environment groups (NAME => [HOSTNAMES]). | map(list(string)) | | {} | -| [environments](variables.tf#L46) | Environments. | map(object({…})) | | {} | -| [instances](variables.tf#L73) | Instances ([REGION] => [INSTANCE]). | map(object({…})) | | {} | -| [organization](variables.tf#L98) | Apigee organization. If set to null the organization must already exist. | object({…}) | | null | +| [environments](variables.tf#L46) | Environments. | map(object({…})) | | {} | +| [instances](variables.tf#L73) | Instances ([REGION] => [INSTANCE]). | map(object({…})) | | {} | +| [organization](variables.tf#L98) | Apigee organization. If set to null the organization must already exist. | object({…}) | | null | ## Outputs diff --git a/modules/apigee/main.tf b/modules/apigee/main.tf index bb0417b279..afbc1e5af6 100644 --- a/modules/apigee/main.tf +++ b/modules/apigee/main.tf @@ -20,15 +20,30 @@ locals { } resource "google_apigee_organization" "organization" { - count = var.organization == null ? 0 : 1 - analytics_region = var.organization.analytics_region - project_id = var.project_id - authorized_network = var.organization.authorized_network - billing_type = var.organization.billing_type - runtime_type = var.organization.runtime_type - runtime_database_encryption_key_name = var.organization.database_encryption_key - retention = var.organization.retention - disable_vpc_peering = var.organization.disable_vpc_peering + count = var.organization == null ? 0 : 1 + analytics_region = var.organization.analytics_region + project_id = var.project_id + authorized_network = var.organization.authorized_network + billing_type = var.organization.billing_type + runtime_type = var.organization.runtime_type + runtime_database_encryption_key_name = var.organization.database_encryption_key + retention = var.organization.retention + disable_vpc_peering = var.organization.disable_vpc_peering + api_consumer_data_location = var.organization.api_consumer_data_location + api_consumer_data_encryption_key_name = var.organization.api_consumer_data_encryption_key + control_plane_encryption_key_name = var.organization.control_plane_encryption_key + dynamic "properties" { + for_each = length(var.organization.properties) > 0 ? [""] : [] + content { + dynamic "property" { + for_each = var.organization.properties + content { + name = properties.key + value = properties.value + } + } + } + } } resource "google_apigee_envgroup" "envgroups" { diff --git a/modules/apigee/variables.tf b/modules/apigee/variables.tf index 027ad05e47..6ce9fdcf1f 100644 --- a/modules/apigee/variables.tf +++ b/modules/apigee/variables.tf @@ -46,16 +46,12 @@ variable "envgroups" { variable "environments" { description = "Environments." type = map(object({ - display_name = optional(string) + api_proxy_type = optional(string) description = optional(string, "Terraform-managed") + display_name = optional(string) deployment_type = optional(string) - api_proxy_type = optional(string) - type = optional(string) - node_config = optional(object({ - min_node_count = optional(number) - max_node_count = optional(number) - })) - iam = optional(map(list(string)), {}) + envgroups = optional(list(string), []) + iam = optional(map(list(string)), {}) iam_bindings = optional(map(object({ role = string members = list(string) @@ -64,7 +60,11 @@ variable "environments" { role = string member = string })), {}) - envgroups = optional(list(string), []) + node_config = optional(object({ + min_node_count = optional(number) + max_node_count = optional(number) + })) + type = optional(string) })) default = {} nullable = false @@ -73,15 +73,15 @@ variable "environments" { variable "instances" { description = "Instances ([REGION] => [INSTANCE])." type = map(object({ - name = optional(string) - display_name = optional(string) + consumer_accept_list = optional(list(string)) description = optional(string, "Terraform-managed") - runtime_ip_cidr_range = optional(string) - troubleshooting_ip_cidr_range = optional(string) disk_encryption_key = optional(string) - consumer_accept_list = optional(list(string)) + display_name = optional(string) enable_nat = optional(bool, false) environments = optional(list(string), []) + name = optional(string) + runtime_ip_cidr_range = optional(string) + troubleshooting_ip_cidr_range = optional(string) })) validation { condition = alltrue([ @@ -98,15 +98,19 @@ variable "instances" { variable "organization" { description = "Apigee organization. If set to null the organization must already exist." type = object({ - display_name = optional(string) - description = optional(string, "Terraform-managed") - authorized_network = optional(string) - runtime_type = optional(string, "CLOUD") - billing_type = optional(string) - database_encryption_key = optional(string) - analytics_region = optional(string, "europe-west1") - retention = optional(string) - disable_vpc_peering = optional(bool, false) + analytics_region = optional(string) + api_consumer_data_encryption_key = optional(string) + api_consumer_data_location = optional(string) + authorized_network = optional(string) + billing_type = optional(string) + control_plane_encryption_key = optional(string) + database_encryption_key = optional(string) + description = optional(string, "Terraform-managed") + disable_vpc_peering = optional(bool, false) + display_name = optional(string) + properties = optional(map(string), {}) + runtime_type = optional(string, "CLOUD") + retention = optional(string) }) validation { condition = var.organization == null || ( diff --git a/modules/apigee/versions.tf b/modules/apigee/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/apigee/versions.tf +++ b/modules/apigee/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/artifact-registry/versions.tf b/modules/artifact-registry/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/artifact-registry/versions.tf +++ b/modules/artifact-registry/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/bigquery-dataset/versions.tf b/modules/bigquery-dataset/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/bigquery-dataset/versions.tf +++ b/modules/bigquery-dataset/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/bigtable-instance/versions.tf b/modules/bigtable-instance/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/bigtable-instance/versions.tf +++ b/modules/bigtable-instance/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/billing-account/versions.tf b/modules/billing-account/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/billing-account/versions.tf +++ b/modules/billing-account/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/binauthz/versions.tf b/modules/binauthz/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/binauthz/versions.tf +++ b/modules/binauthz/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/cloud-config-container/README.md b/modules/cloud-config-container/README.md index d7017dcb77..b41490040b 100644 --- a/modules/cloud-config-container/README.md +++ b/modules/cloud-config-container/README.md @@ -11,6 +11,7 @@ These modules are designed for several use cases: ## Available modules +- [Bindplane](./bindplane) - [CoreDNS](./coredns) - [MySQL](./mysql) - [Nginx](./nginx) diff --git a/modules/cloud-config-container/__need_fixing/onprem/versions.tf b/modules/cloud-config-container/__need_fixing/onprem/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/cloud-config-container/__need_fixing/onprem/versions.tf +++ b/modules/cloud-config-container/__need_fixing/onprem/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/cloud-config-container/__need_fixing/squid/versions.tf b/modules/cloud-config-container/__need_fixing/squid/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/cloud-config-container/__need_fixing/squid/versions.tf +++ b/modules/cloud-config-container/__need_fixing/squid/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/cloud-config-container/bindplane/README.md b/modules/cloud-config-container/bindplane/README.md new file mode 100644 index 0000000000..035722521e --- /dev/null +++ b/modules/cloud-config-container/bindplane/README.md @@ -0,0 +1,95 @@ +# Containerized Bindplane on Container Optimized OS + +This module manages a `cloud-config` configuration that starts a containerized [Bindplane](https://observiq.com/solutions) service on Container Optimized OS, using the official [Bindplane EE image](https://hub.docker.com/r/observiq/bindplane-ee) provided by observIQ and documented in the [official documentation page](https://observiq.com/download) when selecting "Docker" as target platform. + +The resulting `cloud-config` can be customized in a number of ways: + +- a custom Bindplane configuration can be set in Docker compose file available in `/run/bindplane/docker-compose.yml` using the `bindplane_config` variable +- additional files can be passed in via the `files` variable +- a completely custom `cloud-config` can be passed in via the `cloud_config` variable, and additional template variables can be passed in via `config_variables` + +The default instance configuration inserts iptables rules to allow traffic on port 3001. + +Logging and monitoring are enabled via the [Google Cloud Logging agent](https://cloud.google.com/container-optimized-os/docs/how-to/logging) configured for the instance via the `google-logging-enabled` metadata property, and the [Node Problem Detector](https://cloud.google.com/container-optimized-os/docs/how-to/monitoring) service started by default on boot. + +The module renders the generated cloud config in the `cloud_config` output, to be used in instances or instance templates via the `user-data` metadata. + +## Setup + +Please refer to the examples below for a sample terraform code for deploying a Bindplane server on GCP Compute VM with COS. After setting up the terraform code run the following commands: + +```bash +terraform init +terraform apply +``` + +Wait for a couple of minutes for the VM to be bootstrapped then connect via IAP tunnel using the following command (substitute the VM name, project and zone according to your configuration): + +```bash +gcloud compute ssh $VM_NAME --project $PROJECT --zone $ZONE -- -L 3001:127.0.0.1:3001 -N -q -f +``` + +Navigate to http://localhost:3001 to access the Bindplane console, the following login page should be displayed. + +

+ Bindplane Login page +

+ +## Examples + +### Default configuration + +This example will create a `cloud-config` that uses the module's defaults, creating a simple bindplane server with default (latest) docker image versions and setting localhost as remote url (suited only for local development). + +```hcl +module "cos-nginx" { + source = "./fabric/modules/cloud-config-container/bindplane" + password = "secret" +} + +module "vm-nginx-tls" { + source = "./fabric/modules/compute-vm" + project_id = "my-project" + zone = "europe-west8-b" + name = "cos-nginx" + network_interfaces = [{ + network = "default" + subnetwork = "gce" + }] + metadata = { + user-data = module.cos-nginx.cloud_config + google-logging-enabled = true + } + boot_disk = { + initialize_params = { + image = "projects/cos-cloud/global/images/family/cos-stable" + type = "pd-ssd" + size = 10 + } + } + tags = ["http-server", "ssh"] +} +# tftest modules=2 resources=2 +``` + + +## Variables + +| name | description | type | required | default | +|---|---|:---:|:---:|:---:| +| [password](variables.tf#L63) | Default admin user password. | string | ✓ | | +| [bindplane_config](variables.tf#L17) | Bindplane configurations. | object({…}) | | {} | +| [cloud_config](variables.tf#L29) | Cloud config template path. If null default will be used. | string | | null | +| [config_variables](variables.tf#L35) | Additional variables used to render the cloud-config and Nginx templates. | map(any) | | {} | +| [file_defaults](variables.tf#L41) | Default owner and permissions for files. | object({…}) | | {…} | +| [files](variables.tf#L53) | Map of extra files to create on the instance, path as key. Owner and permissions will use defaults if null. | map(object({…})) | | {} | +| [runcmd_post](variables.tf#L68) | Extra commands to run after starting nginx. | list(string) | | [] | +| [runcmd_pre](variables.tf#L74) | Extra commands to run before starting nginx. | list(string) | | [] | +| [users](variables.tf#L80) | List of additional usernames to be created. | list(object({…})) | | […] | + +## Outputs + +| name | description | sensitive | +|---|---|:---:| +| [cloud_config](outputs.tf#L17) | Rendered cloud-config file to be passed as user-data instance metadata. | | + diff --git a/modules/cloud-config-container/bindplane/cloud-config.yaml b/modules/cloud-config-container/bindplane/cloud-config.yaml new file mode 100644 index 0000000000..78f6ea6ec5 --- /dev/null +++ b/modules/cloud-config-container/bindplane/cloud-config.yaml @@ -0,0 +1,128 @@ +#cloud-config + +# 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. + +# https://hub.docker.com/r/nginx/nginx/ +# https://nginx.io/manual/toc/#installation + +users: + - name: bindplane + uid: 2000 + %{ for user in users } + - name: ${user.username} + uid: ${user.uid} + %{ endfor } + +write_files: + - path: /var/lib/docker/daemon.json + permissions: 0644 + owner: root + content: | + { + "live-restore": true, + "storage-driver": "overlay2", + "log-opts": { + "max-size": "1024m" + } + } + + - path: /run/bindplane/docker-compose.yml + permissions: 0644 + owner: root + content: | + version: "3" + + volumes: + bindplane: + prometheus: + + services: + prometheus: + container_name: bindplane-prometheus + restart: always + image: ${bindplane_prometheus_image} + ports: + - "9090:9090" + volumes: + - prometheus:/prometheus + + transform: + container_name: bindplane-transform-agent + restart: always + image: ${bindplane_transform_agent_image} + ports: + - "4568:4568" + + bindplane: + container_name: bindplane-server + restart: always + image: ${bindplane_server_image} + ports: + - "3001:3001" + environment: + - BINDPLANE_USERNAME=admin + - BINDPLANE_PASSWORD=${password} + - BINDPLANE_REMOTE_URL=http://${remote_url}:3001 + - BINDPLANE_SESSION_SECRET=${uuid} + - BINDPLANE_LOG_OUTPUT=stdout + - BINDPLANE_ACCEPT_EULA=true + - BINDPLANE_PROMETHEUS_ENABLE=true + - BINDPLANE_PROMETHEUS_ENABLE_REMOTE=true + - BINDPLANE_PROMETHEUS_HOST=prometheus + - BINDPLANE_PROMETHEUS_PORT=9090 + - BINDPLANE_TRANSFORM_AGENT_ENABLE_REMOTE=true + - BINDPLANE_TRANSFORM_AGENT_REMOTE_AGENTS=transform:4568 + volumes: + - bindplane:/data + depends_on: + - prometheus + - transform + + # bindplane container service + - path: /etc/systemd/system/bindplane.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Start bindplane containers + After=gcr-online.target docker.socket + Wants=gcr-online.target docker.socket docker-events-collector.service + [Service] + Environment="HOME=/home/bindplane" + ExecStartPre=/usr/bin/docker-credential-gcr configure-docker + ExecStart=/usr/bin/docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v /var:/var -v /run:/run -w=/var cryptopants/docker-compose-gcr -f /run/bindplane/docker-compose.yml up + ExecStop=/usr/bin/docker rm -f $(docker ps -a -q) + + %{ for path, data in files } + - path: ${path} + owner: ${lookup(data, "owner", "root")} + permissions: ${lookup(data, "permissions", "0644")} + content: | + ${indent(6, data.content)} + %{ endfor } + +bootcmd: + - systemctl start node-problem-detector + +runcmd: +%{ for cmd in runcmd_pre ~} + - ${cmd} +%{ endfor ~} + - iptables -I INPUT 1 -p tcp -m tcp --dport 3001 -m state --state NEW,ESTABLISHED -j ACCEPT + - systemctl daemon-reload + - systemctl start bindplane +%{ for cmd in runcmd_post ~} + - ${cmd} +%{ endfor ~} diff --git a/modules/cloud-config-container/bindplane/images/login.png b/modules/cloud-config-container/bindplane/images/login.png new file mode 100644 index 0000000000..3de1e6829a Binary files /dev/null and b/modules/cloud-config-container/bindplane/images/login.png differ diff --git a/modules/cloud-config-container/bindplane/main.tf b/modules/cloud-config-container/bindplane/main.tf new file mode 100644 index 0000000000..a2a11f8654 --- /dev/null +++ b/modules/cloud-config-container/bindplane/main.tf @@ -0,0 +1,48 @@ +/** + * 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. + */ + +locals { + cloud_config = templatefile(local.template, merge(var.config_variables, { + bindplane_prometheus_image = var.bindplane_config.bindplane_prometheus_image + bindplane_server_image = var.bindplane_config.bindplane_server_image + bindplane_transform_agent_image = var.bindplane_config.bindplane_transform_agent_image + files = local.files + password = var.password + remote_url = var.bindplane_config.remote_url + runcmd_pre = var.runcmd_pre + runcmd_post = var.runcmd_post + users = var.users + uuid = random_uuid.uuid_secret.result + })) + files = { + for path, attrs in var.files : path => { + content = attrs.content, + owner = attrs.owner == null ? var.file_defaults.owner : attrs.owner, + permissions = ( + attrs.permissions == null + ? var.file_defaults.permissions + : attrs.permissions + ) + } + } + template = ( + var.cloud_config == null + ? "${path.module}/cloud-config.yaml" + : var.cloud_config + ) +} + +resource "random_uuid" "uuid_secret" {} diff --git a/modules/cloud-config-container/bindplane/outputs.tf b/modules/cloud-config-container/bindplane/outputs.tf new file mode 100644 index 0000000000..56e0824296 --- /dev/null +++ b/modules/cloud-config-container/bindplane/outputs.tf @@ -0,0 +1,20 @@ +/** + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +output "cloud_config" { + description = "Rendered cloud-config file to be passed as user-data instance metadata." + value = local.cloud_config +} diff --git a/modules/cloud-config-container/bindplane/variables.tf b/modules/cloud-config-container/bindplane/variables.tf new file mode 100644 index 0000000000..39856f4585 --- /dev/null +++ b/modules/cloud-config-container/bindplane/variables.tf @@ -0,0 +1,88 @@ +/** + * 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. + */ + +variable "bindplane_config" { + description = "Bindplane configurations." + type = object({ + remote_url = optional(string, "localhost") + bindplane_server_image = optional(string, "us-central1-docker.pkg.dev/observiq-containers/bindplane/bindplane-ee:latest") + bindplane_transform_agent_image = optional(string, "us-central1-docker.pkg.dev/observiq-containers/bindplane/bindplane-transform-agent:latest") + bindplane_prometheus_image = optional(string, "us-central1-docker.pkg.dev/observiq-containers/bindplane/bindplane-prometheus:1.56.0") + }) + default = {} + nullable = false +} + +variable "cloud_config" { + description = "Cloud config template path. If null default will be used." + type = string + default = null +} + +variable "config_variables" { + description = "Additional variables used to render the cloud-config and Nginx templates." + type = map(any) + default = {} +} + +variable "file_defaults" { + description = "Default owner and permissions for files." + type = object({ + owner = string + permissions = string + }) + default = { + owner = "root" + permissions = "0644" + } +} + +variable "files" { + description = "Map of extra files to create on the instance, path as key. Owner and permissions will use defaults if null." + type = map(object({ + content = string + owner = string + permissions = string + })) + default = {} +} + +variable "password" { + description = "Default admin user password." + type = string +} + +variable "runcmd_post" { + description = "Extra commands to run after starting nginx." + type = list(string) + default = [] +} + +variable "runcmd_pre" { + description = "Extra commands to run before starting nginx." + type = list(string) + default = [] +} + +variable "users" { + description = "List of additional usernames to be created." + type = list(object({ + username = string, + uid = number, + })) + default = [ + ] +} diff --git a/modules/cloud-config-container/bindplane/versions.tf b/modules/cloud-config-container/bindplane/versions.tf new file mode 100644 index 0000000000..bc9986b3c7 --- /dev/null +++ b/modules/cloud-config-container/bindplane/versions.tf @@ -0,0 +1,27 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# 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. + +terraform { + required_version = ">= 1.7.4" + required_providers { + google = { + source = "hashicorp/google" + version = ">= 5.26.0, < 6.0.0" # tftest + } + google-beta = { + source = "hashicorp/google-beta" + version = ">= 5.26.0, < 6.0.0" # tftest + } + } +} diff --git a/modules/cloud-config-container/coredns/versions.tf b/modules/cloud-config-container/coredns/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/cloud-config-container/coredns/versions.tf +++ b/modules/cloud-config-container/coredns/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/cloud-config-container/cos-generic-metadata/versions.tf b/modules/cloud-config-container/cos-generic-metadata/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/cloud-config-container/cos-generic-metadata/versions.tf +++ b/modules/cloud-config-container/cos-generic-metadata/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/versions.tf b/modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/versions.tf +++ b/modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/cloud-config-container/envoy-traffic-director/versions.tf b/modules/cloud-config-container/envoy-traffic-director/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/cloud-config-container/envoy-traffic-director/versions.tf +++ b/modules/cloud-config-container/envoy-traffic-director/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/cloud-config-container/mysql/versions.tf b/modules/cloud-config-container/mysql/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/cloud-config-container/mysql/versions.tf +++ b/modules/cloud-config-container/mysql/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/cloud-config-container/nginx-tls/versions.tf b/modules/cloud-config-container/nginx-tls/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/cloud-config-container/nginx-tls/versions.tf +++ b/modules/cloud-config-container/nginx-tls/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/cloud-config-container/nginx/versions.tf b/modules/cloud-config-container/nginx/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/cloud-config-container/nginx/versions.tf +++ b/modules/cloud-config-container/nginx/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/cloud-config-container/simple-nva/cloud-config.yaml b/modules/cloud-config-container/simple-nva/cloud-config.yaml index 328ace7e2c..b5553793c0 100644 --- a/modules/cloud-config-container/simple-nva/cloud-config.yaml +++ b/modules/cloud-config-container/simple-nva/cloud-config.yaml @@ -1,6 +1,6 @@ #cloud-config -# Copyright 2023 Google LLC +# Copyright 2024 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -51,6 +51,9 @@ write_files: %{ endfor ~} iptables -t nat -A POSTROUTING -o ${interface.name} -j MASQUERADE %{ endif ~} +%{ if interface.number == 0 ~} + ip route add 35.235.240.0/20 via `curl http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/gateway -H "Metadata-Flavor:Google"` dev ${interface.name} +%{ endif ~} %{ for route in interface.routes ~} ip route add ${route} via `curl http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/${interface.number}/gateway -H "Metadata-Flavor:Google"` dev ${interface.name} %{ endfor ~} diff --git a/modules/cloud-config-container/simple-nva/versions.tf b/modules/cloud-config-container/simple-nva/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/cloud-config-container/simple-nva/versions.tf +++ b/modules/cloud-config-container/simple-nva/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/cloud-function-v1/README.md b/modules/cloud-function-v1/README.md index 2d52842bb8..ebcf0dd0aa 100644 --- a/modules/cloud-function-v1/README.md +++ b/modules/cloud-function-v1/README.md @@ -16,6 +16,7 @@ The GCS object used for deployment uses a hash of the bundle zip contents in its - [Private Cloud Build Pool](#private-cloud-build-pool) - [Multiple Cloud Functions within project](#multiple-cloud-functions-within-project) - [Mounting secrets from Secret Manager](#mounting-secrets-from-secret-manager) + - [Using CMEK to encrypt function resources](#using-cmek-to-encrypt-function-resources) - [Variables](#variables) - [Outputs](#outputs) @@ -258,32 +259,57 @@ module "cf-http" { } # tftest modules=1 resources=2 inventory=secrets.yaml ``` + +### Using CMEK to encrypt function resources +This encrypt bucket _gcf-sources-*_ with the provided kms key. The repository has to be encrypted with the same kms key. + +```hcl +module "cf-http" { + source = "./fabric/modules/cloud-function-v1" + project_id = "my-project" + region = "europe-west1" + name = "test-cf-http" + bucket_name = "test-cf-bundles" + bundle_config = { + source_dir = "fabric/assets" + output_path = "bundle.zip" + } + kms_key = "projects/my-project/locations/europe-west1/keyRings/mykeyring/cryptoKeys/mykey" + repository_settings = { + repository = "projects/my-project/locations/europe-west1/repositories/myrepo" + } +} +# tftest modules=1 resources=2 +``` ## Variables | name | description | type | required | default | |---|---|:---:|:---:|:---:| | [bucket_name](variables.tf#L26) | Name of the bucket that will be used for the function code. It will be created with prefix prepended if bucket_config is not null. | string | ✓ | | -| [bundle_config](variables.tf#L38) | Cloud function source folder and generated zip bundle paths. Output path defaults to '/tmp/bundle.zip' if null. | object({…}) | ✓ | | -| [name](variables.tf#L103) | Name used for cloud function and associated resources. | string | ✓ | | -| [project_id](variables.tf#L118) | Project id used for all resources. | string | ✓ | | -| [region](variables.tf#L123) | Region used for all resources. | string | ✓ | | +| [bundle_config](variables.tf#L44) | Cloud function source folder and generated zip bundle paths. Output path defaults to '/tmp/bundle.zip' if null. | object({…}) | ✓ | | +| [name](variables.tf#L115) | Name used for cloud function and associated resources. | string | ✓ | | +| [project_id](variables.tf#L130) | Project id used for all resources. | string | ✓ | | +| [region](variables.tf#L135) | Region used for all resources. | string | ✓ | | | [bucket_config](variables.tf#L17) | Enable and configure auto-created bucket. Set fields to null to use defaults. | object({…}) | | null | -| [build_worker_pool](variables.tf#L32) | Build worker pool, in projects//locations//workerPools/ format. | string | | null | -| [description](variables.tf#L47) | Optional description. | string | | "Terraform managed." | -| [environment_variables](variables.tf#L53) | Cloud function environment variables. | map(string) | | {} | -| [function_config](variables.tf#L59) | Cloud function configuration. Defaults to using main as entrypoint, 1 instance with 256MiB of memory, and 180 second timeout. | object({…}) | | {…} | -| [https_security_level](variables.tf#L79) | The security level for the function: Allowed values are SECURE_ALWAYS, SECURE_OPTIONAL. | string | | null | -| [iam](variables.tf#L85) | IAM bindings for topic in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | -| [ingress_settings](variables.tf#L91) | Control traffic that reaches the cloud function. Allowed values are ALLOW_ALL, ALLOW_INTERNAL_AND_GCLB and ALLOW_INTERNAL_ONLY . | string | | null | -| [labels](variables.tf#L97) | Resource labels. | map(string) | | {} | -| [prefix](variables.tf#L108) | Optional prefix used for resource names. | string | | null | -| [secrets](variables.tf#L128) | Secret Manager secrets. Key is the variable name or mountpoint, volume versions are in version:path format. | map(object({…})) | | {} | -| [service_account](variables.tf#L140) | Service account email. Unused if service account is auto-created. | string | | null | -| [service_account_create](variables.tf#L146) | Auto-create service account. | bool | | false | -| [trigger_config](variables.tf#L152) | Function trigger configuration. Leave null for HTTP trigger. | object({…}) | | null | -| [vpc_connector](variables.tf#L162) | VPC connector configuration. Set create to 'true' if a new connector needs to be created. | object({…}) | | null | -| [vpc_connector_config](variables.tf#L172) | VPC connector network configuration. Must be provided if new VPC connector is being created. | object({…}) | | null | +| [build_environment_variables](variables.tf#L32) | A set of key/value environment variable pairs available during build time. | map(string) | | {} | +| [build_worker_pool](variables.tf#L38) | Build worker pool, in projects//locations//workerPools/ format. | string | | null | +| [description](variables.tf#L53) | Optional description. | string | | "Terraform managed." | +| [environment_variables](variables.tf#L59) | Cloud function environment variables. | map(string) | | {} | +| [function_config](variables.tf#L65) | Cloud function configuration. Defaults to using main as entrypoint, 1 instance with 256MiB of memory, and 180 second timeout. | object({…}) | | {…} | +| [https_security_level](variables.tf#L85) | The security level for the function: Allowed values are SECURE_ALWAYS, SECURE_OPTIONAL. | string | | null | +| [iam](variables.tf#L91) | IAM bindings for topic in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | +| [ingress_settings](variables.tf#L97) | Control traffic that reaches the cloud function. Allowed values are ALLOW_ALL, ALLOW_INTERNAL_AND_GCLB and ALLOW_INTERNAL_ONLY . | string | | null | +| [kms_key](variables.tf#L103) | Resource name of a KMS crypto key (managed by the user) used to encrypt/decrypt function resources in key id format. If specified, you must also provide an artifact registry repository using the docker_repository field that was created with the same KMS crypto key. | string | | null | +| [labels](variables.tf#L109) | Resource labels. | map(string) | | {} | +| [prefix](variables.tf#L120) | Optional prefix used for resource names. | string | | null | +| [repository_settings](variables.tf#L140) | Docker Registry to use for storing the function's Docker images and specific repository. If kms_key is provided, the repository must have already been encrypted with the key. | object({…}) | | {…} | +| [secrets](variables.tf#L151) | Secret Manager secrets. Key is the variable name or mountpoint, volume versions are in version:path format. | map(object({…})) | | {} | +| [service_account](variables.tf#L163) | Service account email. Unused if service account is auto-created. | string | | null | +| [service_account_create](variables.tf#L169) | Auto-create service account. | bool | | false | +| [trigger_config](variables.tf#L175) | Function trigger configuration. Leave null for HTTP trigger. | object({…}) | | null | +| [vpc_connector](variables.tf#L185) | VPC connector configuration. Set create to 'true' if a new connector needs to be created. | object({…}) | | null | +| [vpc_connector_config](variables.tf#L195) | VPC connector network configuration. Must be provided if new VPC connector is being created. | object({…}) | | null | ## Outputs diff --git a/modules/cloud-function-v1/main.tf b/modules/cloud-function-v1/main.tf index 8a9af6df6c..7a7fdc9152 100644 --- a/modules/cloud-function-v1/main.tf +++ b/modules/cloud-function-v1/main.tf @@ -41,6 +41,7 @@ locals { ) } + resource "google_vpc_access_connector" "connector" { count = try(var.vpc_connector.create, false) == false ? 0 : 1 project = var.project_id @@ -67,11 +68,13 @@ resource "google_cloudfunctions_function" "function" { labels = var.labels trigger_http = var.trigger_config == null ? true : null https_trigger_security_level = var.https_security_level == null ? "SECURE_ALWAYS" : var.https_security_level - - ingress_settings = var.ingress_settings - build_worker_pool = var.build_worker_pool - - vpc_connector = local.vpc_connector + ingress_settings = var.ingress_settings + build_worker_pool = var.build_worker_pool + build_environment_variables = var.build_environment_variables + kms_key_name = var.kms_key + docker_registry = try(var.repository_settings.registry, "ARTIFACT_REGISTRY") + docker_repository = try(var.repository_settings.repository, null) + vpc_connector = local.vpc_connector vpc_connector_egress_settings = try( var.vpc_connector.egress_settings, null ) diff --git a/modules/cloud-function-v1/variables.tf b/modules/cloud-function-v1/variables.tf index 567a8c7a7d..8dc592addd 100644 --- a/modules/cloud-function-v1/variables.tf +++ b/modules/cloud-function-v1/variables.tf @@ -29,6 +29,12 @@ variable "bucket_name" { nullable = false } +variable "build_environment_variables" { + description = "A set of key/value environment variable pairs available during build time." + type = map(string) + default = {} +} + variable "build_worker_pool" { description = "Build worker pool, in projects//locations//workerPools/ format." type = string @@ -94,6 +100,12 @@ variable "ingress_settings" { default = null } +variable "kms_key" { + description = "Resource name of a KMS crypto key (managed by the user) used to encrypt/decrypt function resources in key id format. If specified, you must also provide an artifact registry repository using the docker_repository field that was created with the same KMS crypto key." + type = string + default = null +} + variable "labels" { description = "Resource labels." type = map(string) @@ -125,6 +137,17 @@ variable "region" { type = string } +variable "repository_settings" { + description = "Docker Registry to use for storing the function's Docker images and specific repository. If kms_key is provided, the repository must have already been encrypted with the key." + type = object({ + registry = optional(string) + repository = optional(string) + }) + default = { + registry = "ARTIFACT_REGISTRY" + } +} + variable "secrets" { description = "Secret Manager secrets. Key is the variable name or mountpoint, volume versions are in version:path format." type = map(object({ diff --git a/modules/cloud-function-v1/versions.tf b/modules/cloud-function-v1/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/cloud-function-v1/versions.tf +++ b/modules/cloud-function-v1/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/cloud-function-v2/README.md b/modules/cloud-function-v2/README.md index a5bad718e0..f54dd50aec 100644 --- a/modules/cloud-function-v2/README.md +++ b/modules/cloud-function-v2/README.md @@ -281,9 +281,9 @@ module "cf-http" { |---|---|:---:|:---:|:---:| | [bucket_name](variables.tf#L26) | Name of the bucket that will be used for the function code. It will be created with prefix prepended if bucket_config is not null. | string | ✓ | | | [bundle_config](variables.tf#L38) | Cloud function source folder and generated zip bundle paths. Output path defaults to '/tmp/bundle.zip' if null. | object({…}) | ✓ | | -| [name](variables.tf#L103) | Name used for cloud function and associated resources. | string | ✓ | | -| [project_id](variables.tf#L118) | Project id used for all resources. | string | ✓ | | -| [region](variables.tf#L123) | Region used for all resources. | string | ✓ | | +| [name](variables.tf#L109) | Name used for cloud function and associated resources. | string | ✓ | | +| [project_id](variables.tf#L124) | Project id used for all resources. | string | ✓ | | +| [region](variables.tf#L129) | Region used for all resources. | string | ✓ | | | [bucket_config](variables.tf#L17) | Enable and configure auto-created bucket. Set fields to null to use defaults. | object({…}) | | null | | [build_worker_pool](variables.tf#L32) | Build worker pool, in projects//locations//workerPools/ format. | string | | null | | [description](variables.tf#L47) | Optional description. | string | | "Terraform managed." | @@ -292,14 +292,15 @@ module "cf-http" { | [function_config](variables.tf#L65) | Cloud function configuration. Defaults to using main as entrypoint, 1 instance with 256MiB of memory, and 180 second timeout. | object({…}) | | {…} | | [iam](variables.tf#L85) | IAM bindings for topic in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | | [ingress_settings](variables.tf#L91) | Control traffic that reaches the cloud function. Allowed values are ALLOW_ALL, ALLOW_INTERNAL_AND_GCLB and ALLOW_INTERNAL_ONLY . | string | | null | -| [labels](variables.tf#L97) | Resource labels. | map(string) | | {} | -| [prefix](variables.tf#L108) | Optional prefix used for resource names. | string | | null | -| [secrets](variables.tf#L128) | Secret Manager secrets. Key is the variable name or mountpoint, volume versions are in version:path format. | map(object({…})) | | {} | -| [service_account](variables.tf#L140) | Service account email. Unused if service account is auto-created. | string | | null | -| [service_account_create](variables.tf#L146) | Auto-create service account. | bool | | false | -| [trigger_config](variables.tf#L152) | Function trigger configuration. Leave null for HTTP trigger. | object({…}) | | null | -| [vpc_connector](variables.tf#L170) | VPC connector configuration. Set create to 'true' if a new connector needs to be created. | object({…}) | | null | -| [vpc_connector_config](variables.tf#L180) | VPC connector network configuration. Must be provided if new VPC connector is being created. | object({…}) | | null | +| [kms_key](variables.tf#L97) | Resource name of a KMS crypto key (managed by the user) used to encrypt/decrypt function resources in key id format. If specified, you must also provide an artifact registry repository using the docker_repository_id field that was created with the same KMS crypto key. | string | | null | +| [labels](variables.tf#L103) | Resource labels. | map(string) | | {} | +| [prefix](variables.tf#L114) | Optional prefix used for resource names. | string | | null | +| [secrets](variables.tf#L134) | Secret Manager secrets. Key is the variable name or mountpoint, volume versions are in version:path format. | map(object({…})) | | {} | +| [service_account](variables.tf#L146) | Service account email. Unused if service account is auto-created. | string | | null | +| [service_account_create](variables.tf#L152) | Auto-create service account. | bool | | false | +| [trigger_config](variables.tf#L158) | Function trigger configuration. Leave null for HTTP trigger. | object({…}) | | null | +| [vpc_connector](variables.tf#L176) | VPC connector configuration. Set create to 'true' if a new connector needs to be created. | object({…}) | | null | +| [vpc_connector_config](variables.tf#L186) | VPC connector network configuration. Must be provided if new VPC connector is being created. | object({…}) | | null | ## Outputs diff --git a/modules/cloud-function-v2/main.tf b/modules/cloud-function-v2/main.tf index c38f863950..24046eada2 100644 --- a/modules/cloud-function-v2/main.tf +++ b/modules/cloud-function-v2/main.tf @@ -59,11 +59,12 @@ resource "google_vpc_access_connector" "connector" { } resource "google_cloudfunctions2_function" "function" { - provider = google-beta - project = var.project_id - location = var.region - name = "${local.prefix}${var.name}" - description = var.description + provider = google-beta + project = var.project_id + location = var.region + name = "${local.prefix}${var.name}" + description = var.description + kms_key_name = var.kms_key build_config { worker_pool = var.build_worker_pool runtime = var.function_config.runtime diff --git a/modules/cloud-function-v2/variables.tf b/modules/cloud-function-v2/variables.tf index af97650fc3..428ba8dba2 100644 --- a/modules/cloud-function-v2/variables.tf +++ b/modules/cloud-function-v2/variables.tf @@ -94,6 +94,12 @@ variable "ingress_settings" { default = null } +variable "kms_key" { + description = "Resource name of a KMS crypto key (managed by the user) used to encrypt/decrypt function resources in key id format. If specified, you must also provide an artifact registry repository using the docker_repository_id field that was created with the same KMS crypto key." + type = string + default = null +} + variable "labels" { description = "Resource labels." type = map(string) diff --git a/modules/cloud-function-v2/versions.tf b/modules/cloud-function-v2/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/cloud-function-v2/versions.tf +++ b/modules/cloud-function-v2/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/cloud-identity-group/versions.tf b/modules/cloud-identity-group/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/cloud-identity-group/versions.tf +++ b/modules/cloud-identity-group/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/cloud-run-v2/versions.tf b/modules/cloud-run-v2/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/cloud-run-v2/versions.tf +++ b/modules/cloud-run-v2/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/cloud-run/versions.tf b/modules/cloud-run/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/cloud-run/versions.tf +++ b/modules/cloud-run/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/cloudsql-instance/README.md b/modules/cloudsql-instance/README.md index c1474cec1a..6ecf42a32d 100644 --- a/modules/cloudsql-instance/README.md +++ b/modules/cloudsql-instance/README.md @@ -1,4 +1,4 @@ -# Cloud SQL instance with read replicas +# Cloud SQL instance module This module manages the creation of Cloud SQL instances with potential read replicas in other regions. It can also create an initial set of users and databases via the `users` and `databases` parameters. @@ -6,7 +6,24 @@ Note that this module assumes that some options are the same for both the primar *Warning:* if you use the `users` field, you terraform state will contain each user's password in plain text. -## Simple example + +- [Examples](#examples) + - [Simple example](#simple-example) + - [Cross-regional read replica](#cross-regional-read-replica) + - [Custom flags, databases and users](#custom-flags-databases-and-users) + - [CMEK encryption](#cmek-encryption) + - [Instance with PSC enabled](#instance-with-psc-enabled) + - [Enable public IP](#enable-public-ip) + - [Query Insights](#query-insights) + - [Maintenance Config](#maintenance-config) + - [SSL Config](#ssl-config) +- [Variables](#variables) +- [Outputs](#outputs) +- [Fixtures](#fixtures) + + +## Examples +### Simple example This example shows how to setup a project, VPC and a standalone Cloud SQL instance. @@ -14,10 +31,12 @@ This example shows how to setup a project, VPC and a standalone Cloud SQL instan module "project" { source = "./fabric/modules/project" billing_account = var.billing_account_id - parent = var.organization_id - name = "my-db-project" + parent = var.folder_id + name = "db-prj" + prefix = var.prefix services = [ - "servicenetworking.googleapis.com" + "servicenetworking.googleapis.com", + "sqladmin.googleapis.com", ] } @@ -25,9 +44,18 @@ module "vpc" { source = "./fabric/modules/net-vpc" project_id = module.project.project_id name = "my-network" + # need only one - psa_config or subnets_psc psa_configs = [{ - ranges = { cloud-sql = "10.60.0.0/16" } + ranges = { cloud-sql = "10.60.0.0/16" } + deletion_policy = "ABANDON" }] + subnets_psc = [ + { + ip_cidr_range = "10.0.3.0/24" + name = "psc" + region = var.region + } + ] } module "db" { @@ -38,17 +66,20 @@ module "db" { psa_config = { private_network = module.vpc.self_link } + # psc_allowed_consumer_projects = [var.project_id] } } - name = "db" - region = "europe-west1" - database_version = "POSTGRES_13" - tier = "db-g1-small" + name = "db" + region = var.region + database_version = "POSTGRES_13" + tier = "db-g1-small" + gcp_deletion_protection = false + terraform_deletion_protection = false } -# tftest modules=3 resources=11 inventory=simple.yaml +# tftest modules=3 resources=14 inventory=simple.yaml e2e ``` -## Cross-regional read replica +### Cross-regional read replica ```hcl module "db" { @@ -61,21 +92,23 @@ module "db" { } } } - prefix = "myprefix" name = "db" - region = "europe-west1" + prefix = "myprefix" + region = var.region database_version = "POSTGRES_13" tier = "db-g1-small" replicas = { - replica1 = { region = "europe-west3", encryption_key_name = null } - replica2 = { region = "us-central1", encryption_key_name = null } + replica1 = { region = "europe-west3" } + replica2 = { region = "us-central1" } } + gcp_deletion_protection = false + terraform_deletion_protection = false } -# tftest modules=1 resources=3 inventory=replicas.yaml +# tftest modules=1 resources=3 inventory=replicas.yaml e2e ``` -## Custom flags, databases and users +### Custom flags, databases and users ```hcl module "db" { @@ -89,7 +122,7 @@ module "db" { } } name = "db" - region = "europe-west1" + region = var.region database_version = "MYSQL_8_0" tier = "db-g1-small" @@ -112,47 +145,19 @@ module "db" { password = "mypassword" } } + gcp_deletion_protection = false + terraform_deletion_protection = false } -# tftest modules=1 resources=6 inventory=custom.yaml +# tftest modules=1 resources=6 inventory=custom.yaml e2e ``` ### CMEK encryption ```hcl - -module "project" { - source = "./fabric/modules/project" - billing_account = var.billing_account_id - parent = var.organization_id - name = "my-db-project" - services = [ - "servicenetworking.googleapis.com", - "sqladmin.googleapis.com", - ] -} - -module "kms" { - source = "./fabric/modules/kms" - project_id = module.project.project_id - keyring = { - name = "keyring" - location = var.region - } - keys = { - key-sql = { - iam = { - "roles/cloudkms.cryptoKeyEncrypterDecrypter" = [ - "serviceAccount:${module.project.service_accounts.robots.sqladmin}" - ] - } - } - } -} - module "db" { source = "./fabric/modules/cloudsql-instance" - project_id = module.project.project_id - encryption_key_name = module.kms.keys["key-sql"].id + project_id = var.project_id + encryption_key_name = var.kms_key.id network_config = { connectivity = { psa_config = { @@ -160,13 +165,15 @@ module "db" { } } } - name = "db" - region = var.region - database_version = "POSTGRES_13" - tier = "db-g1-small" + name = "db" + region = var.region + database_version = "POSTGRES_13" + tier = "db-g1-small" + gcp_deletion_protection = false + terraform_deletion_protection = false } -# tftest modules=3 resources=10 +# tftest modules=1 resources=2 fixtures=fixtures/cloudsql-kms-iam-grant.tf e2e ``` ### Instance with PSC enabled @@ -177,22 +184,25 @@ module "db" { project_id = var.project_id network_config = { connectivity = { - psc_allowed_consumer_projects = ["my-project-id"] + psc_allowed_consumer_projects = [var.project_id] } } prefix = "myprefix" name = "db" - region = "europe-west1" + region = var.region availability_type = "REGIONAL" database_version = "POSTGRES_13" tier = "db-g1-small" + + gcp_deletion_protection = false + terraform_deletion_protection = false } -# tftest modules=1 resources=1 +# tftest modules=1 resources=1 inventory=psc.yaml e2e ``` ### Enable public IP -Use `ipv_enabled` to create instances with a public IP. +Use `public_ipv4` to create instances with a public IP. ```hcl module "db" { @@ -206,15 +216,14 @@ module "db" { } } } - name = "db" - region = "europe-west1" - tier = "db-g1-small" - database_version = "MYSQL_8_0" - replicas = { - replica1 = { region = "europe-west3", encryption_key_name = null } - } + name = "db" + region = var.region + tier = "db-g1-small" + database_version = "MYSQL_8_0" + gcp_deletion_protection = false + terraform_deletion_protection = false } -# tftest modules=1 resources=2 inventory=public-ip.yaml +# tftest modules=1 resources=1 inventory=public-ip.yaml e2e ``` ### Query Insights @@ -233,15 +242,17 @@ module "db" { } } name = "db" - region = "europe-west1" + region = var.region database_version = "POSTGRES_13" tier = "db-g1-small" insights_config = { query_string_length = 2048 } + gcp_deletion_protection = false + terraform_deletion_protection = false } -# tftest modules=1 resources=1 inventory=insights.yaml +# tftest modules=1 resources=1 inventory=insights.yaml e2e ``` ### Maintenance Config @@ -260,13 +271,15 @@ module "db" { } } name = "db" - region = "europe-west1" + region = var.region database_version = "POSTGRES_13" tier = "db-g1-small" - maintenance_config = {} + maintenance_config = {} + gcp_deletion_protection = false + terraform_deletion_protection = false } -# tftest modules=1 resources=1 +# tftest modules=1 resources=1 e2e ``` ### SSL Config @@ -285,13 +298,15 @@ module "db" { } } name = "db" - region = "europe-west1" + region = var.region database_version = "POSTGRES_13" tier = "db-g1-small" - ssl = {} + ssl = {} + gcp_deletion_protection = false + terraform_deletion_protection = false } -# tftest modules=1 resources=1 +# tftest modules=1 resources=1 e2e ``` ## Variables @@ -322,7 +337,7 @@ module "db" { | [labels](variables.tf#L140) | Labels to be attached to all instances. | map(string) | | null | | [maintenance_config](variables.tf#L146) | Set maintenance window configuration and maintenance deny period (up to 90 days). Date format: 'yyyy-mm-dd'. | object({…}) | | {} | | [prefix](variables.tf#L207) | Optional prefix used to generate instance names. | string | | null | -| [replicas](variables.tf#L227) | Map of NAME=> {REGION, KMS_KEY} for additional read replicas. Set to null to disable replica creation. | map(object({…})) | | {} | +| [replicas](variables.tf#L227) | Map of NAME=> {REGION, KMS_KEY} for additional read replicas. Set to null to disable replica creation. | map(object({…})) | | {} | | [root_password](variables.tf#L236) | Root password of the Cloud SQL instance. Required for MS SQL Server. | string | | null | | [ssl](variables.tf#L242) | Setting to enable SSL, set config and certificates. | object({…}) | | {} | | [terraform_deletion_protection](variables.tf#L258) | Prevent terraform from deleting instances. | bool | | true | @@ -350,4 +365,8 @@ module "db" { | [self_link](outputs.tf#L114) | Self link of the primary instance. | | | [self_links](outputs.tf#L119) | Self links of all instances. | | | [user_passwords](outputs.tf#L127) | Map of containing the password of all users created through terraform. | ✓ | + +## Fixtures + +- [cloudsql-kms-iam-grant.tf](../../tests/fixtures/cloudsql-kms-iam-grant.tf) diff --git a/modules/cloudsql-instance/variables.tf b/modules/cloudsql-instance/variables.tf index e67dd3979a..613e106e74 100644 --- a/modules/cloudsql-instance/variables.tf +++ b/modules/cloudsql-instance/variables.tf @@ -228,7 +228,7 @@ variable "replicas" { description = "Map of NAME=> {REGION, KMS_KEY} for additional read replicas. Set to null to disable replica creation." type = map(object({ region = string - encryption_key_name = string + encryption_key_name = optional(string) })) default = {} } diff --git a/modules/cloudsql-instance/versions.tf b/modules/cloudsql-instance/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/cloudsql-instance/versions.tf +++ b/modules/cloudsql-instance/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/compute-mig/versions.tf b/modules/compute-mig/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/compute-mig/versions.tf +++ b/modules/compute-mig/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/compute-vm/versions.tf b/modules/compute-vm/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/compute-vm/versions.tf +++ b/modules/compute-vm/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/container-registry/versions.tf b/modules/container-registry/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/container-registry/versions.tf +++ b/modules/container-registry/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/data-catalog-policy-tag/versions.tf b/modules/data-catalog-policy-tag/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/data-catalog-policy-tag/versions.tf +++ b/modules/data-catalog-policy-tag/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/data-catalog-tag-template/versions.tf b/modules/data-catalog-tag-template/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/data-catalog-tag-template/versions.tf +++ b/modules/data-catalog-tag-template/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/data-catalog-tag/versions.tf b/modules/data-catalog-tag/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/data-catalog-tag/versions.tf +++ b/modules/data-catalog-tag/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/dataform-repository/versions.tf b/modules/dataform-repository/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/dataform-repository/versions.tf +++ b/modules/dataform-repository/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/datafusion/versions.tf b/modules/datafusion/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/datafusion/versions.tf +++ b/modules/datafusion/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/dataplex-datascan/versions.tf b/modules/dataplex-datascan/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/dataplex-datascan/versions.tf +++ b/modules/dataplex-datascan/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/dataplex/versions.tf b/modules/dataplex/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/dataplex/versions.tf +++ b/modules/dataplex/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/dataproc/versions.tf b/modules/dataproc/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/dataproc/versions.tf +++ b/modules/dataproc/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/dns-response-policy/versions.tf b/modules/dns-response-policy/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/dns-response-policy/versions.tf +++ b/modules/dns-response-policy/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/dns/versions.tf b/modules/dns/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/dns/versions.tf +++ b/modules/dns/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/endpoints/versions.tf b/modules/endpoints/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/endpoints/versions.tf +++ b/modules/endpoints/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/folder/README.md b/modules/folder/README.md index 2efb626b97..ff242aeec0 100644 --- a/modules/folder/README.md +++ b/modules/folder/README.md @@ -345,12 +345,13 @@ module "folder" { | name | description | resources | |---|---|---| | [iam.tf](./iam.tf) | IAM bindings. | google_folder_iam_binding · google_folder_iam_member | -| [logging.tf](./logging.tf) | Log sinks and supporting resources. | google_bigquery_dataset_iam_member · google_folder_iam_audit_config · google_logging_folder_exclusion · google_logging_folder_sink · google_project_iam_member · google_pubsub_topic_iam_member · google_storage_bucket_iam_member | +| [logging.tf](./logging.tf) | Log sinks and supporting resources. | google_bigquery_dataset_iam_member · google_folder_iam_audit_config · google_logging_folder_exclusion · google_logging_folder_settings · google_logging_folder_sink · google_project_iam_member · google_pubsub_topic_iam_member · google_storage_bucket_iam_member | | [main.tf](./main.tf) | Module-level locals and resources. | google_compute_firewall_policy_association · google_essential_contacts_contact · google_folder | | [organization-policies.tf](./organization-policies.tf) | Folder-level organization policies. | google_org_policy_policy | | [outputs.tf](./outputs.tf) | Module outputs. | | | [tags.tf](./tags.tf) | None | google_tags_tag_binding | | [variables-iam.tf](./variables-iam.tf) | None | | +| [variables-logging.tf](./variables-logging.tf) | None | | | [variables.tf](./variables.tf) | Module variables. | | | [versions.tf](./versions.tf) | Version pins. | | @@ -367,13 +368,14 @@ module "folder" { | [iam_bindings_additive](variables-iam.tf#L39) | Individual additive IAM bindings. Keys are arbitrary. | map(object({…})) | | {} | | [iam_by_principals](variables-iam.tf#L54) | 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)) | | {} | | [id](variables.tf#L48) | Folder ID in case you use folder_create=false. | string | | null | -| [logging_data_access](variables.tf#L54) | Control activation of data access logs. Format is service => { log type => [exempted members]}. The special 'allServices' key denotes configuration for all services. | map(map(list(string))) | | {} | -| [logging_exclusions](variables.tf#L69) | Logging exclusions for this folder in the form {NAME -> FILTER}. | map(string) | | {} | -| [logging_sinks](variables.tf#L76) | Logging sinks to create for the folder. | map(object({…})) | | {} | -| [name](variables.tf#L107) | Folder name. | string | | null | -| [org_policies](variables.tf#L113) | Organization policies applied to this folder keyed by policy name. | map(object({…})) | | {} | -| [parent](variables.tf#L140) | Parent in folders/folder_id or organizations/org_id format. | string | | null | -| [tag_bindings](variables.tf#L150) | Tag bindings for this folder, in key => tag value id format. | map(string) | | null | +| [logging_data_access](variables-logging.tf#L17) | Control activation of data access logs. Format is service => { log type => [exempted members]}. The special 'allServices' key denotes configuration for all services. | map(map(list(string))) | | {} | +| [logging_exclusions](variables-logging.tf#L32) | Logging exclusions for this folder in the form {NAME -> FILTER}. | map(string) | | {} | +| [logging_settings](variables-logging.tf#L39) | Default settings for logging resources. | object({…}) | | null | +| [logging_sinks](variables-logging.tf#L49) | Logging sinks to create for the folder. | map(object({…})) | | {} | +| [name](variables.tf#L54) | Folder name. | string | | null | +| [org_policies](variables.tf#L60) | Organization policies applied to this folder keyed by policy name. | map(object({…})) | | {} | +| [parent](variables.tf#L87) | Parent in folders/folder_id or organizations/org_id format. | string | | null | +| [tag_bindings](variables.tf#L97) | Tag bindings for this folder, in key => tag value id format. | map(string) | | null | ## Outputs diff --git a/modules/folder/iam.tf b/modules/folder/iam.tf index ba852837cb..68d3e606b0 100644 --- a/modules/folder/iam.tf +++ b/modules/folder/iam.tf @@ -35,14 +35,14 @@ locals { resource "google_folder_iam_binding" "authoritative" { for_each = local.iam - folder = local.folder.name + folder = local.folder_id role = each.key members = each.value } resource "google_folder_iam_binding" "bindings" { for_each = var.iam_bindings - folder = local.folder.name + folder = local.folder_id role = each.value.role members = each.value.members dynamic "condition" { @@ -57,7 +57,7 @@ resource "google_folder_iam_binding" "bindings" { resource "google_folder_iam_member" "bindings" { for_each = var.iam_bindings_additive - folder = local.folder.name + folder = local.folder_id role = each.value.role member = each.value.member dynamic "condition" { diff --git a/modules/folder/logging.tf b/modules/folder/logging.tf index f6942baa4b..bb42983c22 100644 --- a/modules/folder/logging.tf +++ b/modules/folder/logging.tf @@ -35,9 +35,16 @@ locals { } } +resource "google_logging_folder_settings" "default" { + count = var.logging_settings != null ? 1 : 0 + folder = local.folder_id + disable_default_sink = var.logging_settings.disable_default_sink + storage_location = var.logging_settings.storage_location +} + resource "google_folder_iam_audit_config" "default" { for_each = var.logging_data_access - folder = local.folder.name + folder = local.folder_id service = each.key dynamic "audit_log_config" { for_each = each.value @@ -53,7 +60,7 @@ resource "google_logging_folder_sink" "sink" { for_each = local.logging_sinks name = each.key description = coalesce(each.value.description, "${each.key} (Terraform-managed).") - folder = local.folder.name + folder = local.folder_id destination = "${each.value.type}.googleapis.com/${each.value.destination}" filter = each.value.filter include_children = each.value.include_children @@ -108,10 +115,9 @@ resource "google_project_iam_member" "bucket-sinks-binding" { project = split("/", each.value.destination)[1] role = "roles/logging.bucketWriter" member = google_logging_folder_sink.sink[each.key].writer_identity - condition { title = "${each.key} bucket writer" - description = "Grants bucketWriter to ${google_logging_folder_sink.sink[each.key].writer_identity} used by log sink ${each.key} on ${local.folder.id}" + description = "Grants bucketWriter to ${google_logging_folder_sink.sink[each.key].writer_identity} used by log sink ${each.key} on ${local.folder_id}" expression = "resource.name.endsWith('${each.value.destination}')" } } @@ -126,7 +132,7 @@ resource "google_project_iam_member" "project-sinks-binding" { resource "google_logging_folder_exclusion" "logging-exclusion" { for_each = var.logging_exclusions name = each.key - folder = local.folder.name + folder = local.folder_id description = "${each.key} (Terraform-managed)." filter = each.value } diff --git a/modules/folder/main.tf b/modules/folder/main.tf index 4335dbe515..8bb46a533c 100644 --- a/modules/folder/main.tf +++ b/modules/folder/main.tf @@ -15,18 +15,13 @@ */ locals { - folder = ( + folder_id = ( var.folder_create - ? try(google_folder.folder[0], null) - : try(data.google_folder.folder[0], null) + ? try(google_folder.folder[0].id, null) + : var.id ) } -data "google_folder" "folder" { - count = var.folder_create ? 0 : 1 - folder = var.id -} - resource "google_folder" "folder" { count = var.folder_create ? 1 : 0 display_name = var.name @@ -36,7 +31,7 @@ resource "google_folder" "folder" { resource "google_essential_contacts_contact" "contact" { provider = google-beta for_each = var.contacts - parent = local.folder.name + parent = local.folder_id email = each.key language_tag = "en" notification_category_subscriptions = each.value @@ -49,7 +44,7 @@ resource "google_essential_contacts_contact" "contact" { resource "google_compute_firewall_policy_association" "default" { count = var.firewall_policy == null ? 0 : 1 - attachment_target = local.folder.id + attachment_target = local.folder_id name = var.firewall_policy.name firewall_policy = var.firewall_policy.policy } diff --git a/modules/folder/organization-policies.tf b/modules/folder/organization-policies.tf index 38b69871c9..6de3081ce8 100644 --- a/modules/folder/organization-policies.tf +++ b/modules/folder/organization-policies.tf @@ -52,8 +52,8 @@ locals { org_policies = { for k, v in local._org_policies : k => merge(v, { - name = "${local.folder.name}/policies/${k}" - parent = local.folder.name + name = "${local.folder_id}/policies/${k}" + parent = local.folder_id is_boolean_policy = ( alltrue([for r in v.rules : r.allow == null && r.deny == null]) ) diff --git a/modules/folder/outputs.tf b/modules/folder/outputs.tf index aec28f7152..79ff37cb7d 100644 --- a/modules/folder/outputs.tf +++ b/modules/folder/outputs.tf @@ -16,12 +16,12 @@ output "folder" { description = "Folder resource." - value = local.folder + value = try(google_folder.folder[0], null) } output "id" { description = "Fully qualified folder id." - value = local.folder.name + value = local.folder_id depends_on = [ google_folder_iam_binding.authoritative, google_folder_iam_binding.bindings, @@ -32,7 +32,7 @@ output "id" { output "name" { description = "Folder name." - value = local.folder.display_name + value = try(google_folder.folder[0].display_name, null) } output "sink_writer_identities" { diff --git a/modules/folder/tags.tf b/modules/folder/tags.tf index 2cd2f2fd1a..323886ef50 100644 --- a/modules/folder/tags.tf +++ b/modules/folder/tags.tf @@ -16,6 +16,6 @@ resource "google_tags_tag_binding" "binding" { for_each = coalesce(var.tag_bindings, {}) - parent = "//cloudresourcemanager.googleapis.com/${local.folder.id}" + parent = "//cloudresourcemanager.googleapis.com/${local.folder_id}" tag_value = each.value } diff --git a/modules/folder/variables-logging.tf b/modules/folder/variables-logging.tf new file mode 100644 index 0000000000..89685a6de9 --- /dev/null +++ b/modules/folder/variables-logging.tf @@ -0,0 +1,78 @@ +/** + * 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 "logging_data_access" { + description = "Control activation of data access logs. Format is service => { log type => [exempted members]}. The special 'allServices' key denotes configuration for all services." + type = map(map(list(string))) + nullable = false + default = {} + validation { + condition = alltrue(flatten([ + for k, v in var.logging_data_access : [ + for kk, vv in v : contains(["DATA_READ", "DATA_WRITE", "ADMIN_READ"], kk) + ] + ])) + error_message = "Log type keys for each service can only be one of 'DATA_READ', 'DATA_WRITE', 'ADMIN_READ'." + } +} + +variable "logging_exclusions" { + description = "Logging exclusions for this folder in the form {NAME -> FILTER}." + type = map(string) + default = {} + nullable = false +} + +variable "logging_settings" { + description = "Default settings for logging resources." + type = object({ + # TODO: add support for CMEK + disable_default_sink = optional(bool) + storage_location = optional(string) + }) + default = null +} + +variable "logging_sinks" { + description = "Logging sinks to create for the folder." + type = map(object({ + bq_partitioned_table = optional(bool, false) + description = optional(string) + destination = string + disabled = optional(bool, false) + exclusions = optional(map(string), {}) + filter = optional(string) + iam = optional(bool, true) + include_children = optional(bool, true) + type = string + })) + default = {} + nullable = false + validation { + condition = alltrue([ + for k, v in var.logging_sinks : + contains(["bigquery", "logging", "project", "pubsub", "storage"], v.type) + ]) + error_message = "Type must be one of 'bigquery', 'logging', 'project', 'pubsub', 'storage'." + } + validation { + condition = alltrue([ + for k, v in var.logging_sinks : + v.bq_partitioned_table != true || v.type == "bigquery" + ]) + error_message = "Can only set bq_partitioned_table when type is `bigquery`." + } +} diff --git a/modules/folder/variables.tf b/modules/folder/variables.tf index 6da2685a71..e5f6d548be 100644 --- a/modules/folder/variables.tf +++ b/modules/folder/variables.tf @@ -51,59 +51,6 @@ variable "id" { default = null } -variable "logging_data_access" { - description = "Control activation of data access logs. Format is service => { log type => [exempted members]}. The special 'allServices' key denotes configuration for all services." - type = map(map(list(string))) - nullable = false - default = {} - validation { - condition = alltrue(flatten([ - for k, v in var.logging_data_access : [ - for kk, vv in v : contains(["DATA_READ", "DATA_WRITE", "ADMIN_READ"], kk) - ] - ])) - error_message = "Log type keys for each service can only be one of 'DATA_READ', 'DATA_WRITE', 'ADMIN_READ'." - } -} - -variable "logging_exclusions" { - description = "Logging exclusions for this folder in the form {NAME -> FILTER}." - type = map(string) - default = {} - nullable = false -} - -variable "logging_sinks" { - description = "Logging sinks to create for the folder." - type = map(object({ - bq_partitioned_table = optional(bool, false) - description = optional(string) - destination = string - disabled = optional(bool, false) - exclusions = optional(map(string), {}) - filter = optional(string) - iam = optional(bool, true) - include_children = optional(bool, true) - type = string - })) - default = {} - nullable = false - validation { - condition = alltrue([ - for k, v in var.logging_sinks : - contains(["bigquery", "logging", "project", "pubsub", "storage"], v.type) - ]) - error_message = "Type must be one of 'bigquery', 'logging', 'project', 'pubsub', 'storage'." - } - validation { - condition = alltrue([ - for k, v in var.logging_sinks : - v.bq_partitioned_table != true || v.type == "bigquery" - ]) - error_message = "Can only set bq_partitioned_table when type is `bigquery`." - } -} - variable "name" { description = "Folder name." type = string diff --git a/modules/folder/versions.tf b/modules/folder/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/folder/versions.tf +++ b/modules/folder/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/gcs/versions.tf b/modules/gcs/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/gcs/versions.tf +++ b/modules/gcs/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/gcve-private-cloud/versions.tf b/modules/gcve-private-cloud/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/gcve-private-cloud/versions.tf +++ b/modules/gcve-private-cloud/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/gke-cluster-autopilot/README.md b/modules/gke-cluster-autopilot/README.md index bf8affbe51..0091d6e04d 100644 --- a/modules/gke-cluster-autopilot/README.md +++ b/modules/gke-cluster-autopilot/README.md @@ -206,25 +206,25 @@ module "cluster-1" { | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [location](variables.tf#L112) | Autopilot clusters are always regional. | string | ✓ | | -| [name](variables.tf#L189) | Cluster name. | string | ✓ | | -| [project_id](variables.tf#L225) | Cluster project ID. | string | ✓ | | -| [vpc_config](variables.tf#L241) | VPC-level configuration. | object({…}) | ✓ | | -| [backup_configs](variables.tf#L17) | Configuration for Backup for GKE. | object({…}) | | {} | -| [deletion_protection](variables.tf#L37) | Whether or not to allow Terraform to destroy the cluster. Unless this field is set to false in Terraform state, a terraform destroy or terraform apply that would delete the cluster will fail. | bool | | true | -| [description](variables.tf#L44) | Cluster description. | string | | null | -| [enable_addons](variables.tf#L50) | Addons enabled in the cluster (true means enabled). | object({…}) | | {} | -| [enable_features](variables.tf#L64) | Enable cluster-level features. Certain features allow configuration. | object({…}) | | {} | -| [issue_client_certificate](variables.tf#L100) | Enable issuing client certificate. | bool | | false | -| [labels](variables.tf#L106) | Cluster resource labels. | map(string) | | null | -| [logging_config](variables.tf#L117) | Logging configuration. | object({…}) | | {} | -| [maintenance_config](variables.tf#L128) | Maintenance window configuration. | object({…}) | | {…} | -| [min_master_version](variables.tf#L151) | Minimum version of the master, defaults to the version of the most recent official release. | string | | null | -| [monitoring_config](variables.tf#L157) | Monitoring configuration. System metrics collection cannot be disabled. Control plane metrics are optional. Kube state metrics are optional. Google Cloud Managed Service for Prometheus is enabled by default. | object({…}) | | {} | -| [node_config](variables.tf#L194) | Configuration for nodes and nodepools. | object({…}) | | {} | -| [node_locations](variables.tf#L204) | Zones in which the cluster's nodes are located. | list(string) | | [] | -| [private_cluster_config](variables.tf#L211) | Private cluster configuration. | object({…}) | | null | -| [release_channel](variables.tf#L230) | Release channel for GKE upgrades. Clusters created in the Autopilot mode must use a release channel. Choose between \"RAPID\", \"REGULAR\", and \"STABLE\". | string | | "REGULAR" | +| [location](variables.tf#L113) | Autopilot clusters are always regional. | string | ✓ | | +| [name](variables.tf#L190) | Cluster name. | string | ✓ | | +| [project_id](variables.tf#L226) | Cluster project ID. | string | ✓ | | +| [vpc_config](variables.tf#L242) | VPC-level configuration. | object({…}) | ✓ | | +| [backup_configs](variables.tf#L17) | Configuration for Backup for GKE. | object({…}) | | {} | +| [deletion_protection](variables.tf#L38) | Whether or not to allow Terraform to destroy the cluster. Unless this field is set to false in Terraform state, a terraform destroy or terraform apply that would delete the cluster will fail. | bool | | true | +| [description](variables.tf#L45) | Cluster description. | string | | null | +| [enable_addons](variables.tf#L51) | Addons enabled in the cluster (true means enabled). | object({…}) | | {} | +| [enable_features](variables.tf#L65) | Enable cluster-level features. Certain features allow configuration. | object({…}) | | {} | +| [issue_client_certificate](variables.tf#L101) | Enable issuing client certificate. | bool | | false | +| [labels](variables.tf#L107) | Cluster resource labels. | map(string) | | null | +| [logging_config](variables.tf#L118) | Logging configuration. | object({…}) | | {} | +| [maintenance_config](variables.tf#L129) | Maintenance window configuration. | object({…}) | | {…} | +| [min_master_version](variables.tf#L152) | Minimum version of the master, defaults to the version of the most recent official release. | string | | null | +| [monitoring_config](variables.tf#L158) | Monitoring configuration. System metrics collection cannot be disabled. Control plane metrics are optional. Kube state metrics are optional. Google Cloud Managed Service for Prometheus is enabled by default. | object({…}) | | {} | +| [node_config](variables.tf#L195) | Configuration for nodes and nodepools. | object({…}) | | {} | +| [node_locations](variables.tf#L205) | Zones in which the cluster's nodes are located. | list(string) | | [] | +| [private_cluster_config](variables.tf#L212) | Private cluster configuration. | object({…}) | | null | +| [release_channel](variables.tf#L231) | Release channel for GKE upgrades. Clusters created in the Autopilot mode must use a release channel. Choose between \"RAPID\", \"REGULAR\", and \"STABLE\". | string | | "REGULAR" | ## Outputs diff --git a/modules/gke-cluster-autopilot/main.tf b/modules/gke-cluster-autopilot/main.tf index 825c8739e5..6824d22309 100644 --- a/modules/gke-cluster-autopilot/main.tf +++ b/modules/gke-cluster-autopilot/main.tf @@ -322,6 +322,7 @@ resource "google_gke_backup_backup_plan" "backup_plan" { cluster = google_container_cluster.cluster.id location = each.value.region project = var.project_id + labels = each.value.labels retention_policy { backup_delete_lock_days = try(each.value.retention_policy_delete_lock_days) backup_retain_days = try(each.value.retention_policy_days) diff --git a/modules/gke-cluster-autopilot/variables.tf b/modules/gke-cluster-autopilot/variables.tf index 570899274e..a31596a6e6 100644 --- a/modules/gke-cluster-autopilot/variables.tf +++ b/modules/gke-cluster-autopilot/variables.tf @@ -22,6 +22,7 @@ variable "backup_configs" { encryption_key = optional(string) include_secrets = optional(bool, true) include_volume_data = optional(bool, true) + labels = optional(map(string)) namespaces = optional(list(string)) region = string schedule = string diff --git a/modules/gke-cluster-autopilot/versions.tf b/modules/gke-cluster-autopilot/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/gke-cluster-autopilot/versions.tf +++ b/modules/gke-cluster-autopilot/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/gke-cluster-standard/README.md b/modules/gke-cluster-standard/README.md index 286b20a3dc..dd8ad0f444 100644 --- a/modules/gke-cluster-standard/README.md +++ b/modules/gke-cluster-standard/README.md @@ -310,28 +310,28 @@ module "cluster-1" { | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [location](variables.tf#L233) | Cluster zone or region. | string | ✓ | | -| [name](variables.tf#L368) | Cluster name. | string | ✓ | | -| [project_id](variables.tf#L404) | Cluster project id. | string | ✓ | | -| [vpc_config](variables.tf#L415) | VPC-level configuration. | object({…}) | ✓ | | -| [backup_configs](variables.tf#L17) | Configuration for Backup for GKE. | object({…}) | | {} | -| [cluster_autoscaling](variables.tf#L38) | Enable and configure limits for Node Auto-Provisioning with Cluster Autoscaler. | object({…}) | | null | -| [default_nodepool](variables.tf#L116) | Enable default nodepool. | object({…}) | | {} | -| [deletion_protection](variables.tf#L134) | Whether or not to allow Terraform to destroy the cluster. Unless this field is set to false in Terraform state, a terraform destroy or terraform apply that would delete the cluster will fail. | bool | | true | -| [description](variables.tf#L141) | Cluster description. | string | | null | -| [enable_addons](variables.tf#L147) | Addons enabled in the cluster (true means enabled). | object({…}) | | {…} | -| [enable_features](variables.tf#L171) | Enable cluster-level features. Certain features allow configuration. | object({…}) | | {…} | -| [issue_client_certificate](variables.tf#L221) | Enable issuing client certificate. | bool | | false | -| [labels](variables.tf#L227) | Cluster resource labels. | map(string) | | null | -| [logging_config](variables.tf#L238) | Logging configuration. | object({…}) | | {} | -| [maintenance_config](variables.tf#L259) | Maintenance window configuration. | object({…}) | | {…} | -| [max_pods_per_node](variables.tf#L282) | Maximum number of pods per node in this cluster. | number | | 110 | -| [min_master_version](variables.tf#L288) | Minimum version of the master, defaults to the version of the most recent official release. | string | | null | -| [monitoring_config](variables.tf#L294) | Monitoring configuration. Google Cloud Managed Service for Prometheus is enabled by default. | object({…}) | | {} | -| [node_config](variables.tf#L373) | Node-level configuration. | object({…}) | | {} | -| [node_locations](variables.tf#L383) | Zones in which the cluster's nodes are located. | list(string) | | [] | -| [private_cluster_config](variables.tf#L390) | Private cluster configuration. | object({…}) | | null | -| [release_channel](variables.tf#L409) | Release channel for GKE upgrades. | string | | null | +| [location](variables.tf#L235) | Cluster zone or region. | string | ✓ | | +| [name](variables.tf#L370) | Cluster name. | string | ✓ | | +| [project_id](variables.tf#L406) | Cluster project id. | string | ✓ | | +| [vpc_config](variables.tf#L417) | VPC-level configuration. | object({…}) | ✓ | | +| [backup_configs](variables.tf#L17) | Configuration for Backup for GKE. | object({…}) | | {} | +| [cluster_autoscaling](variables.tf#L39) | Enable and configure limits for Node Auto-Provisioning with Cluster Autoscaler. | object({…}) | | null | +| [default_nodepool](variables.tf#L118) | Enable default nodepool. | object({…}) | | {} | +| [deletion_protection](variables.tf#L136) | Whether or not to allow Terraform to destroy the cluster. Unless this field is set to false in Terraform state, a terraform destroy or terraform apply that would delete the cluster will fail. | bool | | true | +| [description](variables.tf#L143) | Cluster description. | string | | null | +| [enable_addons](variables.tf#L149) | Addons enabled in the cluster (true means enabled). | object({…}) | | {…} | +| [enable_features](variables.tf#L173) | Enable cluster-level features. Certain features allow configuration. | object({…}) | | {…} | +| [issue_client_certificate](variables.tf#L223) | Enable issuing client certificate. | bool | | false | +| [labels](variables.tf#L229) | Cluster resource labels. | map(string) | | null | +| [logging_config](variables.tf#L240) | Logging configuration. | object({…}) | | {} | +| [maintenance_config](variables.tf#L261) | Maintenance window configuration. | object({…}) | | {…} | +| [max_pods_per_node](variables.tf#L284) | Maximum number of pods per node in this cluster. | number | | 110 | +| [min_master_version](variables.tf#L290) | Minimum version of the master, defaults to the version of the most recent official release. | string | | null | +| [monitoring_config](variables.tf#L296) | Monitoring configuration. Google Cloud Managed Service for Prometheus is enabled by default. | object({…}) | | {} | +| [node_config](variables.tf#L375) | Node-level configuration. | object({…}) | | {} | +| [node_locations](variables.tf#L385) | Zones in which the cluster's nodes are located. | list(string) | | [] | +| [private_cluster_config](variables.tf#L392) | Private cluster configuration. | object({…}) | | null | +| [release_channel](variables.tf#L411) | Release channel for GKE upgrades. | string | | null | ## Outputs diff --git a/modules/gke-cluster-standard/main.tf b/modules/gke-cluster-standard/main.tf index 6ab4c9d881..bc743fc5ce 100644 --- a/modules/gke-cluster-standard/main.tf +++ b/modules/gke-cluster-standard/main.tf @@ -132,7 +132,7 @@ resource "google_container_cluster" "cluster" { dynamic "cluster_autoscaling" { for_each = local.cas == null ? [] : [""] content { - enabled = true + enabled = var.cluster_autoscaling.enabled autoscaling_profile = var.cluster_autoscaling.autoscaling_profile dynamic "auto_provisioning_defaults" { for_each = local.cas_apd != null ? [""] : [] @@ -511,6 +511,7 @@ resource "google_gke_backup_backup_plan" "backup_plan" { cluster = google_container_cluster.cluster.id location = each.value.region project = var.project_id + labels = each.value.labels retention_policy { backup_delete_lock_days = try(each.value.retention_policy_delete_lock_days) backup_retain_days = try(each.value.retention_policy_days) diff --git a/modules/gke-cluster-standard/variables.tf b/modules/gke-cluster-standard/variables.tf index 6644595494..2436b467cd 100644 --- a/modules/gke-cluster-standard/variables.tf +++ b/modules/gke-cluster-standard/variables.tf @@ -24,6 +24,7 @@ variable "backup_configs" { encryption_key = optional(string) include_secrets = optional(bool, true) include_volume_data = optional(bool, true) + labels = optional(map(string)) namespaces = optional(list(string)) schedule = optional(string) retention_policy_days = optional(number) @@ -38,6 +39,7 @@ variable "backup_configs" { variable "cluster_autoscaling" { description = "Enable and configure limits for Node Auto-Provisioning with Cluster Autoscaler." type = object({ + enabled = optional(bool, true) autoscaling_profile = optional(string, "BALANCED") auto_provisioning_defaults = optional(object({ boot_disk_kms_key = optional(string) diff --git a/modules/gke-cluster-standard/versions.tf b/modules/gke-cluster-standard/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/gke-cluster-standard/versions.tf +++ b/modules/gke-cluster-standard/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/gke-hub/versions.tf b/modules/gke-hub/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/gke-hub/versions.tf +++ b/modules/gke-hub/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/gke-nodepool/versions.tf b/modules/gke-nodepool/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/gke-nodepool/versions.tf +++ b/modules/gke-nodepool/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/iam-service-account/versions.tf b/modules/iam-service-account/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/iam-service-account/versions.tf +++ b/modules/iam-service-account/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/kms/README.md b/modules/kms/README.md index 4782d8240d..90621bef37 100644 --- a/modules/kms/README.md +++ b/modules/kms/README.md @@ -120,14 +120,14 @@ module "kms" { | name | description | type | required | default | |---|---|:---:|:---:|:---:| | [keyring](variables.tf#L64) | Keyring attributes. | object({…}) | ✓ | | -| [project_id](variables.tf#L115) | Project id where the keyring will be created. | string | ✓ | | +| [project_id](variables.tf#L114) | Project id where the keyring will be created. | string | ✓ | | | [iam](variables.tf#L17) | Keyring IAM bindings in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | | [iam_bindings](variables.tf#L24) | Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary. | map(object({…})) | | {} | | [iam_bindings_additive](variables.tf#L39) | Keyring individual additive IAM bindings. Keys are arbitrary. | map(object({…})) | | {} | | [import_job](variables.tf#L54) | Keyring import job attributes. | object({…}) | | null | | [keyring_create](variables.tf#L72) | Set to false to manage keys and IAM bindings in an existing keyring. | bool | | true | -| [keys](variables.tf#L78) | Key names and base attributes. Set attributes to null if not needed. | map(object({…})) | | {} | -| [tag_bindings](variables.tf#L120) | Tag bindings for this keyring, in key => tag value id format. | map(string) | | {} | +| [keys](variables.tf#L78) | Key names and base attributes. Set attributes to null if not needed. | map(object({…})) | | {} | +| [tag_bindings](variables.tf#L119) | Tag bindings for this keyring, in key => tag value id format. | map(string) | | {} | ## Outputs diff --git a/modules/kms/variables.tf b/modules/kms/variables.tf index 2708a7f7cf..d0d335674b 100644 --- a/modules/kms/variables.tf +++ b/modules/kms/variables.tf @@ -87,7 +87,6 @@ variable "keys" { algorithm = string protection_level = optional(string, "SOFTWARE") })) - iam = optional(map(list(string)), {}) iam_bindings = optional(map(object({ members = list(string) diff --git a/modules/kms/versions.tf b/modules/kms/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/kms/versions.tf +++ b/modules/kms/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/logging-bucket/versions.tf b/modules/logging-bucket/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/logging-bucket/versions.tf +++ b/modules/logging-bucket/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/ncc-spoke-ra/versions.tf b/modules/ncc-spoke-ra/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/ncc-spoke-ra/versions.tf +++ b/modules/ncc-spoke-ra/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/net-address/README.md b/modules/net-address/README.md index 55b84108a2..5f53063368 100644 --- a/modules/net-address/README.md +++ b/modules/net-address/README.md @@ -122,6 +122,26 @@ module "addresses" { # tftest modules=1 resources=1 inventory=psc.yaml e2e ``` +To create PSC address targeting a service regional provider use the `service_attachment` property. +```hcl +module "addresses" { + source = "./fabric/modules/net-address" + project_id = var.project_id + psc_addresses = { + cloudsql-one = { + address = "10.0.16.32" + subnet_self_link = var.subnet.self_link + region = var.region + service_attachment = { + psc_service_attachment_link = module.cloudsql-instance.psc_service_attachment_link + } + } + } +} +# tftest modules=2 resources=3 fixtures=fixtures/cloudsql-instance.tf inventory=psc-service-attachment.yaml e2e +``` + + ### IPSec Interconnect addresses ```hcl @@ -176,8 +196,8 @@ module "addresses" { | [internal_addresses](variables.tf#L50) | Map of internal addresses to create, keyed by name. | map(object({…})) | | {} | | [ipsec_interconnect_addresses](variables.tf#L65) | Map of internal addresses used for HPA VPN over Cloud Interconnect. | map(object({…})) | | {} | | [network_attachments](variables.tf#L84) | PSC network attachments, names as keys. | map(object({…})) | | {} | -| [psa_addresses](variables.tf#L102) | Map of internal addresses used for Private Service Access. | map(object({…})) | | {} | -| [psc_addresses](variables.tf#L115) | Map of internal addresses used for Private Service Connect. | map(object({…})) | | {} | +| [psa_addresses](variables.tf#L102) | Map of internal addresses used for Private Service Access. | map(object({…})) | | {} | +| [psc_addresses](variables.tf#L114) | Map of internal addresses used for Private Service Connect. | map(object({…})) | | {} | ## Outputs @@ -193,5 +213,6 @@ module "addresses" { ## Fixtures +- [cloudsql-instance.tf](../../tests/fixtures/cloudsql-instance.tf) - [net-vpc-ipv6.tf](../../tests/fixtures/net-vpc-ipv6.tf) diff --git a/modules/net-address/main.tf b/modules/net-address/main.tf index 20b8b6a16e..e7c69413cd 100644 --- a/modules/net-address/main.tf +++ b/modules/net-address/main.tf @@ -1,5 +1,5 @@ /** - * Copyright 2022 Google LLC + * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,20 +14,6 @@ * limitations under the License. */ -locals { - network_attachments = { - for k, v in var.network_attachments : k => merge(v, { - region = regex("regions/([^/]+)", v.subnet_self_link)[0] - # not using the full self link generates a permadiff - subnet_self_link = ( - startswith(v.subnet_self_link, "https://") - ? v.subnet_self_link - : "https://www.googleapis.com/compute/v1/${v.subnet_self_link}" - ) - }) - } -} - resource "google_compute_global_address" "global" { for_each = var.global_addresses project = var.project_id @@ -66,18 +52,6 @@ resource "google_compute_address" "internal" { subnetwork = each.value.subnetwork } -resource "google_compute_global_address" "psc" { - for_each = var.psc_addresses - project = var.project_id - name = coalesce(each.value.name, each.key) - description = each.value.description - address = try(each.value.address, null) - address_type = "INTERNAL" - network = each.value.network - purpose = "PRIVATE_SERVICE_CONNECT" - # labels = lookup(var.internal_address_labels, each.key, {}) -} - resource "google_compute_global_address" "psa" { for_each = var.psa_addresses project = var.project_id @@ -104,17 +78,3 @@ resource "google_compute_address" "ipsec_interconnect" { purpose = "IPSEC_INTERCONNECT" } -resource "google_compute_network_attachment" "default" { - provider = google-beta - for_each = local.network_attachments - project = var.project_id - region = each.value.region - name = each.key - description = each.value.description - connection_preference = ( - each.value.automatic_connection ? "ACCEPT_AUTOMATIC" : "ACCEPT_MANUAL" - ) - subnetworks = [each.value.subnet_self_link] - producer_accept_lists = each.value.producer_accept_lists - producer_reject_lists = each.value.producer_reject_lists -} diff --git a/modules/net-address/psc.tf b/modules/net-address/psc.tf new file mode 100644 index 0000000000..2fbf75788f --- /dev/null +++ b/modules/net-address/psc.tf @@ -0,0 +1,102 @@ +/** + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +locals { + network_attachments = { + for k, v in var.network_attachments : k => merge(v, { + region = regex("regions/([^/]+)", v.subnet_self_link)[0] + # not using the full self link generates a permadiff + subnet_self_link = ( + startswith(v.subnet_self_link, "https://") + ? v.subnet_self_link + : "https://www.googleapis.com/compute/v1/${v.subnet_self_link}" + ) + }) + } + regional_psc = { + for name, psc in var.psc_addresses : name => psc if psc.region != null + + } + global_psc = { + for name, psc in var.psc_addresses : name => psc if psc.region == null + } +} + +resource "google_compute_network_attachment" "default" { + provider = google-beta + for_each = local.network_attachments + project = var.project_id + region = each.value.region + name = each.key + description = each.value.description + connection_preference = ( + each.value.automatic_connection ? "ACCEPT_AUTOMATIC" : "ACCEPT_MANUAL" + ) + subnetworks = [each.value.subnet_self_link] + producer_accept_lists = each.value.producer_accept_lists + producer_reject_lists = each.value.producer_reject_lists +} + +# global PSC services +resource "google_compute_global_address" "psc" { + for_each = local.global_psc + project = var.project_id + name = coalesce(each.value.name, each.key) + description = each.value.description + address = try(each.value.address, null) + address_type = "INTERNAL" + network = each.value.network + purpose = "PRIVATE_SERVICE_CONNECT" + # labels = lookup(var.internal_address_labels, each.key, {}) +} + +resource "google_compute_global_forwarding_rule" "psc_consumer" { + for_each = { for name, psc in local.global_psc : name => psc if psc.service_attachment != null } + name = coalesce(each.value.name, each.key) + project = var.project_id + subnetwork = each.value.subnet_self_link + ip_address = google_compute_global_address.psc[each.key].self_link + load_balancing_scheme = "" + target = each.value.service_attachment.psc_service_attachment_link +} + +# regional PSC services +resource "google_compute_address" "psc" { + for_each = local.regional_psc + project = var.project_id + name = coalesce(each.value.name, each.key) + address = try(each.value.address, null) + address_type = "INTERNAL" + description = each.value.description + network = each.value.network + # purpose not applicable for regional address + # purpose = "PRIVATE_SERVICE_CONNECT" + region = each.value.region + subnetwork = each.value.subnet_self_link + # labels = lookup(var.internal_address_labels, each.key, {}) +} + +resource "google_compute_forwarding_rule" "psc_consumer" { + for_each = { for name, psc in local.regional_psc : name => psc if psc.service_attachment != null } + name = coalesce(each.value.name, each.key) + project = var.project_id + region = each.value.region + subnetwork = each.value.subnet_self_link + ip_address = google_compute_address.psc[each.key].self_link + load_balancing_scheme = "" + recreate_closed_psc = true + target = each.value.service_attachment.psc_service_attachment_link +} diff --git a/modules/net-address/variables.tf b/modules/net-address/variables.tf index 190bffdde6..236c23960a 100644 --- a/modules/net-address/variables.tf +++ b/modules/net-address/variables.tf @@ -107,7 +107,6 @@ variable "psa_addresses" { prefix_length = number description = optional(string, "Terraform managed.") name = optional(string) - })) default = {} } @@ -115,10 +114,27 @@ variable "psa_addresses" { variable "psc_addresses" { description = "Map of internal addresses used for Private Service Connect." type = map(object({ - address = string - network = string - description = optional(string, "Terraform managed.") - name = optional(string) + address = string + description = optional(string, "Terraform managed.") + name = optional(string) + network = optional(string) + region = optional(string) + subnet_self_link = optional(string) + service_attachment = optional(object({ # so we can safely check if service_attachemnt != null in for_each + psc_service_attachment_link = string + })) })) default = {} + validation { + condition = alltrue([for key, value in var.psc_addresses : (value.region != null || (value.region == null && value.network != null))]) + error_message = "Provide network if creating global PSC addresses / endpoints." + } + validation { + condition = alltrue([for key, value in var.psc_addresses : (value.region == null || (value.region != null && value.subnet_self_link != null))]) + error_message = "Provide subnet_self_link if creating regional PSC addresses / endpoints." + } + validation { + condition = alltrue([for key, value in var.psc_addresses : !(value.subnet_self_link != null && value.network != null)]) + error_message = "Do not provide network and subnet_self_link at the same time" + } } diff --git a/modules/net-address/versions.tf b/modules/net-address/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/net-address/versions.tf +++ b/modules/net-address/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/net-cloudnat/README.md b/modules/net-cloudnat/README.md index 407bce3f08..34fb560660 100644 --- a/modules/net-cloudnat/README.md +++ b/modules/net-cloudnat/README.md @@ -6,6 +6,7 @@ Simple Cloud NAT management, with optional router creation. - [Basic Example](#basic-example) - [Subnetwork configuration](#subnetwork-configuration) - [Reserved IPs and custom rules](#reserved-ips-and-custom-rules) +- [Hybrid NAT](#hybrid-nat) - [Variables](#variables) - [Outputs](#outputs) @@ -102,6 +103,59 @@ module "nat" { } # tftest modules=2 resources=5 inventory=rules.yaml e2e ``` +## Hybrid NAT +```hcl +module "vpc1" { + source = "./fabric/modules/net-vpc" + project_id = var.project_id + name = "vpc1" + subnets = [ + { + ip_cidr_range = "10.0.0.0/24" + name = "vpc1-subnet" + region = var.region + } + ] + subnets_private_nat = [ + { + ip_cidr_range = "192.168.15.0/24" + name = "vpc1-nat" + region = var.region + } + ] +} + +module "vpc1-nat" { + source = "./fabric/modules/net-cloudnat" + project_id = var.project_id + region = var.region + name = "vpc1-nat" + type = "PRIVATE" + router_network = module.vpc1.id + config_source_subnetworks = { + all = false + subnetworks = [ + { + self_link = module.vpc1.subnet_ids["${var.region}/vpc1-subnet"] + } + ] + } + config_port_allocation = { + enable_endpoint_independent_mapping = false + enable_dynamic_port_allocation = true + } + rules = [ + { + description = "private nat" + match = "nexthop.is_hybrid" + source_ranges = [ + module.vpc1.subnets_private_nat["${var.region}/vpc1-nat"].id + ] + } + ] +} +# tftest modules=2 resources=7 inventory=hybrid.yaml +``` ## Variables @@ -111,15 +165,16 @@ module "nat" { | [project_id](variables.tf#L82) | Project where resources will be created. | string | ✓ | | | [region](variables.tf#L87) | Region where resources will be created. | string | ✓ | | | [addresses](variables.tf#L17) | Optional list of external address self links. | list(string) | | [] | -| [config_port_allocation](variables.tf#L23) | Configuration for how to assign ports to virtual machines. min_ports_per_vm and max_ports_per_vm have no effect unless enable_dynamic_port_allocation is set to 'true'. | object({…}) | | {} | +| [config_port_allocation](variables.tf#L23) | Configuration for how to assign ports to virtual machines. min_ports_per_vm and max_ports_per_vm have no effect unless enable_dynamic_port_allocation is set to 'true'. | object({…}) | | {} | | [config_source_subnetworks](variables.tf#L39) | Subnetwork configuration. | object({…}) | | {} | -| [config_timeouts](variables.tf#L58) | Timeout configurations. | object({…}) | | {} | +| [config_timeouts](variables.tf#L58) | Timeout configurations. | object({…}) | | {} | | [logging_filter](variables.tf#L71) | Enables logging if not null, value is one of 'ERRORS_ONLY', 'TRANSLATIONS_ONLY', 'ALL'. | string | | null | | [router_asn](variables.tf#L92) | Router ASN used for auto-created router. | number | | null | | [router_create](variables.tf#L98) | Create router. | bool | | true | | [router_name](variables.tf#L104) | Router name, leave blank if router will be created to use auto generated name. | string | | null | | [router_network](variables.tf#L110) | Name of the VPC used for auto-created router. | string | | null | -| [rules](variables.tf#L116) | List of rules associated with this NAT. | list(object({…})) | | [] | +| [rules](variables.tf#L116) | List of rules associated with this NAT. | list(object({…})) | | [] | +| [type](variables.tf#L136) | Whether this Cloud NAT is used for public or private IP translation. One of 'PUBLIC' or 'PRIVATE'. | string | | "PUBLIC" | ## Outputs diff --git a/modules/net-cloudnat/main.tf b/modules/net-cloudnat/main.tf index 7a537d8eee..bf5b7bc785 100644 --- a/modules/net-cloudnat/main.tf +++ b/modules/net-cloudnat/main.tf @@ -1,5 +1,5 @@ /** - * Copyright 2023 Google LLC + * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -47,13 +47,21 @@ resource "google_compute_router" "router" { } resource "google_compute_router_nat" "nat" { - project = var.project_id - region = var.region - name = var.name - router = local.router_name - nat_ips = var.addresses + provider = google-beta + project = var.project_id + region = var.region + name = var.name + type = var.type + router = local.router_name + nat_ips = var.addresses nat_ip_allocate_option = ( - length(var.addresses) > 0 ? "MANUAL_ONLY" : "AUTO_ONLY" + var.type == "PRIVATE" + ? null + : ( + length(var.addresses) > 0 + ? "MANUAL_ONLY" + : "AUTO_ONLY" + ) ) source_subnetwork_ip_ranges_to_nat = local.subnet_config icmp_idle_timeout_sec = var.config_timeouts.icmp @@ -114,7 +122,8 @@ resource "google_compute_router_nat" "nat" { description = rules.value.description match = rules.value.match action { - source_nat_active_ips = rules.value.source_ips + source_nat_active_ips = rules.value.source_ips + source_nat_active_ranges = rules.value.source_ranges } } } diff --git a/modules/net-cloudnat/variables.tf b/modules/net-cloudnat/variables.tf index 0ec05e4221..27484ee319 100644 --- a/modules/net-cloudnat/variables.tf +++ b/modules/net-cloudnat/variables.tf @@ -1,5 +1,5 @@ /** - * Copyright 2023 Google LLC + * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,8 +25,8 @@ variable "config_port_allocation" { type = object({ enable_endpoint_independent_mapping = optional(bool, true) enable_dynamic_port_allocation = optional(bool, false) - min_ports_per_vm = optional(number, 64) - max_ports_per_vm = optional(number, 65536) + min_ports_per_vm = optional(number) + max_ports_per_vm = optional(number) }) default = {} nullable = false @@ -58,11 +58,11 @@ output "foo" { variable "config_timeouts" { description = "Timeout configurations." type = object({ - icmp = optional(number, 30) - tcp_established = optional(number, 1200) - tcp_time_wait = optional(number, 120) - tcp_transitory = optional(number, 30) - udp = optional(number, 30) + icmp = optional(number) + tcp_established = optional(number) + tcp_time_wait = optional(number) + tcp_transitory = optional(number) + udp = optional(number) }) default = {} nullable = false @@ -116,10 +116,30 @@ variable "router_network" { variable "rules" { description = "List of rules associated with this NAT." type = list(object({ - description = optional(string), - match = string - source_ips = list(string) + description = optional(string) + match = string + source_ips = optional(list(string)) + source_ranges = optional(list(string)) })) default = [] nullable = false + validation { + condition = alltrue([ + for r in var.rules : + r.source_ips != null || r.source_ranges != null + ]) + + error_message = "All rules must specify either source_ips or source_ranges." + } +} + +variable "type" { + description = "Whether this Cloud NAT is used for public or private IP translation. One of 'PUBLIC' or 'PRIVATE'." + type = string + default = "PUBLIC" + nullable = false + validation { + condition = var.type == "PUBLIC" || var.type == "PRIVATE" + error_message = "Field type must be either PUBLIC or PRIVATE." + } } diff --git a/modules/net-cloudnat/versions.tf b/modules/net-cloudnat/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/net-cloudnat/versions.tf +++ b/modules/net-cloudnat/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/net-firewall-policy/versions.tf b/modules/net-firewall-policy/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/net-firewall-policy/versions.tf +++ b/modules/net-firewall-policy/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/net-ipsec-over-interconnect/versions.tf b/modules/net-ipsec-over-interconnect/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/net-ipsec-over-interconnect/versions.tf +++ b/modules/net-ipsec-over-interconnect/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/net-lb-app-ext-regional/versions.tf b/modules/net-lb-app-ext-regional/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/net-lb-app-ext-regional/versions.tf +++ b/modules/net-lb-app-ext-regional/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/net-lb-app-ext/versions.tf b/modules/net-lb-app-ext/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/net-lb-app-ext/versions.tf +++ b/modules/net-lb-app-ext/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/net-lb-app-int-cross-region/versions.tf b/modules/net-lb-app-int-cross-region/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/net-lb-app-int-cross-region/versions.tf +++ b/modules/net-lb-app-int-cross-region/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/net-lb-app-int/versions.tf b/modules/net-lb-app-int/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/net-lb-app-int/versions.tf +++ b/modules/net-lb-app-int/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/net-lb-ext/versions.tf b/modules/net-lb-ext/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/net-lb-ext/versions.tf +++ b/modules/net-lb-ext/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/net-lb-int/versions.tf b/modules/net-lb-int/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/net-lb-int/versions.tf +++ b/modules/net-lb-int/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/net-lb-proxy-int/versions.tf b/modules/net-lb-proxy-int/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/net-lb-proxy-int/versions.tf +++ b/modules/net-lb-proxy-int/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/net-swp/versions.tf b/modules/net-swp/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/net-swp/versions.tf +++ b/modules/net-swp/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/net-vlan-attachment/versions.tf b/modules/net-vlan-attachment/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/net-vlan-attachment/versions.tf +++ b/modules/net-vlan-attachment/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/net-vpc-firewall/versions.tf b/modules/net-vpc-firewall/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/net-vpc-firewall/versions.tf +++ b/modules/net-vpc-firewall/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/net-vpc-peering/versions.tf b/modules/net-vpc-peering/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/net-vpc-peering/versions.tf +++ b/modules/net-vpc-peering/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/net-vpc/README.md b/modules/net-vpc/README.md index feee775cc6..fb115804c2 100644 --- a/modules/net-vpc/README.md +++ b/modules/net-vpc/README.md @@ -299,10 +299,12 @@ module "vpc" { { ranges = { myrange = "10.0.1.0/24" } # service_producer = "servicenetworking.googleapis.com" # default value + deletion_policy = "ABANDON" }, { ranges = { netapp = "10.0.2.0/24" } service_producer = "netapp.servicenetworking.goog" + deletion_policy = "ABANDON" } ] } @@ -662,9 +664,10 @@ module "vpc" { | [shared_vpc_host](variables.tf#L238) | Enable shared VPC for this project. | bool | | false | | [shared_vpc_service_projects](variables.tf#L244) | Shared VPC service projects to register with this host. | list(string) | | [] | | [subnets](variables.tf#L250) | Subnet configuration. | list(object({…})) | | [] | -| [subnets_proxy_only](variables.tf#L297) | List of proxy-only subnets for Regional HTTPS or Internal HTTPS load balancers. Note: Only one proxy-only subnet for each VPC network in each region can be active. | list(object({…})) | | [] | -| [subnets_psc](variables.tf#L331) | List of subnets for Private Service Connect service producers. | list(object({…})) | | [] | -| [vpc_create](variables.tf#L363) | Create VPC. When set to false, uses a data source to reference existing VPC. | bool | | true | +| [subnets_private_nat](variables.tf#L297) | List of private NAT subnets. | list(object({…})) | | [] | +| [subnets_proxy_only](variables.tf#L309) | List of proxy-only subnets for Regional HTTPS or Internal HTTPS load balancers. Note: Only one proxy-only subnet for each VPC network in each region can be active. | list(object({…})) | | [] | +| [subnets_psc](variables.tf#L343) | List of subnets for Private Service Connect service producers. | list(object({…})) | | [] | +| [vpc_create](variables.tf#L375) | Create VPC. When set to false, uses a data source to reference existing VPC. | bool | | true | ## Outputs @@ -684,6 +687,7 @@ module "vpc" { | [subnet_secondary_ranges](outputs.tf#L122) | Map of subnet secondary ranges keyed by name. | | | [subnet_self_links](outputs.tf#L133) | Map of subnet self links keyed by name. | | | [subnets](outputs.tf#L142) | Subnet resources. | | -| [subnets_proxy_only](outputs.tf#L151) | L7 ILB or L7 Regional LB subnet resources. | | -| [subnets_psc](outputs.tf#L156) | Private Service Connect subnet resources. | | +| [subnets_private_nat](outputs.tf#L151) | Private NAT subnet resources. | | +| [subnets_proxy_only](outputs.tf#L156) | L7 ILB or L7 Regional LB subnet resources. | | +| [subnets_psc](outputs.tf#L161) | Private Service Connect subnet resources. | | diff --git a/modules/net-vpc/outputs.tf b/modules/net-vpc/outputs.tf index 412e363a4a..4d143e829f 100644 --- a/modules/net-vpc/outputs.tf +++ b/modules/net-vpc/outputs.tf @@ -1,5 +1,5 @@ /** - * Copyright 2023 Google LLC + * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -148,6 +148,11 @@ output "subnets" { ] } +output "subnets_private_nat" { + description = "Private NAT subnet resources." + value = { for k, v in google_compute_subnetwork.private_nat : k => v } +} + output "subnets_proxy_only" { description = "L7 ILB or L7 Regional LB subnet resources." value = { for k, v in google_compute_subnetwork.proxy_only : k => v } diff --git a/modules/net-vpc/psa.tf b/modules/net-vpc/psa.tf index 1e44a9accb..913cebfb3a 100644 --- a/modules/net-vpc/psa.tf +++ b/modules/net-vpc/psa.tf @@ -28,7 +28,7 @@ locals { _psa_peered_domains = flatten([ for config in local.psa_configs : [ for v in config.peered_domains : { - key = "${config.key}-${replace(v, ".", "-")}" + key = "${config.key}-${trimsuffix(replace(v, ".", "-"), "-")}" dns_suffix = v service_producer = config.service_producer } diff --git a/modules/net-vpc/subnets.tf b/modules/net-vpc/subnets.tf index ca3541450c..09d4748d00 100644 --- a/modules/net-vpc/subnets.tf +++ b/modules/net-vpc/subnets.tf @@ -1,5 +1,5 @@ /** - * Copyright 2023 Google LLC + * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -124,6 +124,10 @@ locals { { for s in var.subnets_proxy_only : "${s.region}/${s.name}" => s }, { for k, v in local._factory_subnets : k => v if v._is_proxy_only }, ) + subnets_private_nat = merge( + { for s in var.subnets_private_nat : "${s.region}/${s.name}" => s }, + # { for k, v in local._factory_subnets : k => v if v._is_proxy_only }, + ) subnets_psc = merge( { for s in var.subnets_psc : "${s.region}/${s.name}" => s }, { for k, v in local._factory_subnets : k => v if v._is_psc } @@ -185,6 +189,20 @@ resource "google_compute_subnetwork" "proxy_only" { role = each.value.active ? "ACTIVE" : "BACKUP" } +resource "google_compute_subnetwork" "private_nat" { + for_each = local.subnets_private_nat + project = var.project_id + network = local.network.name + name = each.value.name + region = each.value.region + ip_cidr_range = each.value.ip_cidr_range + description = coalesce( + each.value.description, + "Terraform-managed private NAT subnet." + ) + purpose = "PRIVATE_NAT" +} + resource "google_compute_subnetwork" "psc" { for_each = local.subnets_psc project = var.project_id diff --git a/modules/net-vpc/variables.tf b/modules/net-vpc/variables.tf index d8948a2640..6fd011bec8 100644 --- a/modules/net-vpc/variables.tf +++ b/modules/net-vpc/variables.tf @@ -1,5 +1,5 @@ /** - * Copyright 2023 Google LLC + * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -294,6 +294,18 @@ variable "subnets" { nullable = false } +variable "subnets_private_nat" { + description = "List of private NAT subnets." + type = list(object({ + name = string + ip_cidr_range = string + region = string + description = optional(string) + })) + default = [] + nullable = false +} + variable "subnets_proxy_only" { description = "List of proxy-only subnets for Regional HTTPS or Internal HTTPS load balancers. Note: Only one proxy-only subnet for each VPC network in each region can be active." type = list(object({ diff --git a/modules/net-vpc/versions.tf b/modules/net-vpc/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/net-vpc/versions.tf +++ b/modules/net-vpc/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/net-vpn-dynamic/versions.tf b/modules/net-vpn-dynamic/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/net-vpn-dynamic/versions.tf +++ b/modules/net-vpn-dynamic/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/net-vpn-ha/README.md b/modules/net-vpn-ha/README.md index 2de72f54ea..164e009f7e 100644 --- a/modules/net-vpn-ha/README.md +++ b/modules/net-vpn-ha/README.md @@ -213,9 +213,9 @@ module "vpn_ha" { | [region](variables.tf#L52) | Region used for resources. | string | ✓ | | | [router_config](variables.tf#L57) | Cloud Router configuration for the VPN. If you want to reuse an existing router, set create to false and use name to specify the desired router. | object({…}) | ✓ | | | [peer_gateways](variables.tf#L27) | Configuration of the (external or GCP) peer gateway. | map(object({…})) | | {} | -| [tunnels](variables.tf#L72) | VPN tunnel configurations. | map(object({…})) | | {} | -| [vpn_gateway](variables.tf#L114) | HA VPN Gateway Self Link for using an existing HA VPN Gateway. Ignored if `vpn_gateway_create` is set to `true`. | string | | null | -| [vpn_gateway_create](variables.tf#L120) | Create HA VPN Gateway. Set to null to avoid creation. | object({…}) | | {} | +| [tunnels](variables.tf#L72) | VPN tunnel configurations. | map(object({…})) | | {} | +| [vpn_gateway](variables.tf#L108) | HA VPN Gateway Self Link for using an existing HA VPN Gateway. Ignored if `vpn_gateway_create` is set to `true`. | string | | null | +| [vpn_gateway_create](variables.tf#L114) | Create HA VPN Gateway. Set to null to avoid creation. | object({…}) | | {} | ## Outputs diff --git a/modules/net-vpn-ha/main.tf b/modules/net-vpn-ha/main.tf index 20af29015a..bbb7ca0295 100644 --- a/modules/net-vpn-ha/main.tf +++ b/modules/net-vpn-ha/main.tf @@ -117,15 +117,6 @@ resource "google_compute_router_peer" "bgp_peer" { description = range.value } } - dynamic "bfd" { - for_each = each.value.bgp_peer.bfd != null ? [each.value.bgp_peer.bfd] : [] - content { - session_initialization_mode = bfd.value.session_initialization_mode - min_receive_interval = bfd.value.min_receive_interval - min_transmit_interval = bfd.value.min_transmit_interval - multiplier = bfd.value.multiplier - } - } dynamic "md5_authentication_key" { for_each = each.value.bgp_peer.md5_authentication_key != null ? toset([each.value.bgp_peer.md5_authentication_key]) : [] content { diff --git a/modules/net-vpn-ha/variables.tf b/modules/net-vpn-ha/variables.tf index d507c89881..ba86eee6e9 100644 --- a/modules/net-vpn-ha/variables.tf +++ b/modules/net-vpn-ha/variables.tf @@ -76,12 +76,6 @@ variable "tunnels" { address = string asn = number route_priority = optional(number, 1000) - bfd = optional(object({ - min_receive_interval = optional(number) - min_transmit_interval = optional(number) - multiplier = optional(number) - session_initialization_mode = optional(string, "ACTIVE") - })) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool diff --git a/modules/net-vpn-ha/versions.tf b/modules/net-vpn-ha/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/net-vpn-ha/versions.tf +++ b/modules/net-vpn-ha/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/net-vpn-static/versions.tf b/modules/net-vpn-static/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/net-vpn-static/versions.tf +++ b/modules/net-vpn-static/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/organization/README.md b/modules/organization/README.md index cc602a6f12..f0253d11b3 100644 --- a/modules/organization/README.md +++ b/modules/organization/README.md @@ -440,12 +440,44 @@ module "org" { iam = { "roles/resourcemanager.tagAdmin" = ["group:${var.group_email}"] } + iam_bindings = { + viewer = { + role = "roles/resourcemanager.tagViewer" + members = ["group:gcp-support@example.org"] + } + } + iam_bindings_additive = { + user_app1 = { + role = "roles/resourcemanager.tagUser" + member = "group:app1-team@example.org" + } + } values = { - dev = {} + dev = { + iam_bindings_additive = { + user_app2 = { + role = "roles/resourcemanager.tagUser" + member = "group:app2-team@example.org" + } + } + } prod = { description = "Environment: production." iam = { - "roles/resourcemanager.tagViewer" = ["group:${var.group_email}"] + "roles/resourcemanager.tagViewer" = ["group:app1-team@example.org"] + } + iam_bindings = { + admin = { + role = "roles/resourcemanager.tagAdmin" + members = ["group:gcp-support@example.org"] + condition = { + title = "gcp_support" + expression = <<-END + request.time.getHours("Europe/Berlin") <= 9 && + request.time.getHours("Europe/Berlin") >= 17 + END + } + } } } } @@ -455,8 +487,9 @@ module "org" { env-prod = module.org.tag_values["environment/prod"].id } } -# tftest modules=1 resources=6 inventory=tags.yaml e2e serial +# tftest modules=1 resources=10 inventory=tags.yaml ``` + You can also define network tags, through a dedicated variable *network_tags*: @@ -498,8 +531,9 @@ module "org" { | [org-policy-custom-constraints.tf](./org-policy-custom-constraints.tf) | None | google_org_policy_custom_constraint | | [organization-policies.tf](./organization-policies.tf) | Organization-level organization policies. | google_org_policy_policy | | [outputs.tf](./outputs.tf) | Module outputs. | | -| [tags.tf](./tags.tf) | None | google_tags_tag_binding · google_tags_tag_key · google_tags_tag_key_iam_binding · google_tags_tag_value · google_tags_tag_value_iam_binding | +| [tags.tf](./tags.tf) | None | google_tags_tag_binding · google_tags_tag_key · google_tags_tag_key_iam_binding · google_tags_tag_key_iam_member · google_tags_tag_value · google_tags_tag_value_iam_binding · google_tags_tag_value_iam_member | | [variables-iam.tf](./variables-iam.tf) | None | | +| [variables-logging.tf](./variables-logging.tf) | None | | | [variables-tags.tf](./variables-tags.tf) | None | | | [variables.tf](./variables.tf) | Module variables. | | | [versions.tf](./versions.tf) | Version pins. | | @@ -508,7 +542,7 @@ module "org" { | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [organization_id](variables.tf#L155) | Organization id in organizations/nnnnnn format. | string | ✓ | | +| [organization_id](variables.tf#L92) | Organization id in organizations/nnnnnn format. | string | ✓ | | | [contacts](variables.tf#L17) | List of essential contacts for this resource. Must be in the form EMAIL -> [NOTIFICATION_TYPES]. Valid notification types are ALL, SUSPENSION, SECURITY, TECHNICAL, BILLING, LEGAL, PRODUCT_UPDATES. | map(list(string)) | | {} | | [custom_roles](variables.tf#L24) | Map of role name => list of permissions to create in this project. | map(list(string)) | | {} | | [factories_config](variables.tf#L31) | Paths to data files and folders that enable factory functionality. | object({…}) | | {} | @@ -517,15 +551,15 @@ module "org" { | [iam_bindings](variables-iam.tf#L24) | Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary. | map(object({…})) | | {} | | [iam_bindings_additive](variables-iam.tf#L39) | Individual additive IAM bindings. Keys are arbitrary. | map(object({…})) | | {} | | [iam_by_principals](variables-iam.tf#L54) | 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)) | | {} | -| [logging_data_access](variables.tf#L51) | Control activation of data access logs. Format is service => { log type => [exempted members]}. The special 'allServices' key denotes configuration for all services. | map(map(list(string))) | | {} | -| [logging_exclusions](variables.tf#L66) | Logging exclusions for this organization in the form {NAME -> FILTER}. | map(string) | | {} | -| [logging_settings](variables.tf#L73) | Default settings for logging resources. | object({…}) | | null | -| [logging_sinks](variables.tf#L83) | Logging sinks to create for the organization. | map(object({…})) | | {} | -| [network_tags](variables-tags.tf#L17) | Network tags by key name. If `id` is provided, key creation is skipped. The `iam` attribute behaves like the similarly named one at module level. | map(object({…})) | | {} | -| [org_policies](variables.tf#L114) | Organization policies applied to this organization keyed by policy name. | map(object({…})) | | {} | -| [org_policy_custom_constraints](variables.tf#L141) | Organization policy custom constraints keyed by constraint name. | map(object({…})) | | {} | -| [tag_bindings](variables-tags.tf#L45) | Tag bindings for this organization, in key => tag value id format. | map(string) | | {} | -| [tags](variables-tags.tf#L52) | Tags by key name. If `id` is provided, key or value creation is skipped. The `iam` attribute behaves like the similarly named one at module level. | map(object({…})) | | {} | +| [logging_data_access](variables-logging.tf#L17) | Control activation of data access logs. Format is service => { log type => [exempted members]}. The special 'allServices' key denotes configuration for all services. | map(map(list(string))) | | {} | +| [logging_exclusions](variables-logging.tf#L32) | Logging exclusions for this organization in the form {NAME -> FILTER}. | map(string) | | {} | +| [logging_settings](variables-logging.tf#L39) | Default settings for logging resources. | object({…}) | | null | +| [logging_sinks](variables-logging.tf#L49) | Logging sinks to create for the organization. | map(object({…})) | | {} | +| [network_tags](variables-tags.tf#L17) | Network tags by key name. If `id` is provided, key creation is skipped. The `iam` attribute behaves like the similarly named one at module level. | map(object({…})) | | {} | +| [org_policies](variables.tf#L51) | Organization policies applied to this organization keyed by policy name. | map(object({…})) | | {} | +| [org_policy_custom_constraints](variables.tf#L78) | Organization policy custom constraints keyed by constraint name. | map(object({…})) | | {} | +| [tag_bindings](variables-tags.tf#L81) | Tag bindings for this organization, in key => tag value id format. | map(string) | | {} | +| [tags](variables-tags.tf#L88) | Tags by key name. If `id` is provided, key or value creation is skipped. The `iam` attribute behaves like the similarly named one at module level. | map(object({…})) | | {} | ## Outputs diff --git a/modules/organization/tags.tf b/modules/organization/tags.tf index d25757c243..0321818a5a 100644 --- a/modules/organization/tags.tf +++ b/modules/organization/tags.tf @@ -15,50 +15,96 @@ */ locals { - _tag_values = flatten([ - for tag, attrs in local.tags : [ - for value, value_attrs in attrs.values : { - description = value_attrs.description, - key = "${tag}/${value}" - id = try(value_attrs.id, null) - name = value - roles = keys(value_attrs.iam) - tag = tag - tag_id = attrs.id - tag_network = try(attrs.network, null) != null + _tag_iam = flatten([ + for k, v in local.tags : [ + for role in keys(v.iam) : { + # we cycle on keys here so we don't risk injecting dynamic values + role = role + tag = k + tag_id = v.id } ] ]) - _tag_values_iam = flatten([ - for key, value_attrs in local.tag_values : [ - for role in value_attrs.roles : { - id = value_attrs.id - key = value_attrs.key - name = value_attrs.name + _tag_value_iam = flatten([ + for k, v in local.tag_values : [ + for role in v.roles : { + id = v.id + key = v.key + name = v.name role = role - tag = value_attrs.tag + tag = v.tag } ] ]) - _tags_iam = flatten([ - for tag, attrs in local.tags : [ - for role in keys(attrs.iam) : { - role = role - tag = tag - tag_id = attrs.id + _tag_values = flatten([ + for k, v in local.tags : [ + for vk, vv in v.values : { + description = vv.description, + key = "${k}/${vk}" + iam_bindings = keys(vv.iam_bindings) + iam_bindings_additive = keys(vv.iam_bindings_additive) + id = try(vv.id, null) + name = vk + # we only store keys here so we don't risk injecting dynamic values + roles = keys(vv.iam) + tag = k + tag_id = v.id + tag_network = try(v.network, null) != null } ] ]) - tag_values = { - for t in local._tag_values : t.key => t + tag_iam = { + for t in local._tag_iam : "${t.tag}:${t.role}" => t + } + tag_iam_bindings = merge([ + for k, v in local.tags : { + for bk in keys(v.iam_bindings) : "${k}:${bk}" => { + binding = bk + tag = k + tag_id = v.id + } + } + ]...) + tag_iam_bindings_additive = merge([ + for k, v in local.tags : { + for bk in keys(v.iam_bindings_additive) : "${k}:${bk}" => { + binding = bk + tag = k + tag_id = v.id + } + } + ]...) + tag_value_iam = { + for v in local._tag_value_iam : "${v.key}:${v.role}" => v } - tag_values_iam = { - for t in local._tag_values_iam : "${t.key}:${t.role}" => t + tag_value_iam_bindings = merge([ + for k, v in local.tag_values : { + for bk in v.iam_bindings : "${k}:${bk}" => { + binding = bk + id = v.id + key = k + name = v.name + tag = v.tag + tag_id = v.id + } + } + ]...) + tag_value_iam_bindings_additive = merge([ + for k, v in local.tag_values : { + for bk in v.iam_bindings_additive : "${k}:${bk}" => { + binding = bk + id = v.id + key = k + name = v.name + tag = v.tag + tag_id = v.id + } + } + ]...) + tag_values = { + for v in local._tag_values : v.key => v } tags = merge(var.tags, var.network_tags) - tags_iam = { - for t in local._tags_iam : "${t.tag}:${t.role}" => t - } } # keys @@ -82,7 +128,7 @@ resource "google_tags_tag_key" "default" { } resource "google_tags_tag_key_iam_binding" "default" { - for_each = local.tags_iam + for_each = local.tag_iam tag_key = ( each.value.tag_id == null ? google_tags_tag_key.default[each.value.tag].id @@ -94,6 +140,30 @@ resource "google_tags_tag_key_iam_binding" "default" { ) } +resource "google_tags_tag_key_iam_binding" "bindings" { + for_each = local.tag_iam_bindings + tag_key = ( + each.value.tag_id == null + ? google_tags_tag_key.default[each.value.tag].id + : each.value.tag_id + ) + role = local.tags[each.value.tag]["iam_bindings"][each.value.binding].role + members = ( + local.tags[each.value.tag]["iam_bindings"][each.value.binding].members + ) +} + +resource "google_tags_tag_key_iam_member" "bindings" { + for_each = local.tag_iam_bindings_additive + tag_key = ( + each.value.tag_id == null + ? google_tags_tag_key.default[each.value.tag].id + : each.value.tag_id + ) + role = local.tags[each.value.tag]["iam_bindings_additive"][each.value.binding].role + member = local.tags[each.value.tag]["iam_bindings_additive"][each.value.binding].member +} + # values resource "google_tags_tag_value" "default" { @@ -108,7 +178,7 @@ resource "google_tags_tag_value" "default" { } resource "google_tags_tag_value_iam_binding" "default" { - for_each = local.tag_values_iam + for_each = local.tag_value_iam tag_value = ( each.value.id == null ? google_tags_tag_value.default[each.value.key].id @@ -121,6 +191,36 @@ resource "google_tags_tag_value_iam_binding" "default" { ) } +resource "google_tags_tag_value_iam_binding" "bindings" { + for_each = local.tag_value_iam_bindings + tag_value = ( + each.value.id == null + ? google_tags_tag_value.default[each.value.key].id + : each.value.id + ) + role = ( + local.tags[each.value.tag]["values"][each.value.name]["iam_bindings"][each.value.binding].role + ) + members = ( + local.tags[each.value.tag]["values"][each.value.name]["iam_bindings"][each.value.binding].members + ) +} + +resource "google_tags_tag_value_iam_member" "bindings" { + for_each = local.tag_value_iam_bindings_additive + tag_value = ( + each.value.id == null + ? google_tags_tag_value.default[each.value.key].id + : each.value.id + ) + role = ( + local.tags[each.value.tag]["values"][each.value.name]["iam_bindings_additive"][each.value.binding].role + ) + member = ( + local.tags[each.value.tag]["values"][each.value.name]["iam_bindings_additive"][each.value.binding].member + ) +} + # bindings resource "google_tags_tag_binding" "binding" { diff --git a/modules/organization/variables-logging.tf b/modules/organization/variables-logging.tf new file mode 100644 index 0000000000..210352f081 --- /dev/null +++ b/modules/organization/variables-logging.tf @@ -0,0 +1,78 @@ +/** + * 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 "logging_data_access" { + description = "Control activation of data access logs. Format is service => { log type => [exempted members]}. The special 'allServices' key denotes configuration for all services." + type = map(map(list(string))) + nullable = false + default = {} + validation { + condition = alltrue(flatten([ + for k, v in var.logging_data_access : [ + for kk, vv in v : contains(["DATA_READ", "DATA_WRITE", "ADMIN_READ"], kk) + ] + ])) + error_message = "Log type keys for each service can only be one of 'DATA_READ', 'DATA_WRITE', 'ADMIN_READ'." + } +} + +variable "logging_exclusions" { + description = "Logging exclusions for this organization in the form {NAME -> FILTER}." + type = map(string) + default = {} + nullable = false +} + +variable "logging_settings" { + description = "Default settings for logging resources." + type = object({ + # TODO: add support for CMEK + disable_default_sink = optional(bool) + storage_location = optional(string) + }) + default = null +} + +variable "logging_sinks" { + description = "Logging sinks to create for the organization." + type = map(object({ + bq_partitioned_table = optional(bool, false) + description = optional(string) + destination = string + disabled = optional(bool, false) + exclusions = optional(map(string), {}) + filter = optional(string) + iam = optional(bool, true) + include_children = optional(bool, true) + type = string + })) + default = {} + nullable = false + validation { + condition = alltrue([ + for k, v in var.logging_sinks : + contains(["bigquery", "logging", "project", "pubsub", "storage"], v.type) + ]) + error_message = "Type must be one of 'bigquery', 'logging', 'project', 'pubsub', 'storage'." + } + validation { + condition = alltrue([ + for k, v in var.logging_sinks : + v.bq_partitioned_table != true || v.type == "bigquery" + ]) + error_message = "Can only set bq_partitioned_table when type is `bigquery`." + } +} diff --git a/modules/organization/variables-tags.tf b/modules/organization/variables-tags.tf index 4688504d57..21a0efe6f4 100644 --- a/modules/organization/variables-tags.tf +++ b/modules/organization/variables-tags.tf @@ -19,11 +19,47 @@ variable "network_tags" { type = map(object({ description = optional(string, "Managed by the Terraform organization module.") iam = optional(map(list(string)), {}) - id = optional(string) - network = string # project_id/vpc_name + iam_bindings = optional(map(object({ + members = list(string) + role = string + condition = optional(object({ + expression = string + title = string + description = optional(string) + })) + })), {}) + iam_bindings_additive = optional(map(object({ + member = string + role = string + condition = optional(object({ + expression = string + title = string + description = optional(string) + })) + })), {}) + id = optional(string) + network = string # project_id/vpc_name values = optional(map(object({ description = optional(string, "Managed by the Terraform organization module.") iam = optional(map(list(string)), {}) + iam_bindings = optional(map(object({ + members = list(string) + role = string + condition = optional(object({ + expression = string + title = string + description = optional(string) + })) + })), {}) + iam_bindings_additive = optional(map(object({ + member = string + role = string + condition = optional(object({ + expression = string + title = string + description = optional(string) + })) + })), {}) })), {}) })) nullable = false @@ -54,11 +90,47 @@ variable "tags" { type = map(object({ description = optional(string, "Managed by the Terraform organization module.") iam = optional(map(list(string)), {}) - id = optional(string) + iam_bindings = optional(map(object({ + members = list(string) + role = string + condition = optional(object({ + expression = string + title = string + description = optional(string) + })) + })), {}) + iam_bindings_additive = optional(map(object({ + member = string + role = string + condition = optional(object({ + expression = string + title = string + description = optional(string) + })) + })), {}) + id = optional(string) values = optional(map(object({ description = optional(string, "Managed by the Terraform organization module.") iam = optional(map(list(string)), {}) - id = optional(string) + iam_bindings = optional(map(object({ + members = list(string) + role = string + condition = optional(object({ + expression = string + title = string + description = optional(string) + })) + })), {}) + iam_bindings_additive = optional(map(object({ + member = string + role = string + condition = optional(object({ + expression = string + title = string + description = optional(string) + })) + })), {}) + id = optional(string) })), {}) })) nullable = false diff --git a/modules/organization/variables.tf b/modules/organization/variables.tf index 4464558e69..146cf9b14a 100644 --- a/modules/organization/variables.tf +++ b/modules/organization/variables.tf @@ -48,69 +48,6 @@ variable "firewall_policy" { default = null } -variable "logging_data_access" { - description = "Control activation of data access logs. Format is service => { log type => [exempted members]}. The special 'allServices' key denotes configuration for all services." - type = map(map(list(string))) - nullable = false - default = {} - validation { - condition = alltrue(flatten([ - for k, v in var.logging_data_access : [ - for kk, vv in v : contains(["DATA_READ", "DATA_WRITE", "ADMIN_READ"], kk) - ] - ])) - error_message = "Log type keys for each service can only be one of 'DATA_READ', 'DATA_WRITE', 'ADMIN_READ'." - } -} - -variable "logging_exclusions" { - description = "Logging exclusions for this organization in the form {NAME -> FILTER}." - type = map(string) - default = {} - nullable = false -} - -variable "logging_settings" { - description = "Default settings for logging resources." - type = object({ - # TODO: add support for CMEK - disable_default_sink = optional(bool) - storage_location = optional(string) - }) - default = null -} - -variable "logging_sinks" { - description = "Logging sinks to create for the organization." - type = map(object({ - bq_partitioned_table = optional(bool, false) - description = optional(string) - destination = string - disabled = optional(bool, false) - exclusions = optional(map(string), {}) - filter = optional(string) - iam = optional(bool, true) - include_children = optional(bool, true) - type = string - })) - default = {} - nullable = false - validation { - condition = alltrue([ - for k, v in var.logging_sinks : - contains(["bigquery", "logging", "project", "pubsub", "storage"], v.type) - ]) - error_message = "Type must be one of 'bigquery', 'logging', 'project', 'pubsub', 'storage'." - } - validation { - condition = alltrue([ - for k, v in var.logging_sinks : - v.bq_partitioned_table != true || v.type == "bigquery" - ]) - error_message = "Can only set bq_partitioned_table when type is `bigquery`." - } -} - variable "org_policies" { description = "Organization policies applied to this organization keyed by policy name." type = map(object({ diff --git a/modules/organization/versions.tf b/modules/organization/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/organization/versions.tf +++ b/modules/organization/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/project-factory/outputs.tf b/modules/project-factory/outputs.tf index 9f49ebe986..5040e76671 100644 --- a/modules/project-factory/outputs.tf +++ b/modules/project-factory/outputs.tf @@ -16,7 +16,7 @@ output "folders" { description = "Folder ids." - value = local.folders + value = local.hierarchy } output "projects" { diff --git a/modules/project/README.md b/modules/project/README.md index 75388aefc3..cd92870a47 100644 --- a/modules/project/README.md +++ b/modules/project/README.md @@ -1173,7 +1173,7 @@ module "bucket" { | [quotas.tf](./quotas.tf) | None | google_cloud_quotas_quota_preference | | [service-accounts.tf](./service-accounts.tf) | Service identities and supporting resources. | google_kms_crypto_key_iam_member · google_project_default_service_accounts · google_project_iam_member · google_project_service_identity | | [shared-vpc.tf](./shared-vpc.tf) | Shared VPC project-level configuration. | google_compute_shared_vpc_host_project · google_compute_shared_vpc_service_project · google_compute_subnetwork_iam_member · google_project_iam_member | -| [tags.tf](./tags.tf) | None | google_tags_tag_binding · google_tags_tag_key · google_tags_tag_key_iam_binding · google_tags_tag_value · google_tags_tag_value_iam_binding | +| [tags.tf](./tags.tf) | None | google_tags_tag_binding · google_tags_tag_key · google_tags_tag_key_iam_binding · google_tags_tag_key_iam_member · google_tags_tag_value · google_tags_tag_value_iam_binding · google_tags_tag_value_iam_member | | [variables-iam.tf](./variables-iam.tf) | None | | | [variables-quotas.tf](./variables-quotas.tf) | None | | | [variables-tags.tf](./variables-tags.tf) | None | | @@ -1204,7 +1204,7 @@ module "bucket" { | [logging_exclusions](variables.tf#L108) | Logging exclusions for this project in the form {NAME -> FILTER}. | map(string) | | {} | | [logging_sinks](variables.tf#L115) | Logging sinks to create for this project. | map(object({…})) | | {} | | [metric_scopes](variables.tf#L146) | List of projects that will act as metric scopes for this project. | list(string) | | [] | -| [network_tags](variables-tags.tf#L17) | Network tags by key name. If `id` is provided, key creation is skipped. The `iam` attribute behaves like the similarly named one at module level. | map(object({…})) | | {} | +| [network_tags](variables-tags.tf#L17) | Network tags by key name. If `id` is provided, key creation is skipped. The `iam` attribute behaves like the similarly named one at module level. | map(object({…})) | | {} | | [org_policies](variables.tf#L158) | Organization policies applied to this project keyed by policy name. | map(object({…})) | | {} | | [parent](variables.tf#L185) | Parent folder or organization in 'folders/folder_id' or 'organizations/org_id' format. | string | | null | | [prefix](variables.tf#L195) | Optional prefix used to generate project id and name. | string | | null | @@ -1216,8 +1216,8 @@ module "bucket" { | [shared_vpc_host_config](variables.tf#L235) | Configures this project as a Shared VPC host project (mutually exclusive with shared_vpc_service_project). | object({…}) | | null | | [shared_vpc_service_config](variables.tf#L244) | Configures this project as a Shared VPC service project (mutually exclusive with shared_vpc_host_config). | object({…}) | | {…} | | [skip_delete](variables.tf#L272) | Allows the underlying resources to be destroyed without destroying the project itself. | bool | | false | -| [tag_bindings](variables-tags.tf#L45) | Tag bindings for this project, in key => tag value id format. | map(string) | | null | -| [tags](variables-tags.tf#L51) | Tags by key name. If `id` is provided, key or value creation is skipped. The `iam` attribute behaves like the similarly named one at module level. | map(object({…})) | | {} | +| [tag_bindings](variables-tags.tf#L81) | Tag bindings for this project, in key => tag value id format. | map(string) | | null | +| [tags](variables-tags.tf#L88) | Tags by key name. If `id` is provided, key or value creation is skipped. The `iam` attribute behaves like the similarly named one at module level. | map(object({…})) | | {} | | [vpc_sc](variables.tf#L278) | VPC-SC configuration for the project, use when `ignore_changes` for resources is set in the VPC-SC module. | object({…}) | | null | ## Outputs diff --git a/modules/project/service-agents.yaml b/modules/project/service-agents.yaml index 66c95a4640..455287e807 100644 --- a/modules/project/service-agents.yaml +++ b/modules/project/service-agents.yaml @@ -121,6 +121,7 @@ service_agent: "service-%s@gcp-sa-anthossupport.iam.gserviceaccount.com" - name: "connectors" service_agent: "service-%s@gcp-sa-connectors.iam.gserviceaccount.com" + jit: true - name: "contactcenteraiplatform" service_agent: "service-%s@gcp-sa-ccaip.iam.gserviceaccount.com" - name: "contactcenterinsights" diff --git a/modules/project/tags.tf b/modules/project/tags.tf index 4f2a666459..1f9ff378b5 100644 --- a/modules/project/tags.tf +++ b/modules/project/tags.tf @@ -15,50 +15,96 @@ */ locals { - _tag_values = flatten([ - for tag, attrs in local.tags : [ - for value, value_attrs in attrs.values : { - description = value_attrs.description, - key = "${tag}/${value}" - id = try(value_attrs.id, null) - name = value - roles = keys(value_attrs.iam) - tag = tag - tag_id = attrs.id - tag_network = try(attrs.network, null) != null + _tag_iam = flatten([ + for k, v in local.tags : [ + for role in keys(v.iam) : { + # we cycle on keys here so we don't risk injecting dynamic values + role = role + tag = k + tag_id = v.id } ] ]) - _tag_values_iam = flatten([ - for key, value_attrs in local.tag_values : [ - for role in value_attrs.roles : { - id = value_attrs.id - key = value_attrs.key - name = value_attrs.name + _tag_value_iam = flatten([ + for k, v in local.tag_values : [ + for role in v.roles : { + id = v.id + key = v.key + name = v.name role = role - tag = value_attrs.tag + tag = v.tag } ] ]) - _tags_iam = flatten([ - for tag, attrs in local.tags : [ - for role in keys(attrs.iam) : { - role = role - tag = tag - tag_id = attrs.id + _tag_values = flatten([ + for k, v in local.tags : [ + for vk, vv in v.values : { + description = vv.description, + key = "${k}/${vk}" + iam_bindings = keys(vv.iam_bindings) + iam_bindings_additive = keys(vv.iam_bindings_additive) + id = try(vv.id, null) + name = vk + # we only store keys here so we don't risk injecting dynamic values + roles = keys(vv.iam) + tag = k + tag_id = v.id + tag_network = try(v.network, null) != null } ] ]) - tag_values = { - for t in local._tag_values : t.key => t + tag_iam = { + for t in local._tag_iam : "${t.tag}:${t.role}" => t + } + tag_iam_bindings = merge([ + for k, v in local.tags : { + for bk in keys(v.iam_bindings) : "${k}:${bk}" => { + binding = bk + tag = k + tag_id = v.id + } + } + ]...) + tag_iam_bindings_additive = merge([ + for k, v in local.tags : { + for bk in keys(v.iam_bindings_additive) : "${k}:${bk}" => { + binding = bk + tag = k + tag_id = v.id + } + } + ]...) + tag_value_iam = { + for v in local._tag_value_iam : "${v.key}:${v.role}" => v } - tag_values_iam = { - for t in local._tag_values_iam : "${t.key}:${t.role}" => t + tag_value_iam_bindings = merge([ + for k, v in local.tag_values : { + for bk in v.iam_bindings : "${k}:${bk}" => { + binding = bk + id = v.id + key = k + name = v.name + tag = v.tag + tag_id = v.id + } + } + ]...) + tag_value_iam_bindings_additive = merge([ + for k, v in local.tag_values : { + for bk in v.iam_bindings_additive : "${k}:${bk}" => { + binding = bk + id = v.id + key = k + name = v.name + tag = v.tag + tag_id = v.id + } + } + ]...) + tag_values = { + for v in local._tag_values : v.key => v } tags = merge(var.tags, var.network_tags) - tags_iam = { - for t in local._tags_iam : "${t.tag}:${t.role}" => t - } } # keys @@ -82,7 +128,7 @@ resource "google_tags_tag_key" "default" { } resource "google_tags_tag_key_iam_binding" "default" { - for_each = local.tags_iam + for_each = local.tag_iam tag_key = ( each.value.tag_id == null ? google_tags_tag_key.default[each.value.tag].id @@ -94,6 +140,30 @@ resource "google_tags_tag_key_iam_binding" "default" { ) } +resource "google_tags_tag_key_iam_binding" "bindings" { + for_each = local.tag_iam_bindings + tag_key = ( + each.value.tag_id == null + ? google_tags_tag_key.default[each.value.tag].id + : each.value.tag_id + ) + role = local.tags[each.value.tag]["iam_bindings"][each.value.binding].role + members = ( + local.tags[each.value.tag]["iam_bindings"][each.value.binding].members + ) +} + +resource "google_tags_tag_key_iam_member" "bindings" { + for_each = local.tag_iam_bindings_additive + tag_key = ( + each.value.tag_id == null + ? google_tags_tag_key.default[each.value.tag].id + : each.value.tag_id + ) + role = local.tags[each.value.tag]["iam_bindings_additive"][each.value.binding].role + member = local.tags[each.value.tag]["iam_bindings_additive"][each.value.binding].member +} + # values resource "google_tags_tag_value" "default" { @@ -108,7 +178,7 @@ resource "google_tags_tag_value" "default" { } resource "google_tags_tag_value_iam_binding" "default" { - for_each = local.tag_values_iam + for_each = local.tag_value_iam tag_value = ( each.value.id == null ? google_tags_tag_value.default[each.value.key].id @@ -121,6 +191,36 @@ resource "google_tags_tag_value_iam_binding" "default" { ) } +resource "google_tags_tag_value_iam_binding" "bindings" { + for_each = local.tag_value_iam_bindings + tag_value = ( + each.value.id == null + ? google_tags_tag_value.default[each.value.key].id + : each.value.id + ) + role = ( + local.tags[each.value.tag]["values"][each.value.name]["iam_bindings"][each.value.binding].role + ) + members = ( + local.tags[each.value.tag]["values"][each.value.name]["iam_bindings"][each.value.binding].members + ) +} + +resource "google_tags_tag_value_iam_member" "bindings" { + for_each = local.tag_value_iam_bindings_additive + tag_value = ( + each.value.id == null + ? google_tags_tag_value.default[each.value.key].id + : each.value.id + ) + role = ( + local.tags[each.value.tag]["values"][each.value.name]["iam_bindings_additive"][each.value.binding].role + ) + member = ( + local.tags[each.value.tag]["values"][each.value.name]["iam_bindings_additive"][each.value.binding].member + ) +} + # bindings resource "google_tags_tag_binding" "binding" { diff --git a/modules/project/variables-tags.tf b/modules/project/variables-tags.tf index 8914aae6e6..ac73f03fd8 100644 --- a/modules/project/variables-tags.tf +++ b/modules/project/variables-tags.tf @@ -19,11 +19,47 @@ variable "network_tags" { type = map(object({ description = optional(string, "Managed by the Terraform project module.") iam = optional(map(list(string)), {}) - id = optional(string) - network = string # project_id/vpc_name + iam_bindings = optional(map(object({ + members = list(string) + role = string + condition = optional(object({ + expression = string + title = string + description = optional(string) + })) + })), {}) + iam_bindings_additive = optional(map(object({ + member = string + role = string + condition = optional(object({ + expression = string + title = string + description = optional(string) + })) + })), {}) + id = optional(string) + network = string # project_id/vpc_name values = optional(map(object({ description = optional(string, "Managed by the Terraform project module.") iam = optional(map(list(string)), {}) + iam_bindings = optional(map(object({ + members = list(string) + role = string + condition = optional(object({ + expression = string + title = string + description = optional(string) + })) + })), {}) + iam_bindings_additive = optional(map(object({ + member = string + role = string + condition = optional(object({ + expression = string + title = string + description = optional(string) + })) + })), {}) })), {}) })) nullable = false @@ -45,7 +81,8 @@ variable "network_tags" { variable "tag_bindings" { description = "Tag bindings for this project, in key => tag value id format." type = map(string) - default = null + # we need default null here for the project factory module + default = null } variable "tags" { @@ -53,11 +90,47 @@ variable "tags" { type = map(object({ description = optional(string, "Managed by the Terraform project module.") iam = optional(map(list(string)), {}) - id = optional(string) + iam_bindings = optional(map(object({ + members = list(string) + role = string + condition = optional(object({ + expression = string + title = string + description = optional(string) + })) + })), {}) + iam_bindings_additive = optional(map(object({ + member = string + role = string + condition = optional(object({ + expression = string + title = string + description = optional(string) + })) + })), {}) + id = optional(string) values = optional(map(object({ description = optional(string, "Managed by the Terraform project module.") iam = optional(map(list(string)), {}) - id = optional(string) + iam_bindings = optional(map(object({ + members = list(string) + role = string + condition = optional(object({ + expression = string + title = string + description = optional(string) + })) + })), {}) + iam_bindings_additive = optional(map(object({ + member = string + role = string + condition = optional(object({ + expression = string + title = string + description = optional(string) + })) + })), {}) + id = optional(string) })), {}) })) nullable = false diff --git a/modules/project/versions.tf b/modules/project/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/project/versions.tf +++ b/modules/project/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/projects-data-source/versions.tf b/modules/projects-data-source/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/projects-data-source/versions.tf +++ b/modules/projects-data-source/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/pubsub/README.md b/modules/pubsub/README.md index 6d924d90d2..4aaa4a4812 100644 --- a/modules/pubsub/README.md +++ b/modules/pubsub/README.md @@ -60,6 +60,7 @@ module "pubsub" { source = "./fabric/modules/pubsub" project_id = var.project_id name = "my-topic" + labels = { test = "default" } subscriptions = { test-pull = {} test-pull-override = { diff --git a/modules/pubsub/main.tf b/modules/pubsub/main.tf index b65d372f11..a090f861b0 100644 --- a/modules/pubsub/main.tf +++ b/modules/pubsub/main.tf @@ -54,7 +54,7 @@ resource "google_pubsub_subscription" "default" { project = var.project_id name = each.key topic = google_pubsub_topic.default.name - labels = each.value.labels + labels = coalesce(each.value.labels, var.labels) ack_deadline_seconds = each.value.ack_deadline_seconds message_retention_duration = each.value.message_retention_duration retain_acked_messages = each.value.retain_acked_messages diff --git a/modules/pubsub/versions.tf b/modules/pubsub/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/pubsub/versions.tf +++ b/modules/pubsub/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/secret-manager/versions.tf b/modules/secret-manager/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/secret-manager/versions.tf +++ b/modules/secret-manager/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/service-directory/versions.tf b/modules/service-directory/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/service-directory/versions.tf +++ b/modules/service-directory/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/source-repository/versions.tf b/modules/source-repository/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/source-repository/versions.tf +++ b/modules/source-repository/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/vpc-sc/README.md b/modules/vpc-sc/README.md index 2bdeebe9fe..fb99c10657 100644 --- a/modules/vpc-sc/README.md +++ b/modules/vpc-sc/README.md @@ -233,7 +233,7 @@ module "test" { resources = ["projects/11111", "projects/111111"] restricted_services = ["storage.googleapis.com"] egress_policies = ["gcs-sa-foo"] - ingress_policies = ["sa-tf-test"] + ingress_policies = ["sa-tf-test-geo", "sa-tf-test"] vpc_accessible_services = { allowed_services = ["storage.googleapis.com"] enable_restriction = true @@ -242,7 +242,7 @@ module "test" { } } } -# tftest modules=1 resources=3 files=a1,a2,e1,i1 inventory=factory.yaml +# tftest modules=1 resources=3 files=a1,a2,e1,i1,i2 inventory=factory.yaml ``` ```yaml @@ -282,12 +282,29 @@ from: - serviceAccount:test-tf@myproject.iam.gserviceaccount.com to: operations: - - service_name: "*" + - service_name: compute.googleapis.com + method_selectors: + - ProjectsService.Get + - RegionsService.Get resources: - "*" # tftest-file id=i1 path=data/ingress-policies/sa-tf-test.yaml ``` +```yaml +from: + access_levels: + - geo-it + identities: + - serviceAccount:test-tf@myproject.iam.gserviceaccount.com +to: + operations: + - service_name: "*" + resources: + - projects/1234567890 +# tftest-file id=i2 path=data/ingress-policies/sa-tf-test-geo.yaml +``` + ## Notes - To remove an access level, first remove the binding between perimeter and the access level in `status` and/or `spec` without removing the access level itself. Once you have run `terraform apply`, you'll then be able to remove the access level and run `terraform apply` again. diff --git a/modules/vpc-sc/factory.tf b/modules/vpc-sc/factory.tf index eca5867a7e..d8a0a53622 100644 --- a/modules/vpc-sc/factory.tf +++ b/modules/vpc-sc/factory.tf @@ -74,7 +74,7 @@ locals { }, try(v.from, {})) to = { operations = [ - for o in try(v.operations, []) : merge({ + for o in try(v.to.operations, []) : merge({ method_selectors = [] permission_selectors = [] service_name = null diff --git a/modules/vpc-sc/versions.tf b/modules/vpc-sc/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/vpc-sc/versions.tf +++ b/modules/vpc-sc/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/modules/workstation-cluster/README.md b/modules/workstation-cluster/README.md index cf45451479..05a0acdea2 100644 --- a/modules/workstation-cluster/README.md +++ b/modules/workstation-cluster/README.md @@ -59,6 +59,9 @@ module "workstation-cluster" { } workstation_configs = { my-workstation-config = { + gce_instance = { + disable_public_ip_addresses = true + } workstations = { my-workstation = { labels = { diff --git a/modules/workstation-cluster/main.tf b/modules/workstation-cluster/main.tf index 07399df4c8..b26a9fe579 100644 --- a/modules/workstation-cluster/main.tf +++ b/modules/workstation-cluster/main.tf @@ -70,8 +70,8 @@ resource "google_workstations_workstation_config" "configs" { pool_size = each.value.gce_instance.pool_size boot_disk_size_gb = each.value.gce_instance.boot_disk_size_gb tags = each.value.gce_instance.tags - disable_public_ip_addresses = each.value.disable_public_ip_addresses - enable_nested_virtualization = each.value.enable_nested_virtualization + disable_public_ip_addresses = each.value.gce_instance.disable_public_ip_addresses + enable_nested_virtualization = each.value.gce_instance.enable_nested_virtualization dynamic "shielded_instance_config" { for_each = each.value.gce_instance.shielded_instance_config == null ? [] : [""] content { @@ -81,7 +81,7 @@ resource "google_workstations_workstation_config" "configs" { } } dynamic "confidential_instance_config" { - for_each = each.value.gce_instance.enable_confidential_compute ? [] : [""] + for_each = each.value.gce_instance.enable_confidential_compute ? [""] : [] content { enable_confidential_compute = true } @@ -114,6 +114,21 @@ resource "google_workstations_workstation_config" "configs" { kms_key_service_account = each.value.encryption_key.kms_key_service_account } } + dynamic "persistent_directories" { + for_each = each.value.persistent_directories + content { + mount_path = persistent_directories.value.mount_path + dynamic "gce_pd" { + for_each = persistent_directories.value.gce_pd == null ? [] : [""] + content { + size_gb = persistent_directories.value.gce_pd.size_gb + fs_type = persistent_directories.value.gce_pd.fs_type + disk_type = persistent_directories.value.gce_pd.disk_type + reclaim_policy = persistent_directories.value.gce_pd.reclaim_policy + } + } + } + } } resource "google_workstations_workstation" "workstations" { diff --git a/modules/workstation-cluster/versions.tf b/modules/workstation-cluster/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/modules/workstation-cluster/versions.tf +++ b/modules/workstation-cluster/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/tests/collectors.py b/tests/collectors.py index 749e192c50..9e26c06774 100644 --- a/tests/collectors.py +++ b/tests/collectors.py @@ -87,8 +87,15 @@ def __init__(self, name, parent, module, inventory, tf_var_files, self.extra_files = extra_files def runtest(self): - s = plan_validator(self.module, self.inventory, self.parent.path.parent, - self.tf_var_files, self.extra_files) + try: + summary = plan_validator(self.module, self.inventory, self.parent.path.parent, + self.tf_var_files, self.extra_files) + except AssertionError: + def full_paths(x): + return [str(self.parent.path.parent / x ) for x in x] + print(f'Error in inventory file: {" ".join(full_paths(self.inventory))}') + print(f'To regenerate inventory run: python tools/plan_summary.py {self.module} {" ".join(full_paths(self.tf_var_files))}') + raise def reportinfo(self): return self.path, None, self.name diff --git a/tests/examples/variables.tf b/tests/examples/variables.tf index 29dc8d8940..d999609b0e 100644 --- a/tests/examples/variables.tf +++ b/tests/examples/variables.tf @@ -84,7 +84,7 @@ variable "subnet_psc_1" { name = "subnet_name" region = "subnet_region" cidr = "subnet_cidr" - self_link = "subnet_self_link" + self_link = "https://www.googleapis.com/compute/v1/projects/my-project/regions/europe-west8/subnetworks/subnet" } } diff --git a/tests/examples_e2e/setup_module/e2e_tests.tfvars.tftpl b/tests/examples_e2e/setup_module/e2e_tests.tfvars.tftpl index 5bb6d779ec..fd63d450fe 100644 --- a/tests/examples_e2e/setup_module/e2e_tests.tfvars.tftpl +++ b/tests/examples_e2e/setup_module/e2e_tests.tfvars.tftpl @@ -37,6 +37,12 @@ subnet = { cidr = "${subnet.ip_cidr_range}" self_link = "${subnet.self_link}" } +subnet_psc_1 = { + name = "${subnet_psc_1.name}" + region = "${subnet_psc_1.region}" + cidr = "${subnet_psc_1.ip_cidr_range}" + self_link = "${subnet_psc_1.self_link}" +} vpc = { name = "${vpc.name}" self_link = "${vpc.self_link}" diff --git a/tests/examples_e2e/setup_module/main.tf b/tests/examples_e2e/setup_module/main.tf index bd48e4fbd9..4e1d1931bf 100644 --- a/tests/examples_e2e/setup_module/main.tf +++ b/tests/examples_e2e/setup_module/main.tf @@ -15,7 +15,8 @@ locals { prefix = "${var.prefix}-${var.timestamp}${var.suffix}" jit_services = [ - "storage.googleapis.com", # no permissions granted by default + "storage.googleapis.com", # no permissions granted by default + "sqladmin.googleapis.com", # roles/cloudsql.serviceAgent ] services = [ # trimmed down list of services, to be extended as needed @@ -35,6 +36,7 @@ locals { "secretmanager.googleapis.com", "servicenetworking.googleapis.com", "serviceusage.googleapis.com", + "sqladmin.googleapis.com", "stackdriver.googleapis.com", "storage-component.googleapis.com", "storage.googleapis.com", @@ -114,6 +116,36 @@ resource "google_compute_subnetwork" "proxy_only_regional" { role = "ACTIVE" } +resource "google_compute_subnetwork" "psc" { + project = google_project.project.project_id + network = google_compute_network.network.name + name = "psc-regional" + region = var.region + ip_cidr_range = "10.0.19.0/24" + purpose = "PRIVATE_SERVICE_CONNECT" +} + +### PSA ### + +resource "google_compute_global_address" "psa_ranges" { + project = google_project.project.project_id + network = google_compute_network.network.id + name = "psa-range" + purpose = "VPC_PEERING" + address_type = "INTERNAL" + address = "10.0.20.0" + prefix_length = 22 +} + +resource "google_service_networking_connection" "psa_connection" { + network = google_compute_network.network.id + service = "servicenetworking.googleapis.com" + reserved_peering_ranges = [google_compute_global_address.psa_ranges.name] + deletion_policy = "ABANDON" +} + +### END OF PSA + resource "google_service_account" "service_account" { account_id = "e2e-service-account" project = google_project.project.project_id @@ -141,6 +173,12 @@ resource "google_project_service_identity" "jit_si" { depends_on = [google_project_service.project_service] } +resource "google_project_iam_binding" "cloudsql_agent" { + members = ["serviceAccount:service-${google_project.project.number}@gcp-sa-cloud-sql.iam.gserviceaccount.com"] + project = google_project.project.project_id + role = "roles/cloudsql.serviceAgent" + depends_on = [google_project_service_identity.jit_si] +} resource "local_file" "terraform_tfvars" { filename = "e2e_tests.tfvars" @@ -168,6 +206,12 @@ resource "local_file" "terraform_tfvars" { ip_cidr_range = google_compute_subnetwork.subnetwork.ip_cidr_range self_link = google_compute_subnetwork.subnetwork.self_link } + subnet_psc_1 = { + name = google_compute_subnetwork.psc.name + region = google_compute_subnetwork.psc.region + ip_cidr_range = google_compute_subnetwork.psc.ip_cidr_range + self_link = google_compute_subnetwork.psc.self_link + } vpc = { name = google_compute_network.network.name self_link = google_compute_network.network.self_link diff --git a/tests/examples_e2e/setup_module/versions.tf b/tests/examples_e2e/setup_module/versions.tf index 3d6a43260a..bc9986b3c7 100644 --- a/tests/examples_e2e/setup_module/versions.tf +++ b/tests/examples_e2e/setup_module/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.24.0, < 6.0.0" # tftest + version = ">= 5.26.0, < 6.0.0" # tftest } } } diff --git a/tests/fast/stages/s0_bootstrap/checklist.yaml b/tests/fast/stages/s0_bootstrap/checklist.yaml index 91fe60eb76..0b1d71d48f 100644 --- a/tests/fast/stages/s0_bootstrap/checklist.yaml +++ b/tests/fast/stages/s0_bootstrap/checklist.yaml @@ -55,9 +55,9 @@ values: module.organization.google_organization_iam_binding.authoritative["roles/cloudasset.owner"]: condition: [] members: - - group:gcp-network-admins@fast.example.com - group:gcp-organization-admins@fast.example.com - group:gcp-security-admins@fast.example.com + - group:gcp-vpc-network-admins@fast.example.com org_id: '123456789012' role: roles/cloudasset.owner module.organization.google_organization_iam_binding.authoritative["roles/cloudsupport.admin"]: @@ -70,8 +70,8 @@ values: condition: [] members: - group:gcp-devops@fast.example.com - - group:gcp-network-admins@fast.example.com - group:gcp-security-admins@fast.example.com + - group:gcp-vpc-network-admins@fast.example.com org_id: '123456789012' role: roles/cloudsupport.techSupportEditor module.organization.google_organization_iam_binding.authoritative["roles/compute.osAdminLogin"]: @@ -131,7 +131,7 @@ values: condition: [] members: - group:gcp-devops@fast.example.com - - group:gcp-network-admins@fast.example.com + - group:gcp-vpc-network-admins@fast.example.com - serviceAccount:fast-prod-bootstrap-0r@fast-prod-iac-core-0.iam.gserviceaccount.com - serviceAccount:fast-prod-resman-0r@fast-prod-iac-core-0.iam.gserviceaccount.com org_id: '123456789012' @@ -240,19 +240,19 @@ values: member: serviceAccount:fast-prod-resman-0r@fast-prod-iac-core-0.iam.gserviceaccount.com org_id: '123456789012' role: roles/billing.viewer - ? module.organization.google_organization_iam_member.bindings["roles/compute.networkAdmin-group:gcp-network-admins@fast.example.com"] + ? module.organization.google_organization_iam_member.bindings["roles/compute.networkAdmin-group:gcp-vpc-network-admins@fast.example.com"] : condition: [] - member: group:gcp-network-admins@fast.example.com + member: group:gcp-vpc-network-admins@fast.example.com org_id: '123456789012' role: roles/compute.networkAdmin - ? module.organization.google_organization_iam_member.bindings["roles/compute.orgFirewallPolicyAdmin-group:gcp-network-admins@fast.example.com"] + ? module.organization.google_organization_iam_member.bindings["roles/compute.orgFirewallPolicyAdmin-group:gcp-vpc-network-admins@fast.example.com"] : condition: [] - member: group:gcp-network-admins@fast.example.com + member: group:gcp-vpc-network-admins@fast.example.com org_id: '123456789012' role: roles/compute.orgFirewallPolicyAdmin - ? module.organization.google_organization_iam_member.bindings["roles/compute.securityAdmin-group:gcp-network-admins@fast.example.com"] + ? module.organization.google_organization_iam_member.bindings["roles/compute.securityAdmin-group:gcp-vpc-network-admins@fast.example.com"] : condition: [] - member: group:gcp-network-admins@fast.example.com + member: group:gcp-vpc-network-admins@fast.example.com org_id: '123456789012' role: roles/compute.securityAdmin ? module.organization.google_organization_iam_member.bindings["roles/compute.viewer-group:gcp-security-admins@fast.example.com"] @@ -260,9 +260,9 @@ values: member: group:gcp-security-admins@fast.example.com org_id: '123456789012' role: roles/compute.viewer - ? module.organization.google_organization_iam_member.bindings["roles/compute.xpnAdmin-group:gcp-network-admins@fast.example.com"] + ? module.organization.google_organization_iam_member.bindings["roles/compute.xpnAdmin-group:gcp-vpc-network-admins@fast.example.com"] : condition: [] - member: group:gcp-network-admins@fast.example.com + member: group:gcp-vpc-network-admins@fast.example.com org_id: '123456789012' role: roles/compute.xpnAdmin ? module.organization.google_organization_iam_member.bindings["roles/container.viewer-group:gcp-security-admins@fast.example.com"] @@ -360,15 +360,15 @@ counts: google_bigquery_dataset: 1 google_bigquery_default_service_account: 3 google_essential_contacts_contact: 3 - google_logging_organization_sink: 3 - google_logging_project_bucket_config: 3 + google_logging_organization_sink: 4 + google_logging_project_bucket_config: 4 google_org_policy_policy: 22 google_organization_iam_binding: 27 google_organization_iam_custom_role: 7 google_organization_iam_member: 35 google_project: 3 google_project_iam_binding: 19 - google_project_iam_member: 6 + google_project_iam_member: 7 google_project_service: 31 google_project_service_identity: 4 google_service_account: 4 @@ -380,5 +380,5 @@ counts: google_storage_project_service_account: 3 google_tags_tag_key: 1 google_tags_tag_value: 1 - modules: 17 - resources: 198 + modules: 18 + resources: 202 diff --git a/tests/fast/stages/s0_bootstrap/iam_by_principals.tfvars b/tests/fast/stages/s0_bootstrap/iam_by_principals.tfvars new file mode 100644 index 0000000000..4ceaffb6ac --- /dev/null +++ b/tests/fast/stages/s0_bootstrap/iam_by_principals.tfvars @@ -0,0 +1,20 @@ +organization = { + domain = "fast.example.com" + id = 123456789012 + customer_id = "C00000000" +} +billing_account = { + id = "000000-111111-222222" +} +essential_contacts = "gcp-organization-admins@fast.example.com" +iam_by_principals = { + "user:other@fast.example.com" = ["roles/browser"] +} +prefix = "fast" +org_policies_config = { + import_defaults = false +} +outputs_location = "/fast-config" +groups = { + gcp-support = "group:gcp-support@example.com" +} diff --git a/tests/fast/stages/s0_bootstrap/iam_by_principals.yaml b/tests/fast/stages/s0_bootstrap/iam_by_principals.yaml new file mode 100644 index 0000000000..83b965d302 --- /dev/null +++ b/tests/fast/stages/s0_bootstrap/iam_by_principals.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. + +values: + module.organization.google_organization_iam_binding.authoritative["roles/browser"]: + condition: [] + members: + - domain:fast.example.com + - user:other@fast.example.com + org_id: '123456789012' + role: roles/browser diff --git a/tests/fast/stages/s0_bootstrap/simple.yaml b/tests/fast/stages/s0_bootstrap/simple.yaml index 904471a061..bdc0ec68cb 100644 --- a/tests/fast/stages/s0_bootstrap/simple.yaml +++ b/tests/fast/stages/s0_bootstrap/simple.yaml @@ -16,9 +16,9 @@ values: module.organization.google_organization_iam_binding.authoritative["roles/cloudsupport.techSupportEditor"]: condition: [] members: - - group:gcp-network-admins@fast.example.com - group:gcp-security-admins@fast.example.com - group:gcp-support@example.com + - group:gcp-vpc-network-admins@fast.example.com org_id: '123456789012' role: roles/cloudsupport.techSupportEditor module.organization.google_organization_iam_binding.authoritative["roles/logging.viewer"]: @@ -39,15 +39,15 @@ counts: google_bigquery_dataset: 1 google_bigquery_default_service_account: 3 google_essential_contacts_contact: 3 - google_logging_organization_sink: 3 - google_logging_project_bucket_config: 3 + google_logging_organization_sink: 4 + google_logging_project_bucket_config: 4 google_org_policy_policy: 22 google_organization_iam_binding: 27 google_organization_iam_custom_role: 7 google_organization_iam_member: 22 google_project: 3 google_project_iam_binding: 19 - google_project_iam_member: 6 + google_project_iam_member: 7 google_project_service: 31 google_project_service_identity: 4 google_service_account: 4 @@ -60,8 +60,8 @@ counts: google_tags_tag_key: 1 google_tags_tag_value: 1 local_file: 7 - modules: 16 - resources: 189 + modules: 17 + resources: 193 outputs: custom_roles: diff --git a/tests/fast/stages/s0_bootstrap/tftest.yaml b/tests/fast/stages/s0_bootstrap/tftest.yaml index 8f415a219a..2643714eb9 100644 --- a/tests/fast/stages/s0_bootstrap/tftest.yaml +++ b/tests/fast/stages/s0_bootstrap/tftest.yaml @@ -25,3 +25,5 @@ tests: - simple.yaml - simple_projects.yaml - simple_sas.yaml + + iam_by_principals: diff --git a/tests/fast/stages/s1_resman/checklist.tfvars b/tests/fast/stages/s1_resman/checklist.tfvars index 88df6b629c..0e303043d1 100644 --- a/tests/fast/stages/s1_resman/checklist.tfvars +++ b/tests/fast/stages/s1_resman/checklist.tfvars @@ -24,7 +24,7 @@ factories_config = { groups = { gcp-billing-admins = "gcp-billing-admins", gcp-devops = "gcp-devops", - gcp-network-admins = "gcp-network-admins", + gcp-network-admins = "gcp-vpc-network-admins", gcp-organization-admins = "gcp-organization-admins", gcp-security-admins = "gcp-security-admins", gcp-support = "gcp-support" diff --git a/tests/fast/stages/s1_resman/simple.tfvars b/tests/fast/stages/s1_resman/simple.tfvars index 9cb8528817..8086201d88 100644 --- a/tests/fast/stages/s1_resman/simple.tfvars +++ b/tests/fast/stages/s1_resman/simple.tfvars @@ -21,7 +21,7 @@ custom_roles = { groups = { gcp-billing-admins = "gcp-billing-admins", gcp-devops = "gcp-devops", - gcp-network-admins = "gcp-network-admins", + gcp-network-admins = "gcp-vpc-network-admins", gcp-organization-admins = "gcp-organization-admins", gcp-security-admins = "gcp-security-admins", gcp-support = "gcp-support" diff --git a/tests/fast/stages/s2_networking_a_peering/simple.tfvars b/tests/fast/stages/s2_networking_a_peering/simple.tfvars index bdff7a433f..9a117062e3 100644 --- a/tests/fast/stages/s2_networking_a_peering/simple.tfvars +++ b/tests/fast/stages/s2_networking_a_peering/simple.tfvars @@ -19,7 +19,7 @@ folder_ids = { networking-prod = null } groups = { - gcp-network-admins = "gcp-network-admins" + gcp-network-admins = "gcp-vpc-network-admins" } service_accounts = { data-platform-dev = "string" diff --git a/tests/fast/stages/s2_networking_b_vpn/simple.tfvars b/tests/fast/stages/s2_networking_b_vpn/simple.tfvars index 24d3a8e039..b9c4ec9ddb 100644 --- a/tests/fast/stages/s2_networking_b_vpn/simple.tfvars +++ b/tests/fast/stages/s2_networking_b_vpn/simple.tfvars @@ -19,7 +19,7 @@ folder_ids = { networking-prod = null } groups = { - gcp-network-admins = "gcp-network-admins" + gcp-network-admins = "gcp-vpc-network-admins" } service_accounts = { data-platform-dev = "string" diff --git a/tests/fast/stages/s2_networking_c_nva/simple.tfvars b/tests/fast/stages/s2_networking_c_nva/simple.tfvars index fca8913f8a..c2a9cef0bd 100644 --- a/tests/fast/stages/s2_networking_c_nva/simple.tfvars +++ b/tests/fast/stages/s2_networking_c_nva/simple.tfvars @@ -19,7 +19,7 @@ folder_ids = { networking-prod = null } groups = { - gcp-network-admins = "gcp-network-admins" + gcp-network-admins = "gcp-vpc-network-admins" } service_accounts = { data-platform-dev = "string" diff --git a/tests/fast/stages/s2_networking_d_separate_envs/simple.tfvars b/tests/fast/stages/s2_networking_d_separate_envs/simple.tfvars index 071011dd5e..8522e2b2f0 100644 --- a/tests/fast/stages/s2_networking_d_separate_envs/simple.tfvars +++ b/tests/fast/stages/s2_networking_d_separate_envs/simple.tfvars @@ -20,7 +20,7 @@ folder_ids = { networking-prod = null } groups = { - gcp-network-admins = "gcp-network-admins" + gcp-network-admins = "gcp-vpc-network-admins" } service_accounts = { data-platform-dev = "string" diff --git a/tests/fast/stages/s2_networking_e_nva_bgp/simple.tfvars b/tests/fast/stages/s2_networking_e_nva_bgp/simple.tfvars index fca8913f8a..c2a9cef0bd 100644 --- a/tests/fast/stages/s2_networking_e_nva_bgp/simple.tfvars +++ b/tests/fast/stages/s2_networking_e_nva_bgp/simple.tfvars @@ -19,7 +19,7 @@ folder_ids = { networking-prod = null } groups = { - gcp-network-admins = "gcp-network-admins" + gcp-network-admins = "gcp-vpc-network-admins" } service_accounts = { data-platform-dev = "string" diff --git a/tests/fast/stages/s2_networking_e_nva_bgp/simple.yaml b/tests/fast/stages/s2_networking_e_nva_bgp/simple.yaml index f0594c4ca6..25ba7ccf9b 100644 --- a/tests/fast/stages/s2_networking_e_nva_bgp/simple.yaml +++ b/tests/fast/stages/s2_networking_e_nva_bgp/simple.yaml @@ -10,7 +10,6 @@ # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and -# limitations under the License. values: google_compute_address.nva_static_ip_dmz["primary-b"]: @@ -113,22 +112,21 @@ values: alert_strategy: [] combiner: OR conditions: - - condition_absent: [] - condition_matched_log: [] - condition_monitoring_query_language: - - duration: 120s - evaluation_missing_data: null - query: - fetch vpn_gateway| { metric vpn.googleapis.com/network/sent_bytes_count; - metric vpn.googleapis.com/network/received_bytes_count }| align rate (1m)| - group_by [metric.tunnel_name]| outer_join 0,0| value val(0) + val(1)| condition - val() > 187.5 "MBy/s" - trigger: - - count: 1 - percent: null - condition_prometheus_query_language: [] - condition_threshold: [] - display_name: VPN Tunnel Bandwidth usage + - condition_absent: [] + condition_matched_log: [] + condition_monitoring_query_language: + - duration: 120s + evaluation_missing_data: null + query: fetch vpn_gateway| { metric vpn.googleapis.com/network/sent_bytes_count; + metric vpn.googleapis.com/network/received_bytes_count }| align rate (1m)| + group_by [metric.tunnel_name]| outer_join 0,0| value val(0) + val(1)| condition + val() > 187.5 "MBy/s" + trigger: + - count: 1 + percent: null + condition_prometheus_query_language: [] + condition_threshold: [] + display_name: VPN Tunnel Bandwidth usage display_name: VPN Tunnel Bandwidth usage documentation: [] enabled: true @@ -141,21 +139,20 @@ values: alert_strategy: [] combiner: OR conditions: - - condition_absent: [] - condition_matched_log: [] - condition_monitoring_query_language: - - duration: 120s - evaluation_missing_data: null - query: - "fetch vpn_gateway| metric vpn.googleapis.com/tunnel_established| group_by - 5m, [value_tunnel_established_max: max(value.tunnel_established)]| every - 5m| condition val() < 1 '1'" - trigger: - - count: 1 - percent: null - condition_prometheus_query_language: [] - condition_threshold: [] - display_name: VPN Tunnel Established + - condition_absent: [] + condition_matched_log: [] + condition_monitoring_query_language: + - duration: 120s + evaluation_missing_data: null + query: 'fetch vpn_gateway| metric vpn.googleapis.com/tunnel_established| group_by + 5m, [value_tunnel_established_max: max(value.tunnel_established)]| every + 5m| condition val() < 1 ''1''' + trigger: + - count: 1 + percent: null + condition_prometheus_query_language: [] + condition_threshold: [] + display_name: VPN Tunnel Established display_name: VPN Tunnel Established documentation: [] enabled: true @@ -165,17 +162,15 @@ values: timeouts: null user_labels: null google_monitoring_dashboard.dashboard["firewall_insights.json"]: - dashboard_json: - '{"displayName":"Firewall Insights Monitoring","gridLayout":{"columns":"2","widgets":[{"title":"Subnet + dashboard_json: '{"displayName":"Firewall Insights Monitoring","gridLayout":{"columns":"2","widgets":[{"title":"Subnet Firewall Hit Counts","xyChart":{"chartOptions":{"mode":"COLOR"},"dataSets":[{"minAlignmentPeriod":"60s","plotType":"LINE","targetAxis":"Y1","timeSeriesQuery":{"timeSeriesFilter":{"aggregation":{"perSeriesAligner":"ALIGN_RATE"},"filter":"metric.type=\"firewallinsights.googleapis.com/subnet/firewall_hit_count\" resource.type=\"gce_subnetwork\"","secondaryAggregation":{}},"unitOverride":"1"}}],"timeshiftDuration":"0s","yAxis":{"label":"y1Axis","scale":"LINEAR"}}},{"title":"VM Firewall Hit Counts","xyChart":{"chartOptions":{"mode":"COLOR"},"dataSets":[{"minAlignmentPeriod":"60s","plotType":"LINE","targetAxis":"Y1","timeSeriesQuery":{"timeSeriesFilter":{"aggregation":{"perSeriesAligner":"ALIGN_RATE"},"filter":"metric.type=\"firewallinsights.googleapis.com/vm/firewall_hit_count\" resource.type=\"gce_instance\"","secondaryAggregation":{}},"unitOverride":"1"}}],"timeshiftDuration":"0s","yAxis":{"label":"y1Axis","scale":"LINEAR"}}}]}}' project: fast2-prod-net-landing-0 timeouts: null - ? google_monitoring_dashboard.dashboard["vpc_and_vpc_peering_group_quotas.json"] - : dashboard_json: - '{"dashboardFilters":[],"displayName":"VPC \u0026 VPC Peering + google_monitoring_dashboard.dashboard["vpc_and_vpc_peering_group_quotas.json"]: + dashboard_json: '{"dashboardFilters":[],"displayName":"VPC \u0026 VPC Peering Group Quotas","labels":{},"mosaicLayout":{"columns":12,"tiles":[{"height":4,"widget":{"title":"Internal network (L4) Load Balancers per VPC Peering Group","xyChart":{"chartOptions":{"mode":"COLOR"},"dataSets":[{"breakdowns":[],"dimensions":[],"measures":[],"plotType":"LINE","targetAxis":"Y1","timeSeriesQuery":{"timeSeriesQueryLanguage":"fetch compute.googleapis.com/VpcNetwork\n|{ metric\n compute.googleapis.com/quota/internal_lb_forwarding_rules_per_peering_group/usage\n | @@ -228,8 +223,7 @@ values: project: fast2-prod-net-landing-0 timeouts: null google_monitoring_dashboard.dashboard["vpn.json"]: - dashboard_json: - '{"displayName":"VPN Monitoring","mosaicLayout":{"columns":12,"tiles":[{"height":4,"widget":{"title":"Number + dashboard_json: '{"displayName":"VPN Monitoring","mosaicLayout":{"columns":12,"tiles":[{"height":4,"widget":{"title":"Number of connections","xyChart":{"chartOptions":{"mode":"COLOR"},"dataSets":[{"minAlignmentPeriod":"60s","plotType":"LINE","targetAxis":"Y1","timeSeriesQuery":{"timeSeriesFilter":{"aggregation":{"perSeriesAligner":"ALIGN_MEAN"},"filter":"metric.type=\"vpn.googleapis.com/gateway/connections\" resource.type=\"vpn_gateway\"","secondaryAggregation":{}},"unitOverride":"1"}}],"timeshiftDuration":"0s","yAxis":{"label":"y1Axis","scale":"LINEAR"}}},"width":4},{"height":4,"widget":{"title":"Tunnel established","xyChart":{"chartOptions":{"mode":"COLOR"},"dataSets":[{"minAlignmentPeriod":"60s","plotType":"LINE","targetAxis":"Y1","timeSeriesQuery":{"timeSeriesFilter":{"aggregation":{"perSeriesAligner":"ALIGN_MEAN"},"filter":"metric.type=\"vpn.googleapis.com/tunnel_established\" @@ -279,9 +273,9 @@ values: source: null temporary_hold: null timeouts: null - ? module.dev-dns-peer-landing-rev-10.google_dns_managed_zone.dns_managed_zone[0] - : cloud_logging_config: - - enable_logging: false + module.dev-dns-peer-landing-rev-10.google_dns_managed_zone.dns_managed_zone[0]: + cloud_logging_config: + - enable_logging: false description: Terraform managed. dns_name: 10.in-addr.arpa. dnssec_config: [] @@ -296,7 +290,7 @@ values: visibility: private module.dev-dns-peer-landing-root.google_dns_managed_zone.dns_managed_zone[0]: cloud_logging_config: - - enable_logging: false + - enable_logging: false description: Terraform managed. dns_name: . dnssec_config: [] @@ -311,7 +305,7 @@ values: visibility: private module.dev-dns-private-zone.google_dns_managed_zone.dns_managed_zone[0]: cloud_logging_config: - - enable_logging: false + - enable_logging: false description: Terraform managed. dns_name: dev.gcp.example.com. dnssec_config: [] @@ -324,23 +318,23 @@ values: service_directory_config: [] timeouts: null visibility: private - ? module.dev-dns-private-zone.google_dns_record_set.dns_record_set["A localhost"] - : managed_zone: dev-gcp-example-com + module.dev-dns-private-zone.google_dns_record_set.dns_record_set["A localhost"]: + managed_zone: dev-gcp-example-com name: localhost.dev.gcp.example.com. project: fast2-dev-net-spoke-0 routing_policy: [] rrdatas: - - 127.0.0.1 + - 127.0.0.1 ttl: 300 type: A - ? module.dev-spoke-firewall.google_compute_firewall.custom-rules["ingress-allow-composer-nodes"] - : allow: - - ports: - - "80" - - "443" - - "3306" - - "3307" - protocol: tcp + module.dev-spoke-firewall.google_compute_firewall.custom-rules["ingress-allow-composer-nodes"]: + allow: + - ports: + - '80' + - '443' + - '3306' + - '3307' + protocol: tcp deny: [] description: Allow traffic to Composer nodes. direction: INGRESS @@ -353,17 +347,17 @@ values: source_ranges: null source_service_accounts: null source_tags: - - composer-worker + - composer-worker target_service_accounts: null target_tags: - - composer-worker - timeouts: null - ? module.dev-spoke-firewall.google_compute_firewall.custom-rules["ingress-allow-dataflow-load"] - : allow: - - ports: - - "12345" - - "12346" - protocol: tcp + - composer-worker + timeouts: null + module.dev-spoke-firewall.google_compute_firewall.custom-rules["ingress-allow-dataflow-load"]: + allow: + - ports: + - '12345' + - '12346' + protocol: tcp deny: [] description: Allow traffic to Dataflow nodes. direction: INGRESS @@ -376,37 +370,37 @@ values: source_ranges: null source_service_accounts: null source_tags: - - dataflow + - dataflow target_service_accounts: null target_tags: - - dataflow + - dataflow timeouts: null - ? module.dev-spoke-firewall.google_compute_firewall.custom-rules["ingress-default-deny"] - : allow: [] + module.dev-spoke-firewall.google_compute_firewall.custom-rules["ingress-default-deny"]: + allow: [] deny: - - ports: [] - protocol: all + - ports: [] + protocol: all description: Deny and log any unmatched ingress traffic. direction: INGRESS disabled: false log_config: - - metadata: EXCLUDE_ALL_METADATA + - metadata: EXCLUDE_ALL_METADATA name: ingress-default-deny network: dev-spoke-0 priority: 65535 project: fast2-dev-net-spoke-0 source_ranges: - - 0.0.0.0/0 + - 0.0.0.0/0 source_service_accounts: null source_tags: null target_service_accounts: null target_tags: null timeouts: null - ? module.dev-spoke-project.google_compute_shared_vpc_host_project.shared_vpc_host[0] - : project: fast2-dev-net-spoke-0 + module.dev-spoke-project.google_compute_shared_vpc_host_project.shared_vpc_host[0]: + project: fast2-dev-net-spoke-0 timeouts: null - ? module.dev-spoke-project.google_monitoring_monitored_project.primary["fast2-prod-net-landing-0"] - : metrics_scope: fast2-prod-net-landing-0 + module.dev-spoke-project.google_monitoring_monitored_project.primary["fast2-prod-net-landing-0"]: + metrics_scope: fast2-prod-net-landing-0 name: fast2-dev-net-spoke-0 timeouts: null module.dev-spoke-project.google_project.project[0]: @@ -419,69 +413,69 @@ values: project_id: fast2-dev-net-spoke-0 skip_delete: false timeouts: null - ? module.dev-spoke-project.google_project_iam_binding.authoritative["roles/dns.admin"] - : condition: [] + module.dev-spoke-project.google_project_iam_binding.authoritative["roles/dns.admin"]: + condition: [] members: - - serviceAccount:string + - serviceAccount:string project: fast2-dev-net-spoke-0 role: roles/dns.admin - ? module.dev-spoke-project.google_project_iam_binding.bindings["sa_delegated_grants"] - : condition: - - description: Development host project delegated grants. - expression: api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly(['roles/composer.sharedVpcAgent','roles/compute.networkUser','roles/compute.networkViewer','roles/container.hostServiceAgentUser','roles/multiclusterservicediscovery.serviceAgent','roles/vpcaccess.user']) - title: dev_stage3_sa_delegated_grants + module.dev-spoke-project.google_project_iam_binding.bindings["sa_delegated_grants"]: + condition: + - description: Development host project delegated grants. + expression: api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly(['roles/composer.sharedVpcAgent','roles/compute.networkUser','roles/compute.networkViewer','roles/container.hostServiceAgentUser','roles/multiclusterservicediscovery.serviceAgent','roles/vpcaccess.user']) + title: dev_stage3_sa_delegated_grants members: - - serviceAccount:string + - serviceAccount:string project: fast2-dev-net-spoke-0 role: roles/resourcemanager.projectIamAdmin module.dev-spoke-project.google_project_iam_member.servicenetworking[0]: condition: [] project: fast2-dev-net-spoke-0 role: roles/servicenetworking.serviceAgent - ? module.dev-spoke-project.google_project_service.project_services["compute.googleapis.com"] - : disable_dependent_services: false + module.dev-spoke-project.google_project_service.project_services["compute.googleapis.com"]: + disable_dependent_services: false disable_on_destroy: false project: fast2-dev-net-spoke-0 service: compute.googleapis.com timeouts: null - ? module.dev-spoke-project.google_project_service.project_services["dns.googleapis.com"] - : disable_dependent_services: false + module.dev-spoke-project.google_project_service.project_services["dns.googleapis.com"]: + disable_dependent_services: false disable_on_destroy: false project: fast2-dev-net-spoke-0 service: dns.googleapis.com timeouts: null - ? module.dev-spoke-project.google_project_service.project_services["iap.googleapis.com"] - : disable_dependent_services: false + module.dev-spoke-project.google_project_service.project_services["iap.googleapis.com"]: + disable_dependent_services: false disable_on_destroy: false project: fast2-dev-net-spoke-0 service: iap.googleapis.com timeouts: null - ? module.dev-spoke-project.google_project_service.project_services["networkmanagement.googleapis.com"] - : disable_dependent_services: false + module.dev-spoke-project.google_project_service.project_services["networkmanagement.googleapis.com"]: + disable_dependent_services: false disable_on_destroy: false project: fast2-dev-net-spoke-0 service: networkmanagement.googleapis.com timeouts: null - ? module.dev-spoke-project.google_project_service.project_services["servicenetworking.googleapis.com"] - : disable_dependent_services: false + module.dev-spoke-project.google_project_service.project_services["servicenetworking.googleapis.com"]: + disable_dependent_services: false disable_on_destroy: false project: fast2-dev-net-spoke-0 service: servicenetworking.googleapis.com timeouts: null - ? module.dev-spoke-project.google_project_service.project_services["stackdriver.googleapis.com"] - : disable_dependent_services: false + module.dev-spoke-project.google_project_service.project_services["stackdriver.googleapis.com"]: + disable_dependent_services: false disable_on_destroy: false project: fast2-dev-net-spoke-0 service: stackdriver.googleapis.com timeouts: null - ? module.dev-spoke-project.google_project_service.project_services["vpcaccess.googleapis.com"] - : disable_dependent_services: false + module.dev-spoke-project.google_project_service.project_services["vpcaccess.googleapis.com"]: + disable_dependent_services: false disable_on_destroy: false project: fast2-dev-net-spoke-0 service: vpcaccess.googleapis.com timeouts: null - ? module.dev-spoke-project.google_project_service_identity.jit_si["iap.googleapis.com"] - : project: fast2-dev-net-spoke-0 + module.dev-spoke-project.google_project_service_identity.jit_si["iap.googleapis.com"]: + project: fast2-dev-net-spoke-0 service: iap.googleapis.com timeouts: null module.dev-spoke-project.google_project_service_identity.servicenetworking[0]: @@ -525,8 +519,8 @@ values: project: fast2-dev-net-spoke-0 tags: null timeouts: null - ? module.dev-spoke-vpc.google_compute_subnetwork.subnetwork["europe-west1/dev-dataplatform"] - : description: Default subnet for dev Data Platform + module.dev-spoke-vpc.google_compute_subnetwork.subnetwork["europe-west1/dev-dataplatform"]: + description: Default subnet for dev Data Platform ip_cidr_range: 10.68.2.0/24 ipv6_access_type: null log_config: [] @@ -537,13 +531,13 @@ values: region: europe-west1 role: null secondary_ip_range: - - ip_cidr_range: 100.69.0.0/16 - range_name: pods - - ip_cidr_range: 100.71.2.0/24 - range_name: services + - ip_cidr_range: 100.69.0.0/16 + range_name: pods + - ip_cidr_range: 100.71.2.0/24 + range_name: services timeouts: null - ? module.dev-spoke-vpc.google_compute_subnetwork.subnetwork["europe-west1/dev-default"] - : description: Default europe-west1 subnet for dev + module.dev-spoke-vpc.google_compute_subnetwork.subnetwork["europe-west1/dev-default"]: + description: Default europe-west1 subnet for dev ip_cidr_range: 10.68.0.0/24 ipv6_access_type: null log_config: [] @@ -555,8 +549,8 @@ values: role: null secondary_ip_range: [] timeouts: null - ? module.dev-spoke-vpc.google_compute_subnetwork.subnetwork["europe-west1/dev-gke-nodes"] - : description: Default subnet for prod gke nodes + module.dev-spoke-vpc.google_compute_subnetwork.subnetwork["europe-west1/dev-gke-nodes"]: + description: Default subnet for prod gke nodes ip_cidr_range: 10.68.1.0/24 ipv6_access_type: null log_config: [] @@ -567,13 +561,13 @@ values: region: europe-west1 role: null secondary_ip_range: - - ip_cidr_range: 100.68.0.0/16 - range_name: pods - - ip_cidr_range: 100.71.1.0/24 - range_name: services + - ip_cidr_range: 100.68.0.0/16 + range_name: pods + - ip_cidr_range: 100.71.1.0/24 + range_name: services timeouts: null - ? module.dev-spoke-vpc.google_compute_subnetwork.subnetwork["europe-west4/dev-default"] - : description: Default europe-west4 subnet for dev + module.dev-spoke-vpc.google_compute_subnetwork.subnetwork["europe-west4/dev-default"]: + description: Default europe-west4 subnet for dev ip_cidr_range: 10.84.0.0/24 ipv6_access_type: null log_config: [] @@ -592,14 +586,14 @@ values: enable_logging: true name: dev-spoke-0 networks: - - {} + - {} project: fast2-dev-net-spoke-0 timeouts: null - ? module.dmz-firewall.google_compute_firewall.custom-rules["allow-hc-nva-ssh-dmz"] - : allow: - - ports: - - "22" - protocol: tcp + module.dmz-firewall.google_compute_firewall.custom-rules["allow-hc-nva-ssh-dmz"]: + allow: + - ports: + - '22' + protocol: tcp deny: [] description: Allow traffic from Google healthchecks to NVA appliances direction: INGRESS @@ -610,20 +604,20 @@ values: priority: 1000 project: fast2-prod-net-landing-0 source_ranges: - - 130.211.0.0/22 - - 209.85.152.0/22 - - 209.85.204.0/22 - - 35.191.0.0/16 + - 130.211.0.0/22 + - 209.85.152.0/22 + - 209.85.204.0/22 + - 35.191.0.0/16 source_service_accounts: null source_tags: null target_service_accounts: null target_tags: null timeouts: null - ? module.dmz-firewall.google_compute_firewall.custom-rules["allow-ncc-nva-bgp-dmz"] - : allow: - - ports: - - "179" - protocol: tcp + module.dmz-firewall.google_compute_firewall.custom-rules["allow-ncc-nva-bgp-dmz"]: + allow: + - ports: + - '179' + protocol: tcp deny: [] description: Allow BGP traffic from NCC Cloud Routers to NVAs direction: INGRESS @@ -634,21 +628,21 @@ values: priority: 1000 project: fast2-prod-net-landing-0 source_ranges: - - 10.128.0.201/32 - - 10.128.0.202/32 - - 10.128.32.201/32 - - 10.128.32.202/32 + - 10.128.0.201/32 + - 10.128.0.202/32 + - 10.128.32.201/32 + - 10.128.32.202/32 source_service_accounts: null source_tags: null target_service_accounts: null target_tags: - - nva + - nva timeouts: null - ? module.dmz-firewall.google_compute_firewall.custom-rules["allow-nva-nva-bgp-dmz"] - : allow: - - ports: - - "179" - protocol: tcp + module.dmz-firewall.google_compute_firewall.custom-rules["allow-nva-nva-bgp-dmz"]: + allow: + - ports: + - '179' + protocol: tcp deny: [] description: Allow BGP traffic from cross-regional NVAs direction: INGRESS @@ -661,27 +655,27 @@ values: source_ranges: null source_service_accounts: null source_tags: - - nva + - nva target_service_accounts: null target_tags: - - nva + - nva timeouts: null - ? module.dmz-firewall.google_compute_firewall.custom-rules["dmz-ingress-default-deny"] - : allow: [] + module.dmz-firewall.google_compute_firewall.custom-rules["dmz-ingress-default-deny"]: + allow: [] deny: - - ports: [] - protocol: all + - ports: [] + protocol: all description: Deny and log any unmatched ingress traffic. direction: INGRESS disabled: false log_config: - - metadata: EXCLUDE_ALL_METADATA + - metadata: EXCLUDE_ALL_METADATA name: dmz-ingress-default-deny network: prod-dmz-0 priority: 65535 project: fast2-prod-net-landing-0 source_ranges: - - 0.0.0.0/0 + - 0.0.0.0/0 source_service_accounts: null source_tags: null target_service_accounts: null @@ -698,8 +692,8 @@ values: project: fast2-prod-net-landing-0 routing_mode: GLOBAL timeouts: null - ? module.dmz-vpc.google_compute_subnetwork.subnetwork["europe-west1/dmz-default"] - : description: Default europe-west1 subnet for DMZ + module.dmz-vpc.google_compute_subnetwork.subnetwork["europe-west1/dmz-default"]: + description: Default europe-west1 subnet for DMZ ip_cidr_range: 10.64.128.0/24 ipv6_access_type: null log_config: [] @@ -711,8 +705,8 @@ values: role: null secondary_ip_range: [] timeouts: null - ? module.dmz-vpc.google_compute_subnetwork.subnetwork["europe-west4/dmz-default"] - : description: Default europe-west4 subnet for DMZ + module.dmz-vpc.google_compute_subnetwork.subnetwork["europe-west4/dmz-default"]: + description: Default europe-west4 subnet for DMZ ip_cidr_range: 10.80.128.0/24 ipv6_access_type: null log_config: [] @@ -731,116 +725,117 @@ values: enable_logging: true name: prod-dmz-0 networks: - - {} + - {} project: fast2-prod-net-landing-0 timeouts: null module.firewall-policy-default.google_compute_firewall_policy.hierarchical[0]: description: null short_name: net-default timeouts: null - ? module.firewall-policy-default.google_compute_firewall_policy_rule.hierarchical["ingress/allow-healthchecks"] - : action: allow - description: Enable HTTP and HTTPS healthchecks + module.firewall-policy-default.google_compute_firewall_policy_rule.hierarchical["ingress/allow-healthchecks"]: + action: allow + description: Enable SSH, HTTP and HTTPS healthchecks direction: INGRESS disabled: false enable_logging: null match: - - dest_address_groups: null - dest_fqdns: null - dest_ip_ranges: null - dest_region_codes: null - dest_threat_intelligences: null - layer4_configs: - - ip_protocol: tcp - ports: - - "80" - - "443" - src_address_groups: null - src_fqdns: null - src_ip_ranges: - - 35.191.0.0/16 - - 130.211.0.0/22 - - 209.85.152.0/22 - - 209.85.204.0/22 - src_region_codes: null - src_threat_intelligences: null + - dest_address_groups: null + dest_fqdns: null + dest_ip_ranges: null + dest_region_codes: null + dest_threat_intelligences: null + layer4_configs: + - ip_protocol: tcp + ports: + - '22' + - '80' + - '443' + src_address_groups: null + src_fqdns: null + src_ip_ranges: + - 35.191.0.0/16 + - 130.211.0.0/22 + - 209.85.152.0/22 + - 209.85.204.0/22 + src_region_codes: null + src_threat_intelligences: null priority: 1001 target_resources: null target_service_accounts: null timeouts: null - ? module.firewall-policy-default.google_compute_firewall_policy_rule.hierarchical["ingress/allow-icmp"] - : action: allow + module.firewall-policy-default.google_compute_firewall_policy_rule.hierarchical["ingress/allow-icmp"]: + action: allow description: Enable ICMP direction: INGRESS disabled: false enable_logging: null match: - - dest_address_groups: null - dest_fqdns: null - dest_ip_ranges: null - dest_region_codes: null - dest_threat_intelligences: null - layer4_configs: - - ip_protocol: icmp - ports: [] - src_address_groups: null - src_fqdns: null - src_ip_ranges: - - 0.0.0.0/0 - src_region_codes: null - src_threat_intelligences: null + - dest_address_groups: null + dest_fqdns: null + dest_ip_ranges: null + dest_region_codes: null + dest_threat_intelligences: null + layer4_configs: + - ip_protocol: icmp + ports: [] + src_address_groups: null + src_fqdns: null + src_ip_ranges: + - 0.0.0.0/0 + src_region_codes: null + src_threat_intelligences: null priority: 1003 target_resources: null target_service_accounts: null timeouts: null - ? module.firewall-policy-default.google_compute_firewall_policy_rule.hierarchical["ingress/allow-nat-ranges"] - : action: allow + module.firewall-policy-default.google_compute_firewall_policy_rule.hierarchical["ingress/allow-nat-ranges"]: + action: allow description: Enable NAT ranges for VPC serverless connector direction: INGRESS disabled: false enable_logging: null match: - - dest_address_groups: null - dest_fqdns: null - dest_ip_ranges: null - dest_region_codes: null - dest_threat_intelligences: null - layer4_configs: - - ip_protocol: all - ports: null - src_address_groups: null - src_fqdns: null - src_ip_ranges: - - 107.178.230.64/26 - - 35.199.224.0/19 - src_region_codes: null - src_threat_intelligences: null + - dest_address_groups: null + dest_fqdns: null + dest_ip_ranges: null + dest_region_codes: null + dest_threat_intelligences: null + layer4_configs: + - ip_protocol: all + ports: null + src_address_groups: null + src_fqdns: null + src_ip_ranges: + - 107.178.230.64/26 + - 35.199.224.0/19 + src_region_codes: null + src_threat_intelligences: null priority: 1004 target_resources: null target_service_accounts: null timeouts: null - ? module.firewall-policy-default.google_compute_firewall_policy_rule.hierarchical["ingress/allow-ssh-from-iap"] - : action: allow + module.firewall-policy-default.google_compute_firewall_policy_rule.hierarchical["ingress/allow-ssh-from-iap"]: + action: allow description: Enable SSH from IAP direction: INGRESS disabled: false enable_logging: true match: - - dest_address_groups: null - dest_fqdns: null - dest_ip_ranges: null - dest_region_codes: null - dest_threat_intelligences: null - layer4_configs: - - ip_protocol: tcp - ports: - - "22" - src_address_groups: null - src_fqdns: null - src_ip_ranges: - - 35.235.240.0/20 - src_region_codes: null - src_threat_intelligences: null + - dest_address_groups: null + dest_fqdns: null + dest_ip_ranges: null + dest_region_codes: null + dest_threat_intelligences: null + layer4_configs: + - ip_protocol: tcp + ports: + - '22' + src_address_groups: null + src_fqdns: null + src_ip_ranges: + - 35.235.240.0/20 + src_region_codes: null + src_threat_intelligences: null priority: 1002 target_resources: null target_service_accounts: null @@ -848,27 +843,27 @@ values: module.folder.google_compute_firewall_policy_association.default[0]: name: default timeouts: null - ? module.folder.google_essential_contacts_contact.contact["gcp-network-admins@fast.example.com"] - : email: gcp-network-admins@fast.example.com + module.folder.google_essential_contacts_contact.contact["gcp-network-admins@fast.example.com"]: + email: gcp-network-admins@fast.example.com language_tag: en notification_category_subscriptions: - - ALL + - ALL timeouts: null module.folder.google_folder.folder[0]: display_name: Networking parent: organizations/123456789012 timeouts: null - ? module.landing-dns-fwd-onprem-example[0].google_dns_managed_zone.dns_managed_zone[0] - : cloud_logging_config: - - enable_logging: false + module.landing-dns-fwd-onprem-example[0].google_dns_managed_zone.dns_managed_zone[0]: + cloud_logging_config: + - enable_logging: false description: Terraform managed. dns_name: onprem.example.com. dnssec_config: [] force_destroy: false forwarding_config: - - target_name_servers: - - forwarding_path: "" - ipv4_address: 10.10.10.10 + - target_name_servers: + - forwarding_path: '' + ipv4_address: 10.10.10.10 labels: null name: example-com peering_config: [] @@ -877,17 +872,17 @@ values: service_directory_config: [] timeouts: null visibility: private - ? module.landing-dns-fwd-onprem-rev-10[0].google_dns_managed_zone.dns_managed_zone[0] - : cloud_logging_config: - - enable_logging: false + module.landing-dns-fwd-onprem-rev-10[0].google_dns_managed_zone.dns_managed_zone[0]: + cloud_logging_config: + - enable_logging: false description: Terraform managed. dns_name: 10.in-addr.arpa. dnssec_config: [] force_destroy: false forwarding_config: - - target_name_servers: - - forwarding_path: "" - ipv4_address: 10.10.10.10 + - target_name_servers: + - forwarding_path: '' + ipv4_address: 10.10.10.10 labels: null name: root-reverse-10 peering_config: [] @@ -900,496 +895,496 @@ values: description: Terraform managed. gke_clusters: [] networks: - - {} - - {} + - {} + - {} project: fast2-prod-net-landing-0 response_policy_name: googleapis timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["accounts"] - : behavior: null + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["accounts"]: + behavior: null dns_name: accounts.google.com. local_data: - - local_datas: - - name: accounts.google.com. - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: accounts.google.com. + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: accounts timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["backupdr-cloud"] - : behavior: null + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["backupdr-cloud"]: + behavior: null dns_name: backupdr.cloud.google.com. local_data: - - local_datas: - - name: backupdr.cloud.google.com. - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: backupdr.cloud.google.com. + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: backupdr-cloud timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["backupdr-cloud-all"] - : behavior: null - dns_name: "*.backupdr.cloud.google.com." + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["backupdr-cloud-all"]: + behavior: null + dns_name: '*.backupdr.cloud.google.com.' local_data: - - local_datas: - - name: "*.backupdr.cloud.google.com." - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: '*.backupdr.cloud.google.com.' + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: backupdr-cloud-all timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["backupdr-gu"] - : behavior: null + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["backupdr-gu"]: + behavior: null dns_name: backupdr.googleusercontent.google.com. local_data: - - local_datas: - - name: backupdr.googleusercontent.google.com. - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: backupdr.googleusercontent.google.com. + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: backupdr-gu timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["backupdr-gu-all"] - : behavior: null - dns_name: "*.backupdr.googleusercontent.google.com." + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["backupdr-gu-all"]: + behavior: null + dns_name: '*.backupdr.googleusercontent.google.com.' local_data: - - local_datas: - - name: "*.backupdr.googleusercontent.google.com." - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: '*.backupdr.googleusercontent.google.com.' + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: backupdr-gu-all timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["cloudfunctions"] - : behavior: null - dns_name: "*.cloudfunctions.net." + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["cloudfunctions"]: + behavior: null + dns_name: '*.cloudfunctions.net.' local_data: - - local_datas: - - name: "*.cloudfunctions.net." - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: '*.cloudfunctions.net.' + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: cloudfunctions timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["cloudproxy"] - : behavior: null - dns_name: "*.cloudproxy.app." + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["cloudproxy"]: + behavior: null + dns_name: '*.cloudproxy.app.' local_data: - - local_datas: - - name: "*.cloudproxy.app." - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: '*.cloudproxy.app.' + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: cloudproxy timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["composer-cloud-all"] - : behavior: null - dns_name: "*.composer.cloud.google.com." + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["composer-cloud-all"]: + behavior: null + dns_name: '*.composer.cloud.google.com.' local_data: - - local_datas: - - name: "*.composer.cloud.google.com." - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: '*.composer.cloud.google.com.' + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: composer-cloud-all timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["composer-gu-all"] - : behavior: null - dns_name: "*.composer.googleusercontent.com." + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["composer-gu-all"]: + behavior: null + dns_name: '*.composer.googleusercontent.com.' local_data: - - local_datas: - - name: "*.composer.googleusercontent.com." - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: '*.composer.googleusercontent.com.' + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: composer-gu-all timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["datafusion-all"] - : behavior: null - dns_name: "*.datafusion.cloud.google.com." + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["datafusion-all"]: + behavior: null + dns_name: '*.datafusion.cloud.google.com.' local_data: - - local_datas: - - name: "*.datafusion.cloud.google.com." - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: '*.datafusion.cloud.google.com.' + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: datafusion-all timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["datafusion-gu-all"] - : behavior: null - dns_name: "*.datafusion.googleusercontent.com." + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["datafusion-gu-all"]: + behavior: null + dns_name: '*.datafusion.googleusercontent.com.' local_data: - - local_datas: - - name: "*.datafusion.googleusercontent.com." - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: '*.datafusion.googleusercontent.com.' + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: datafusion-gu-all timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["dataproc"] - : behavior: null + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["dataproc"]: + behavior: null dns_name: dataproc.cloud.google.com. local_data: - - local_datas: - - name: dataproc.cloud.google.com. - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: dataproc.cloud.google.com. + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: dataproc timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["dataproc-all"] - : behavior: null - dns_name: "*.dataproc.cloud.google.com." + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["dataproc-all"]: + behavior: null + dns_name: '*.dataproc.cloud.google.com.' local_data: - - local_datas: - - name: "*.dataproc.cloud.google.com." - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: '*.dataproc.cloud.google.com.' + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: dataproc-all timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["dataproc-gu"] - : behavior: null + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["dataproc-gu"]: + behavior: null dns_name: dataproc.googleusercontent.com. local_data: - - local_datas: - - name: dataproc.googleusercontent.com. - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: dataproc.googleusercontent.com. + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: dataproc-gu timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["dataproc-gu-all"] - : behavior: null - dns_name: "*.dataproc.googleusercontent.com." + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["dataproc-gu-all"]: + behavior: null + dns_name: '*.dataproc.googleusercontent.com.' local_data: - - local_datas: - - name: "*.dataproc.googleusercontent.com." - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: '*.dataproc.googleusercontent.com.' + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: dataproc-gu-all timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["dl"] - : behavior: null + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["dl"]: + behavior: null dns_name: dl.google.com. local_data: - - local_datas: - - name: dl.google.com. - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: dl.google.com. + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: dl timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["gcr"] - : behavior: null + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["gcr"]: + behavior: null dns_name: gcr.io. local_data: - - local_datas: - - name: gcr.io. - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: gcr.io. + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: gcr timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["gcr-all"] - : behavior: null - dns_name: "*.gcr.io." + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["gcr-all"]: + behavior: null + dns_name: '*.gcr.io.' local_data: - - local_datas: - - name: "*.gcr.io." - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: '*.gcr.io.' + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: gcr-all timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["googleapis-all"] - : behavior: null - dns_name: "*.googleapis.com." + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["googleapis-all"]: + behavior: null + dns_name: '*.googleapis.com.' local_data: - - local_datas: - - name: "*.googleapis.com." - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: '*.googleapis.com.' + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: googleapis-all timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["googleapis-private"] - : behavior: null + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["googleapis-private"]: + behavior: null dns_name: private.googleapis.com. local_data: - - local_datas: - - name: private.googleapis.com. - rrdatas: - - 199.36.153.8 - - 199.36.153.9 - - 199.36.153.10 - - 199.36.153.11 - ttl: null - type: A + - local_datas: + - name: private.googleapis.com. + rrdatas: + - 199.36.153.8 + - 199.36.153.9 + - 199.36.153.10 + - 199.36.153.11 + ttl: null + type: A project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: googleapis-private timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["googleapis-restricted"] - : behavior: null + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["googleapis-restricted"]: + behavior: null dns_name: restricted.googleapis.com. local_data: - - local_datas: - - name: restricted.googleapis.com. - rrdatas: - - 199.36.153.4 - - 199.36.153.5 - - 199.36.153.6 - - 199.36.153.7 - ttl: null - type: A + - local_datas: + - name: restricted.googleapis.com. + rrdatas: + - 199.36.153.4 + - 199.36.153.5 + - 199.36.153.6 + - 199.36.153.7 + ttl: null + type: A project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: googleapis-restricted timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["gstatic-all"] - : behavior: null - dns_name: "*.gstatic.com." + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["gstatic-all"]: + behavior: null + dns_name: '*.gstatic.com.' local_data: - - local_datas: - - name: "*.gstatic.com." - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: '*.gstatic.com.' + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: gstatic-all timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["kernels-gu"] - : behavior: null + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["kernels-gu"]: + behavior: null dns_name: kernels.googleusercontent.com. local_data: - - local_datas: - - name: kernels.googleusercontent.com. - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: kernels.googleusercontent.com. + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: kernels-gu timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["kernels-gu-all"] - : behavior: null - dns_name: "*.kernels.googleusercontent.com." + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["kernels-gu-all"]: + behavior: null + dns_name: '*.kernels.googleusercontent.com.' local_data: - - local_datas: - - name: "*.kernels.googleusercontent.com." - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: '*.kernels.googleusercontent.com.' + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: kernels-gu-all timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["notebooks-all"] - : behavior: null - dns_name: "*.notebooks.cloud.google.com." + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["notebooks-all"]: + behavior: null + dns_name: '*.notebooks.cloud.google.com.' local_data: - - local_datas: - - name: "*.notebooks.cloud.google.com." - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: '*.notebooks.cloud.google.com.' + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: notebooks-all timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["notebooks-gu-all"] - : behavior: null - dns_name: "*.notebooks.googleusercontent.com." + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["notebooks-gu-all"]: + behavior: null + dns_name: '*.notebooks.googleusercontent.com.' local_data: - - local_datas: - - name: "*.notebooks.googleusercontent.com." - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: '*.notebooks.googleusercontent.com.' + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: notebooks-gu-all timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["packages-cloud"] - : behavior: null + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["packages-cloud"]: + behavior: null dns_name: packages.cloud.google.com. local_data: - - local_datas: - - name: packages.cloud.google.com. - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: packages.cloud.google.com. + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: packages-cloud timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["packages-cloud-all"] - : behavior: null - dns_name: "*.packages.cloud.google.com." + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["packages-cloud-all"]: + behavior: null + dns_name: '*.packages.cloud.google.com.' local_data: - - local_datas: - - name: "*.packages.cloud.google.com." - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: '*.packages.cloud.google.com.' + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: packages-cloud-all timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["pkgdev"] - : behavior: null + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["pkgdev"]: + behavior: null dns_name: pkg.dev. local_data: - - local_datas: - - name: pkg.dev. - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: pkg.dev. + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: pkgdev timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["pkgdev-all"] - : behavior: null - dns_name: "*.pkg.dev." + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["pkgdev-all"]: + behavior: null + dns_name: '*.pkg.dev.' local_data: - - local_datas: - - name: "*.pkg.dev." - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: '*.pkg.dev.' + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: pkgdev-all timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["pkigoog"] - : behavior: null + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["pkigoog"]: + behavior: null dns_name: pki.goog. local_data: - - local_datas: - - name: pki.goog. - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: pki.goog. + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: pkigoog timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["pkigoog-all"] - : behavior: null - dns_name: "*.pki.goog." + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["pkigoog-all"]: + behavior: null + dns_name: '*.pki.goog.' local_data: - - local_datas: - - name: "*.pki.goog." - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: '*.pki.goog.' + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: pkigoog-all timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["run-all"] - : behavior: null - dns_name: "*.run.app." + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["run-all"]: + behavior: null + dns_name: '*.run.app.' local_data: - - local_datas: - - name: "*.run.app." - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: '*.run.app.' + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: run-all timeouts: null - ? module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["source"] - : behavior: null + module.landing-dns-policy-googleapis.google_dns_response_policy_rule.default["source"]: + behavior: null dns_name: source.developers.google.com. local_data: - - local_datas: - - name: source.developers.google.com. - rrdatas: - - private.googleapis.com. - ttl: null - type: CNAME + - local_datas: + - name: source.developers.google.com. + rrdatas: + - private.googleapis.com. + ttl: null + type: CNAME project: fast2-prod-net-landing-0 response_policy: googleapis rule_name: source timeouts: null module.landing-dns-priv-gcp.google_dns_managed_zone.dns_managed_zone[0]: cloud_logging_config: - - enable_logging: false + - enable_logging: false description: Terraform managed. dns_name: gcp.example.com. dnssec_config: [] @@ -1402,20 +1397,20 @@ values: service_directory_config: [] timeouts: null visibility: private - ? module.landing-dns-priv-gcp.google_dns_record_set.dns_record_set["A localhost"] - : managed_zone: gcp-example-com + module.landing-dns-priv-gcp.google_dns_record_set.dns_record_set["A localhost"]: + managed_zone: gcp-example-com name: localhost.gcp.example.com. project: fast2-prod-net-landing-0 routing_policy: [] rrdatas: - - 127.0.0.1 + - 127.0.0.1 ttl: 300 type: A - ? module.landing-firewall.google_compute_firewall.custom-rules["allow-hc-nva-ssh-landing"] - : allow: - - ports: - - "22" - protocol: tcp + module.landing-firewall.google_compute_firewall.custom-rules["allow-hc-nva-ssh-landing"]: + allow: + - ports: + - '22' + protocol: tcp deny: [] description: Allow traffic from Google healthchecks to NVA appliances direction: INGRESS @@ -1426,20 +1421,20 @@ values: priority: 1000 project: fast2-prod-net-landing-0 source_ranges: - - 130.211.0.0/22 - - 209.85.152.0/22 - - 209.85.204.0/22 - - 35.191.0.0/16 + - 130.211.0.0/22 + - 209.85.152.0/22 + - 209.85.204.0/22 + - 35.191.0.0/16 source_service_accounts: null source_tags: null target_service_accounts: null target_tags: null timeouts: null - ? module.landing-firewall.google_compute_firewall.custom-rules["allow-ncc-nva-bgp-landing"] - : allow: - - ports: - - "179" - protocol: tcp + module.landing-firewall.google_compute_firewall.custom-rules["allow-ncc-nva-bgp-landing"]: + allow: + - ports: + - '179' + protocol: tcp deny: [] description: Allow BGP traffic from NCC Cloud Routers to NVAs direction: INGRESS @@ -1450,21 +1445,21 @@ values: priority: 1000 project: fast2-prod-net-landing-0 source_ranges: - - 10.128.64.201/32 - - 10.128.64.202/32 - - 10.128.96.201/32 - - 10.128.96.202/32 + - 10.128.64.201/32 + - 10.128.64.202/32 + - 10.128.96.201/32 + - 10.128.96.202/32 source_service_accounts: null source_tags: null target_service_accounts: null target_tags: - - nva + - nva timeouts: null - ? module.landing-firewall.google_compute_firewall.custom-rules["allow-onprem-probes-landing-example"] - : allow: - - ports: - - "12345" - protocol: tcp + module.landing-firewall.google_compute_firewall.custom-rules["allow-onprem-probes-landing-example"]: + allow: + - ports: + - '12345' + protocol: tcp deny: [] description: Allow traffic from onprem probes direction: INGRESS @@ -1475,28 +1470,28 @@ values: priority: 1000 project: fast2-prod-net-landing-0 source_ranges: - - 10.255.255.254/32 + - 10.255.255.254/32 source_service_accounts: null source_tags: null target_service_accounts: null target_tags: null timeouts: null - ? module.landing-firewall.google_compute_firewall.custom-rules["landing-ingress-default-deny"] - : allow: [] + module.landing-firewall.google_compute_firewall.custom-rules["landing-ingress-default-deny"]: + allow: [] deny: - - ports: [] - protocol: all + - ports: [] + protocol: all description: Deny and log any unmatched ingress traffic. direction: INGRESS disabled: false log_config: - - metadata: EXCLUDE_ALL_METADATA + - metadata: EXCLUDE_ALL_METADATA name: landing-ingress-default-deny network: prod-landing-0 priority: 65535 project: fast2-prod-net-landing-0 source_ranges: - - 0.0.0.0/0 + - 0.0.0.0/0 source_service_accounts: null source_tags: null target_service_accounts: null @@ -1517,10 +1512,9 @@ values: enable_endpoint_independent_mapping: true icmp_idle_timeout_sec: 30 log_config: - - enable: false - filter: ALL - max_ports_per_vm: 65536 - min_ports_per_vm: 64 + - enable: false + filter: ALL + max_ports_per_vm: null name: ew1 nat_ip_allocate_option: AUTO_ONLY nat_ips: null @@ -1534,6 +1528,7 @@ values: tcp_time_wait_timeout_sec: 120 tcp_transitory_idle_timeout_sec: 30 timeouts: null + type: PUBLIC udp_idle_timeout_sec: 30 module.landing-nat-secondary[0].google_compute_router.router[0]: bgp: [] @@ -1550,10 +1545,9 @@ values: enable_endpoint_independent_mapping: true icmp_idle_timeout_sec: 30 log_config: - - enable: false - filter: ALL - max_ports_per_vm: 65536 - min_ports_per_vm: 64 + - enable: false + filter: ALL + max_ports_per_vm: null name: ew4 nat_ip_allocate_option: AUTO_ONLY nat_ips: null @@ -1567,9 +1561,10 @@ values: tcp_time_wait_timeout_sec: 120 tcp_transitory_idle_timeout_sec: 30 timeouts: null + type: PUBLIC udp_idle_timeout_sec: 30 - ? module.landing-project.google_compute_shared_vpc_host_project.shared_vpc_host[0] - : project: fast2-prod-net-landing-0 + module.landing-project.google_compute_shared_vpc_host_project.shared_vpc_host[0]: + project: fast2-prod-net-landing-0 timeouts: null module.landing-project.google_project.project[0]: auto_create_network: false @@ -1581,70 +1576,70 @@ values: project_id: fast2-prod-net-landing-0 skip_delete: false timeouts: null - ? module.landing-project.google_project_iam_binding.authoritative["organizations/123456789012/roles/foo"] - : condition: [] + module.landing-project.google_project_iam_binding.authoritative["organizations/123456789012/roles/foo"]: + condition: [] members: - - serviceAccount:string + - serviceAccount:string project: fast2-prod-net-landing-0 role: organizations/123456789012/roles/foo - ? module.landing-project.google_project_iam_binding.authoritative["roles/dns.admin"] - : condition: [] + module.landing-project.google_project_iam_binding.authoritative["roles/dns.admin"]: + condition: [] members: - - serviceAccount:string + - serviceAccount:string project: fast2-prod-net-landing-0 role: roles/dns.admin - ? module.landing-project.google_project_service.project_services["compute.googleapis.com"] - : disable_dependent_services: false + module.landing-project.google_project_service.project_services["compute.googleapis.com"]: + disable_dependent_services: false disable_on_destroy: false project: fast2-prod-net-landing-0 service: compute.googleapis.com timeouts: null - ? module.landing-project.google_project_service.project_services["dns.googleapis.com"] - : disable_dependent_services: false + module.landing-project.google_project_service.project_services["dns.googleapis.com"]: + disable_dependent_services: false disable_on_destroy: false project: fast2-prod-net-landing-0 service: dns.googleapis.com timeouts: null - ? module.landing-project.google_project_service.project_services["iap.googleapis.com"] - : disable_dependent_services: false + module.landing-project.google_project_service.project_services["iap.googleapis.com"]: + disable_dependent_services: false disable_on_destroy: false project: fast2-prod-net-landing-0 service: iap.googleapis.com timeouts: null - ? module.landing-project.google_project_service.project_services["networkconnectivity.googleapis.com"] - : disable_dependent_services: false + module.landing-project.google_project_service.project_services["networkconnectivity.googleapis.com"]: + disable_dependent_services: false disable_on_destroy: false project: fast2-prod-net-landing-0 service: networkconnectivity.googleapis.com timeouts: null - ? module.landing-project.google_project_service.project_services["networkmanagement.googleapis.com"] - : disable_dependent_services: false + module.landing-project.google_project_service.project_services["networkmanagement.googleapis.com"]: + disable_dependent_services: false disable_on_destroy: false project: fast2-prod-net-landing-0 service: networkmanagement.googleapis.com timeouts: null - ? module.landing-project.google_project_service.project_services["stackdriver.googleapis.com"] - : disable_dependent_services: false + module.landing-project.google_project_service.project_services["stackdriver.googleapis.com"]: + disable_dependent_services: false disable_on_destroy: false project: fast2-prod-net-landing-0 service: stackdriver.googleapis.com timeouts: null - ? module.landing-project.google_project_service_identity.jit_si["iap.googleapis.com"] - : project: fast2-prod-net-landing-0 + module.landing-project.google_project_service_identity.jit_si["iap.googleapis.com"]: + project: fast2-prod-net-landing-0 service: iap.googleapis.com timeouts: null - ? module.landing-to-onprem-primary-vpn[0].google_compute_external_vpn_gateway.external_gateway["default"] - : description: Terraform managed external VPN gateway + module.landing-to-onprem-primary-vpn[0].google_compute_external_vpn_gateway.external_gateway["default"]: + description: Terraform managed external VPN gateway interface: - - id: 0 - ip_address: 8.8.8.8 + - id: 0 + ip_address: 8.8.8.8 labels: null name: vpn-to-onprem-ew1-default project: fast2-prod-net-landing-0 redundancy_type: SINGLE_IP_INTERNALLY_REDUNDANT timeouts: null - ? module.landing-to-onprem-primary-vpn[0].google_compute_ha_vpn_gateway.ha_gateway[0] - : description: Terraform managed external VPN gateway + module.landing-to-onprem-primary-vpn[0].google_compute_ha_vpn_gateway.ha_gateway[0]: + description: Terraform managed external VPN gateway name: vpn-to-onprem-ew1 project: fast2-prod-net-landing-0 region: europe-west1 @@ -1652,25 +1647,25 @@ values: timeouts: null module.landing-to-onprem-primary-vpn[0].google_compute_router.router[0]: bgp: - - advertise_mode: CUSTOM - advertised_groups: [] - advertised_ip_ranges: - - description: gcp - range: 10.1.0.0/16 - - description: gcp-restricted - range: 199.36.153.4/30 - - description: gcp-dns - range: 35.199.192.0/19 - asn: 65501 - keepalive_interval: 20 + - advertise_mode: CUSTOM + advertised_groups: [] + advertised_ip_ranges: + - description: gcp + range: 10.1.0.0/16 + - description: gcp-restricted + range: 199.36.153.4/30 + - description: gcp-dns + range: 35.199.192.0/19 + asn: 65501 + keepalive_interval: 20 description: null encrypted_interconnect_router: null name: vpn-vpn-to-onprem-ew1 project: fast2-prod-net-landing-0 region: europe-west1 timeouts: null - ? module.landing-to-onprem-primary-vpn[0].google_compute_router_interface.router_interface["0"] - : interconnect_attachment: null + module.landing-to-onprem-primary-vpn[0].google_compute_router_interface.router_interface["0"]: + interconnect_attachment: null ip_range: 169.254.1.2/30 name: vpn-to-onprem-ew1-0 private_ip_address: null @@ -1680,8 +1675,8 @@ values: subnetwork: null timeouts: null vpn_tunnel: vpn-to-onprem-ew1-0 - ? module.landing-to-onprem-primary-vpn[0].google_compute_router_interface.router_interface["1"] - : interconnect_attachment: null + module.landing-to-onprem-primary-vpn[0].google_compute_router_interface.router_interface["1"]: + interconnect_attachment: null ip_range: 169.254.2.2/30 name: vpn-to-onprem-ew1-1 private_ip_address: null @@ -1691,8 +1686,8 @@ values: subnetwork: null timeouts: null vpn_tunnel: vpn-to-onprem-ew1-1 - ? module.landing-to-onprem-primary-vpn[0].google_compute_router_peer.bgp_peer["0"] - : advertise_mode: DEFAULT + module.landing-to-onprem-primary-vpn[0].google_compute_router_peer.bgp_peer["0"]: + advertise_mode: DEFAULT advertised_groups: [] advertised_ip_ranges: [] advertised_route_priority: 1000 @@ -1708,8 +1703,8 @@ values: router: vpn-vpn-to-onprem-ew1 router_appliance_instance: null timeouts: null - ? module.landing-to-onprem-primary-vpn[0].google_compute_router_peer.bgp_peer["1"] - : advertise_mode: DEFAULT + module.landing-to-onprem-primary-vpn[0].google_compute_router_peer.bgp_peer["1"]: + advertise_mode: DEFAULT advertised_groups: [] advertised_ip_ranges: [] advertised_route_priority: 1000 @@ -1725,8 +1720,8 @@ values: router: vpn-vpn-to-onprem-ew1 router_appliance_instance: null timeouts: null - ? module.landing-to-onprem-primary-vpn[0].google_compute_vpn_tunnel.tunnels["0"] - : description: null + module.landing-to-onprem-primary-vpn[0].google_compute_vpn_tunnel.tunnels["0"]: + description: null ike_version: 2 labels: null name: vpn-to-onprem-ew1-0 @@ -1739,8 +1734,8 @@ values: target_vpn_gateway: null timeouts: null vpn_gateway_interface: 0 - ? module.landing-to-onprem-primary-vpn[0].google_compute_vpn_tunnel.tunnels["1"] - : description: null + module.landing-to-onprem-primary-vpn[0].google_compute_vpn_tunnel.tunnels["1"]: + description: null ike_version: 2 labels: null name: vpn-to-onprem-ew1-1 @@ -1757,18 +1752,18 @@ values: byte_length: 8 keepers: null prefix: null - ? module.landing-to-onprem-secondary-vpn[0].google_compute_external_vpn_gateway.external_gateway["default"] - : description: Terraform managed external VPN gateway + module.landing-to-onprem-secondary-vpn[0].google_compute_external_vpn_gateway.external_gateway["default"]: + description: Terraform managed external VPN gateway interface: - - id: 0 - ip_address: 8.8.4.4 + - id: 0 + ip_address: 8.8.4.4 labels: null name: vpn-to-onprem-ew4-default project: fast2-prod-net-landing-0 redundancy_type: SINGLE_IP_INTERNALLY_REDUNDANT timeouts: null - ? module.landing-to-onprem-secondary-vpn[0].google_compute_ha_vpn_gateway.ha_gateway[0] - : description: Terraform managed external VPN gateway + module.landing-to-onprem-secondary-vpn[0].google_compute_ha_vpn_gateway.ha_gateway[0]: + description: Terraform managed external VPN gateway name: vpn-to-onprem-ew4 project: fast2-prod-net-landing-0 region: europe-west4 @@ -1776,25 +1771,25 @@ values: timeouts: null module.landing-to-onprem-secondary-vpn[0].google_compute_router.router[0]: bgp: - - advertise_mode: CUSTOM - advertised_groups: [] - advertised_ip_ranges: - - description: gcp - range: 10.1.0.0/16 - - description: gcp-restricted - range: 199.36.153.4/30 - - description: gcp-dns - range: 35.199.192.0/19 - asn: 65501 - keepalive_interval: 20 + - advertise_mode: CUSTOM + advertised_groups: [] + advertised_ip_ranges: + - description: gcp + range: 10.1.0.0/16 + - description: gcp-restricted + range: 199.36.153.4/30 + - description: gcp-dns + range: 35.199.192.0/19 + asn: 65501 + keepalive_interval: 20 description: null encrypted_interconnect_router: null name: vpn-vpn-to-onprem-ew4 project: fast2-prod-net-landing-0 region: europe-west4 timeouts: null - ? module.landing-to-onprem-secondary-vpn[0].google_compute_router_interface.router_interface["0"] - : interconnect_attachment: null + module.landing-to-onprem-secondary-vpn[0].google_compute_router_interface.router_interface["0"]: + interconnect_attachment: null ip_range: 169.254.3.2/30 name: vpn-to-onprem-ew4-0 private_ip_address: null @@ -1804,8 +1799,8 @@ values: subnetwork: null timeouts: null vpn_tunnel: vpn-to-onprem-ew4-0 - ? module.landing-to-onprem-secondary-vpn[0].google_compute_router_interface.router_interface["1"] - : interconnect_attachment: null + module.landing-to-onprem-secondary-vpn[0].google_compute_router_interface.router_interface["1"]: + interconnect_attachment: null ip_range: 169.254.4.2/30 name: vpn-to-onprem-ew4-1 private_ip_address: null @@ -1815,8 +1810,8 @@ values: subnetwork: null timeouts: null vpn_tunnel: vpn-to-onprem-ew4-1 - ? module.landing-to-onprem-secondary-vpn[0].google_compute_router_peer.bgp_peer["0"] - : advertise_mode: DEFAULT + module.landing-to-onprem-secondary-vpn[0].google_compute_router_peer.bgp_peer["0"]: + advertise_mode: DEFAULT advertised_groups: [] advertised_ip_ranges: [] advertised_route_priority: 1000 @@ -1832,8 +1827,8 @@ values: router: vpn-vpn-to-onprem-ew4 router_appliance_instance: null timeouts: null - ? module.landing-to-onprem-secondary-vpn[0].google_compute_router_peer.bgp_peer["1"] - : advertise_mode: DEFAULT + module.landing-to-onprem-secondary-vpn[0].google_compute_router_peer.bgp_peer["1"]: + advertise_mode: DEFAULT advertised_groups: [] advertised_ip_ranges: [] advertised_route_priority: 1000 @@ -1849,8 +1844,8 @@ values: router: vpn-vpn-to-onprem-ew4 router_appliance_instance: null timeouts: null - ? module.landing-to-onprem-secondary-vpn[0].google_compute_vpn_tunnel.tunnels["0"] - : description: null + module.landing-to-onprem-secondary-vpn[0].google_compute_vpn_tunnel.tunnels["0"]: + description: null ike_version: 2 labels: null name: vpn-to-onprem-ew4-0 @@ -1863,8 +1858,8 @@ values: target_vpn_gateway: null timeouts: null vpn_gateway_interface: 0 - ? module.landing-to-onprem-secondary-vpn[0].google_compute_vpn_tunnel.tunnels["1"] - : description: null + module.landing-to-onprem-secondary-vpn[0].google_compute_vpn_tunnel.tunnels["1"]: + description: null ike_version: 2 labels: null name: vpn-to-onprem-ew4-1 @@ -1918,8 +1913,8 @@ values: project: fast2-prod-net-landing-0 tags: null timeouts: null - ? module.landing-vpc.google_compute_subnetwork.subnetwork["europe-west1/landing-default"] - : description: Default europe-west1 subnet for landing + module.landing-vpc.google_compute_subnetwork.subnetwork["europe-west1/landing-default"]: + description: Default europe-west1 subnet for landing ip_cidr_range: 10.64.0.0/24 ipv6_access_type: null log_config: [] @@ -1931,8 +1926,8 @@ values: role: null secondary_ip_range: [] timeouts: null - ? module.landing-vpc.google_compute_subnetwork.subnetwork["europe-west4/landing-default"] - : description: Default europe-west4 subnet for landing + module.landing-vpc.google_compute_subnetwork.subnetwork["europe-west4/landing-default"]: + description: Default europe-west4 subnet for landing ip_cidr_range: 10.80.0.0/24 ipv6_access_type: null log_config: [] @@ -1951,7 +1946,7 @@ values: enable_logging: null name: prod-landing-0 networks: - - {} + - {} project: fast2-prod-net-landing-0 timeouts: null module.nva["primary-b"].google_compute_instance.default[0]: @@ -1959,15 +1954,15 @@ values: allow_stopping_for_update: true attached_disk: [] boot_disk: - - auto_delete: true - disk_encryption_key_raw: null - initialize_params: - - enable_confidential_compute: null - image: projects/cos-cloud/global/images/family/cos-stable - resource_manager_tags: null - size: 10 - type: pd-balanced - mode: READ_WRITE + - auto_delete: true + disk_encryption_key_raw: null + initialize_params: + - enable_confidential_compute: null + image: projects/cos-cloud/global/images/family/cos-stable + resource_manager_tags: null + size: 10 + type: pd-balanced + mode: READ_WRITE can_ip_forward: true deletion_protection: false description: Managed by the compute-vm Terraform module. @@ -1977,8 +1972,7 @@ values: labels: null machine_type: e2-standard-2 metadata: - user-data: - "#cloud-config\n\n# Copyright 2023 Google LLC\n#\n# Licensed under\ + user-data: "#cloud-config\n\n# Copyright 2024 Google LLC\n#\n# Licensed under\ \ the Apache License, Version 2.0 (the \"License\");\n# you may not use this\ \ file except in compliance with the License.\n# You may obtain a copy of\ \ the License at\n#\n# https://www.apache.org/licenses/LICENSE-2.0\n#\n\ @@ -2149,7 +2143,9 @@ values: \ permissions: 0744\n owner: root\n content: |\n iptables --policy\ \ FORWARD ACCEPT\n /var/run/nva/policy_based_routing.sh eth0 &>/dev/null\ \ &\n iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE\n ip\ - \ route add 10.64.127.0/17 via `curl http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/gateway\ + \ route add 35.235.240.0/20 via `curl http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/gateway\ + \ -H \"Metadata-Flavor:Google\"` dev eth0\n ip route add 10.64.127.0/17\ + \ via `curl http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/gateway\ \ -H \"Metadata-Flavor:Google\"` dev eth0\n ip route add 10.80.127.0/17\ \ via `curl http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/gateway\ \ -H \"Metadata-Flavor:Google\"` dev eth0\n /var/run/nva/policy_based_routing.sh\ @@ -2163,44 +2159,44 @@ values: metadata_startup_script: null name: nva-ew1-b network_interface: - - access_config: [] - alias_ip_range: [] - ipv6_access_config: [] - network_ip: 10.64.128.101 - nic_type: null - queue_count: null - security_policy: null - - access_config: [] - alias_ip_range: [] - ipv6_access_config: [] - network_ip: 10.64.0.101 - nic_type: null - queue_count: null - security_policy: null + - access_config: [] + alias_ip_range: [] + ipv6_access_config: [] + network_ip: 10.64.128.101 + nic_type: null + queue_count: null + security_policy: null + - access_config: [] + alias_ip_range: [] + ipv6_access_config: [] + network_ip: 10.64.0.101 + nic_type: null + queue_count: null + security_policy: null network_performance_config: [] params: [] project: fast2-prod-net-landing-0 resource_policies: null scheduling: - - automatic_restart: true - instance_termination_action: null - local_ssd_recovery_timeout: [] - maintenance_interval: null - max_run_duration: [] - min_node_cpus: null - node_affinities: [] - on_host_maintenance: MIGRATE - preemptible: false - provisioning_model: STANDARD + - automatic_restart: true + instance_termination_action: null + local_ssd_recovery_timeout: [] + maintenance_interval: null + max_run_duration: [] + min_node_cpus: null + node_affinities: [] + on_host_maintenance: MIGRATE + preemptible: false + provisioning_model: STANDARD scratch_disk: [] service_account: - - scopes: - - https://www.googleapis.com/auth/devstorage.read_only - - https://www.googleapis.com/auth/logging.write - - https://www.googleapis.com/auth/monitoring.write + - scopes: + - https://www.googleapis.com/auth/devstorage.read_only + - https://www.googleapis.com/auth/logging.write + - https://www.googleapis.com/auth/monitoring.write shielded_instance_config: [] tags: - - nva + - nva timeouts: null zone: europe-west1-b module.nva["primary-c"].google_compute_instance.default[0]: @@ -2208,15 +2204,15 @@ values: allow_stopping_for_update: true attached_disk: [] boot_disk: - - auto_delete: true - disk_encryption_key_raw: null - initialize_params: - - enable_confidential_compute: null - image: projects/cos-cloud/global/images/family/cos-stable - resource_manager_tags: null - size: 10 - type: pd-balanced - mode: READ_WRITE + - auto_delete: true + disk_encryption_key_raw: null + initialize_params: + - enable_confidential_compute: null + image: projects/cos-cloud/global/images/family/cos-stable + resource_manager_tags: null + size: 10 + type: pd-balanced + mode: READ_WRITE can_ip_forward: true deletion_protection: false description: Managed by the compute-vm Terraform module. @@ -2226,8 +2222,7 @@ values: labels: null machine_type: e2-standard-2 metadata: - user-data: - "#cloud-config\n\n# Copyright 2023 Google LLC\n#\n# Licensed under\ + user-data: "#cloud-config\n\n# Copyright 2024 Google LLC\n#\n# Licensed under\ \ the Apache License, Version 2.0 (the \"License\");\n# you may not use this\ \ file except in compliance with the License.\n# You may obtain a copy of\ \ the License at\n#\n# https://www.apache.org/licenses/LICENSE-2.0\n#\n\ @@ -2398,7 +2393,9 @@ values: \ permissions: 0744\n owner: root\n content: |\n iptables --policy\ \ FORWARD ACCEPT\n /var/run/nva/policy_based_routing.sh eth0 &>/dev/null\ \ &\n iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE\n ip\ - \ route add 10.64.127.0/17 via `curl http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/gateway\ + \ route add 35.235.240.0/20 via `curl http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/gateway\ + \ -H \"Metadata-Flavor:Google\"` dev eth0\n ip route add 10.64.127.0/17\ + \ via `curl http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/gateway\ \ -H \"Metadata-Flavor:Google\"` dev eth0\n ip route add 10.80.127.0/17\ \ via `curl http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/gateway\ \ -H \"Metadata-Flavor:Google\"` dev eth0\n /var/run/nva/policy_based_routing.sh\ @@ -2412,44 +2409,44 @@ values: metadata_startup_script: null name: nva-ew1-c network_interface: - - access_config: [] - alias_ip_range: [] - ipv6_access_config: [] - network_ip: 10.64.128.102 - nic_type: null - queue_count: null - security_policy: null - - access_config: [] - alias_ip_range: [] - ipv6_access_config: [] - network_ip: 10.64.0.102 - nic_type: null - queue_count: null - security_policy: null + - access_config: [] + alias_ip_range: [] + ipv6_access_config: [] + network_ip: 10.64.128.102 + nic_type: null + queue_count: null + security_policy: null + - access_config: [] + alias_ip_range: [] + ipv6_access_config: [] + network_ip: 10.64.0.102 + nic_type: null + queue_count: null + security_policy: null network_performance_config: [] params: [] project: fast2-prod-net-landing-0 resource_policies: null scheduling: - - automatic_restart: true - instance_termination_action: null - local_ssd_recovery_timeout: [] - maintenance_interval: null - max_run_duration: [] - min_node_cpus: null - node_affinities: [] - on_host_maintenance: MIGRATE - preemptible: false - provisioning_model: STANDARD + - automatic_restart: true + instance_termination_action: null + local_ssd_recovery_timeout: [] + maintenance_interval: null + max_run_duration: [] + min_node_cpus: null + node_affinities: [] + on_host_maintenance: MIGRATE + preemptible: false + provisioning_model: STANDARD scratch_disk: [] service_account: - - scopes: - - https://www.googleapis.com/auth/devstorage.read_only - - https://www.googleapis.com/auth/logging.write - - https://www.googleapis.com/auth/monitoring.write + - scopes: + - https://www.googleapis.com/auth/devstorage.read_only + - https://www.googleapis.com/auth/logging.write + - https://www.googleapis.com/auth/monitoring.write shielded_instance_config: [] tags: - - nva + - nva timeouts: null zone: europe-west1-c module.nva["secondary-b"].google_compute_instance.default[0]: @@ -2457,15 +2454,15 @@ values: allow_stopping_for_update: true attached_disk: [] boot_disk: - - auto_delete: true - disk_encryption_key_raw: null - initialize_params: - - enable_confidential_compute: null - image: projects/cos-cloud/global/images/family/cos-stable - resource_manager_tags: null - size: 10 - type: pd-balanced - mode: READ_WRITE + - auto_delete: true + disk_encryption_key_raw: null + initialize_params: + - enable_confidential_compute: null + image: projects/cos-cloud/global/images/family/cos-stable + resource_manager_tags: null + size: 10 + type: pd-balanced + mode: READ_WRITE can_ip_forward: true deletion_protection: false description: Managed by the compute-vm Terraform module. @@ -2475,8 +2472,7 @@ values: labels: null machine_type: e2-standard-2 metadata: - user-data: - "#cloud-config\n\n# Copyright 2023 Google LLC\n#\n# Licensed under\ + user-data: "#cloud-config\n\n# Copyright 2024 Google LLC\n#\n# Licensed under\ \ the Apache License, Version 2.0 (the \"License\");\n# you may not use this\ \ file except in compliance with the License.\n# You may obtain a copy of\ \ the License at\n#\n# https://www.apache.org/licenses/LICENSE-2.0\n#\n\ @@ -2647,7 +2643,9 @@ values: \ permissions: 0744\n owner: root\n content: |\n iptables --policy\ \ FORWARD ACCEPT\n /var/run/nva/policy_based_routing.sh eth0 &>/dev/null\ \ &\n iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE\n ip\ - \ route add 10.64.127.0/17 via `curl http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/gateway\ + \ route add 35.235.240.0/20 via `curl http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/gateway\ + \ -H \"Metadata-Flavor:Google\"` dev eth0\n ip route add 10.64.127.0/17\ + \ via `curl http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/gateway\ \ -H \"Metadata-Flavor:Google\"` dev eth0\n ip route add 10.80.127.0/17\ \ via `curl http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/gateway\ \ -H \"Metadata-Flavor:Google\"` dev eth0\n /var/run/nva/policy_based_routing.sh\ @@ -2661,44 +2659,44 @@ values: metadata_startup_script: null name: nva-ew4-b network_interface: - - access_config: [] - alias_ip_range: [] - ipv6_access_config: [] - network_ip: 10.80.128.101 - nic_type: null - queue_count: null - security_policy: null - - access_config: [] - alias_ip_range: [] - ipv6_access_config: [] - network_ip: 10.80.0.101 - nic_type: null - queue_count: null - security_policy: null + - access_config: [] + alias_ip_range: [] + ipv6_access_config: [] + network_ip: 10.80.128.101 + nic_type: null + queue_count: null + security_policy: null + - access_config: [] + alias_ip_range: [] + ipv6_access_config: [] + network_ip: 10.80.0.101 + nic_type: null + queue_count: null + security_policy: null network_performance_config: [] params: [] project: fast2-prod-net-landing-0 resource_policies: null scheduling: - - automatic_restart: true - instance_termination_action: null - local_ssd_recovery_timeout: [] - maintenance_interval: null - max_run_duration: [] - min_node_cpus: null - node_affinities: [] - on_host_maintenance: MIGRATE - preemptible: false - provisioning_model: STANDARD + - automatic_restart: true + instance_termination_action: null + local_ssd_recovery_timeout: [] + maintenance_interval: null + max_run_duration: [] + min_node_cpus: null + node_affinities: [] + on_host_maintenance: MIGRATE + preemptible: false + provisioning_model: STANDARD scratch_disk: [] service_account: - - scopes: - - https://www.googleapis.com/auth/devstorage.read_only - - https://www.googleapis.com/auth/logging.write - - https://www.googleapis.com/auth/monitoring.write + - scopes: + - https://www.googleapis.com/auth/devstorage.read_only + - https://www.googleapis.com/auth/logging.write + - https://www.googleapis.com/auth/monitoring.write shielded_instance_config: [] tags: - - nva + - nva timeouts: null zone: europe-west4-b module.nva["secondary-c"].google_compute_instance.default[0]: @@ -2706,15 +2704,15 @@ values: allow_stopping_for_update: true attached_disk: [] boot_disk: - - auto_delete: true - disk_encryption_key_raw: null - initialize_params: - - enable_confidential_compute: null - image: projects/cos-cloud/global/images/family/cos-stable - resource_manager_tags: null - size: 10 - type: pd-balanced - mode: READ_WRITE + - auto_delete: true + disk_encryption_key_raw: null + initialize_params: + - enable_confidential_compute: null + image: projects/cos-cloud/global/images/family/cos-stable + resource_manager_tags: null + size: 10 + type: pd-balanced + mode: READ_WRITE can_ip_forward: true deletion_protection: false description: Managed by the compute-vm Terraform module. @@ -2724,8 +2722,7 @@ values: labels: null machine_type: e2-standard-2 metadata: - user-data: - "#cloud-config\n\n# Copyright 2023 Google LLC\n#\n# Licensed under\ + user-data: "#cloud-config\n\n# Copyright 2024 Google LLC\n#\n# Licensed under\ \ the Apache License, Version 2.0 (the \"License\");\n# you may not use this\ \ file except in compliance with the License.\n# You may obtain a copy of\ \ the License at\n#\n# https://www.apache.org/licenses/LICENSE-2.0\n#\n\ @@ -2896,7 +2893,9 @@ values: \ permissions: 0744\n owner: root\n content: |\n iptables --policy\ \ FORWARD ACCEPT\n /var/run/nva/policy_based_routing.sh eth0 &>/dev/null\ \ &\n iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE\n ip\ - \ route add 10.64.127.0/17 via `curl http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/gateway\ + \ route add 35.235.240.0/20 via `curl http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/gateway\ + \ -H \"Metadata-Flavor:Google\"` dev eth0\n ip route add 10.64.127.0/17\ + \ via `curl http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/gateway\ \ -H \"Metadata-Flavor:Google\"` dev eth0\n ip route add 10.80.127.0/17\ \ via `curl http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/gateway\ \ -H \"Metadata-Flavor:Google\"` dev eth0\n /var/run/nva/policy_based_routing.sh\ @@ -2910,44 +2909,44 @@ values: metadata_startup_script: null name: nva-ew4-c network_interface: - - access_config: [] - alias_ip_range: [] - ipv6_access_config: [] - network_ip: 10.80.128.102 - nic_type: null - queue_count: null - security_policy: null - - access_config: [] - alias_ip_range: [] - ipv6_access_config: [] - network_ip: 10.80.0.102 - nic_type: null - queue_count: null - security_policy: null + - access_config: [] + alias_ip_range: [] + ipv6_access_config: [] + network_ip: 10.80.128.102 + nic_type: null + queue_count: null + security_policy: null + - access_config: [] + alias_ip_range: [] + ipv6_access_config: [] + network_ip: 10.80.0.102 + nic_type: null + queue_count: null + security_policy: null network_performance_config: [] params: [] project: fast2-prod-net-landing-0 resource_policies: null scheduling: - - automatic_restart: true - instance_termination_action: null - local_ssd_recovery_timeout: [] - maintenance_interval: null - max_run_duration: [] - min_node_cpus: null - node_affinities: [] - on_host_maintenance: MIGRATE - preemptible: false - provisioning_model: STANDARD + - automatic_restart: true + instance_termination_action: null + local_ssd_recovery_timeout: [] + maintenance_interval: null + max_run_duration: [] + min_node_cpus: null + node_affinities: [] + on_host_maintenance: MIGRATE + preemptible: false + provisioning_model: STANDARD scratch_disk: [] service_account: - - scopes: - - https://www.googleapis.com/auth/devstorage.read_only - - https://www.googleapis.com/auth/logging.write - - https://www.googleapis.com/auth/monitoring.write + - scopes: + - https://www.googleapis.com/auth/devstorage.read_only + - https://www.googleapis.com/auth/logging.write + - https://www.googleapis.com/auth/monitoring.write shielded_instance_config: [] tags: - - nva + - nva timeouts: null zone: europe-west4-c module.peering-dev.google_compute_network_peering.local_network_peering: @@ -2978,9 +2977,9 @@ values: import_subnet_routes_with_public_ip: null stack_type: IPV4_ONLY timeouts: null - ? module.prod-dns-peer-landing-rev-10.google_dns_managed_zone.dns_managed_zone[0] - : cloud_logging_config: - - enable_logging: false + module.prod-dns-peer-landing-rev-10.google_dns_managed_zone.dns_managed_zone[0]: + cloud_logging_config: + - enable_logging: false description: Terraform managed. dns_name: 10.in-addr.arpa. dnssec_config: [] @@ -2995,7 +2994,7 @@ values: visibility: private module.prod-dns-peer-landing-root.google_dns_managed_zone.dns_managed_zone[0]: cloud_logging_config: - - enable_logging: false + - enable_logging: false description: Terraform managed. dns_name: . dnssec_config: [] @@ -3010,7 +3009,7 @@ values: visibility: private module.prod-dns-private-zone.google_dns_managed_zone.dns_managed_zone[0]: cloud_logging_config: - - enable_logging: false + - enable_logging: false description: Terraform managed. dns_name: prod.gcp.example.com. dnssec_config: [] @@ -3023,41 +3022,41 @@ values: service_directory_config: [] timeouts: null visibility: private - ? module.prod-dns-private-zone.google_dns_record_set.dns_record_set["A localhost"] - : managed_zone: prod-gcp-example-com + module.prod-dns-private-zone.google_dns_record_set.dns_record_set["A localhost"]: + managed_zone: prod-gcp-example-com name: localhost.prod.gcp.example.com. project: fast2-prod-net-spoke-0 routing_policy: [] rrdatas: - - 127.0.0.1 + - 127.0.0.1 ttl: 300 type: A - ? module.prod-spoke-firewall.google_compute_firewall.custom-rules["ingress-default-deny"] - : allow: [] + module.prod-spoke-firewall.google_compute_firewall.custom-rules["ingress-default-deny"]: + allow: [] deny: - - ports: [] - protocol: all + - ports: [] + protocol: all description: Deny and log any unmatched ingress traffic. direction: INGRESS disabled: false log_config: - - metadata: EXCLUDE_ALL_METADATA + - metadata: EXCLUDE_ALL_METADATA name: ingress-default-deny network: prod-spoke-0 priority: 65535 project: fast2-prod-net-spoke-0 source_ranges: - - 0.0.0.0/0 + - 0.0.0.0/0 source_service_accounts: null source_tags: null target_service_accounts: null target_tags: null timeouts: null - ? module.prod-spoke-project.google_compute_shared_vpc_host_project.shared_vpc_host[0] - : project: fast2-prod-net-spoke-0 + module.prod-spoke-project.google_compute_shared_vpc_host_project.shared_vpc_host[0]: + project: fast2-prod-net-spoke-0 timeouts: null - ? module.prod-spoke-project.google_monitoring_monitored_project.primary["fast2-prod-net-landing-0"] - : metrics_scope: fast2-prod-net-landing-0 + module.prod-spoke-project.google_monitoring_monitored_project.primary["fast2-prod-net-landing-0"]: + metrics_scope: fast2-prod-net-landing-0 name: fast2-prod-net-spoke-0 timeouts: null module.prod-spoke-project.google_project.project[0]: @@ -3070,73 +3069,73 @@ values: project_id: fast2-prod-net-spoke-0 skip_delete: false timeouts: null - ? module.prod-spoke-project.google_project_iam_binding.authoritative["roles/dns.admin"] - : condition: [] + module.prod-spoke-project.google_project_iam_binding.authoritative["roles/dns.admin"]: + condition: [] members: - - serviceAccount:string + - serviceAccount:string project: fast2-prod-net-spoke-0 role: roles/dns.admin - ? module.prod-spoke-project.google_project_iam_binding.bindings["sa_delegated_grants"] - : condition: - - description: Production host project delegated grants. - expression: api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly(['roles/composer.sharedVpcAgent','roles/compute.networkUser','roles/compute.networkViewer','roles/container.hostServiceAgentUser','roles/multiclusterservicediscovery.serviceAgent','roles/vpcaccess.user']) - title: prod_stage3_sa_delegated_grants + module.prod-spoke-project.google_project_iam_binding.bindings["sa_delegated_grants"]: + condition: + - description: Production host project delegated grants. + expression: api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly(['roles/composer.sharedVpcAgent','roles/compute.networkUser','roles/compute.networkViewer','roles/container.hostServiceAgentUser','roles/multiclusterservicediscovery.serviceAgent','roles/vpcaccess.user']) + title: prod_stage3_sa_delegated_grants members: - - serviceAccount:string + - serviceAccount:string project: fast2-prod-net-spoke-0 role: roles/resourcemanager.projectIamAdmin module.prod-spoke-project.google_project_iam_member.servicenetworking[0]: condition: [] project: fast2-prod-net-spoke-0 role: roles/servicenetworking.serviceAgent - ? module.prod-spoke-project.google_project_service.project_services["compute.googleapis.com"] - : disable_dependent_services: false + module.prod-spoke-project.google_project_service.project_services["compute.googleapis.com"]: + disable_dependent_services: false disable_on_destroy: false project: fast2-prod-net-spoke-0 service: compute.googleapis.com timeouts: null - ? module.prod-spoke-project.google_project_service.project_services["dns.googleapis.com"] - : disable_dependent_services: false + module.prod-spoke-project.google_project_service.project_services["dns.googleapis.com"]: + disable_dependent_services: false disable_on_destroy: false project: fast2-prod-net-spoke-0 service: dns.googleapis.com timeouts: null - ? module.prod-spoke-project.google_project_service.project_services["iap.googleapis.com"] - : disable_dependent_services: false + module.prod-spoke-project.google_project_service.project_services["iap.googleapis.com"]: + disable_dependent_services: false disable_on_destroy: false project: fast2-prod-net-spoke-0 service: iap.googleapis.com timeouts: null - ? module.prod-spoke-project.google_project_service.project_services["networkmanagement.googleapis.com"] - : disable_dependent_services: false + module.prod-spoke-project.google_project_service.project_services["networkmanagement.googleapis.com"]: + disable_dependent_services: false disable_on_destroy: false project: fast2-prod-net-spoke-0 service: networkmanagement.googleapis.com timeouts: null - ? module.prod-spoke-project.google_project_service.project_services["servicenetworking.googleapis.com"] - : disable_dependent_services: false + module.prod-spoke-project.google_project_service.project_services["servicenetworking.googleapis.com"]: + disable_dependent_services: false disable_on_destroy: false project: fast2-prod-net-spoke-0 service: servicenetworking.googleapis.com timeouts: null - ? module.prod-spoke-project.google_project_service.project_services["stackdriver.googleapis.com"] - : disable_dependent_services: false + module.prod-spoke-project.google_project_service.project_services["stackdriver.googleapis.com"]: + disable_dependent_services: false disable_on_destroy: false project: fast2-prod-net-spoke-0 service: stackdriver.googleapis.com timeouts: null - ? module.prod-spoke-project.google_project_service.project_services["vpcaccess.googleapis.com"] - : disable_dependent_services: false + module.prod-spoke-project.google_project_service.project_services["vpcaccess.googleapis.com"]: + disable_dependent_services: false disable_on_destroy: false project: fast2-prod-net-spoke-0 service: vpcaccess.googleapis.com timeouts: null - ? module.prod-spoke-project.google_project_service_identity.jit_si["iap.googleapis.com"] - : project: fast2-prod-net-spoke-0 + module.prod-spoke-project.google_project_service_identity.jit_si["iap.googleapis.com"]: + project: fast2-prod-net-spoke-0 service: iap.googleapis.com timeouts: null - ? module.prod-spoke-project.google_project_service_identity.servicenetworking[0] - : project: fast2-prod-net-spoke-0 + module.prod-spoke-project.google_project_service_identity.servicenetworking[0]: + project: fast2-prod-net-spoke-0 service: servicenetworking.googleapis.com timeouts: null module.prod-spoke-vpc.google_compute_network.network[0]: @@ -3176,8 +3175,8 @@ values: project: fast2-prod-net-spoke-0 tags: null timeouts: null - ? module.prod-spoke-vpc.google_compute_subnetwork.subnetwork["europe-west1/prod-default"] - : description: Default europe-west1 subnet for prod + module.prod-spoke-vpc.google_compute_subnetwork.subnetwork["europe-west1/prod-default"]: + description: Default europe-west1 subnet for prod ip_cidr_range: 10.72.0.0/24 ipv6_access_type: null log_config: [] @@ -3189,8 +3188,8 @@ values: role: null secondary_ip_range: [] timeouts: null - ? module.prod-spoke-vpc.google_compute_subnetwork.subnetwork["europe-west4/prod-default"] - : description: Default europe-west4 subnet for prod + module.prod-spoke-vpc.google_compute_subnetwork.subnetwork["europe-west4/prod-default"]: + description: Default europe-west4 subnet for prod ip_cidr_range: 10.88.0.0/24 ipv6_access_type: null log_config: [] @@ -3209,18 +3208,18 @@ values: enable_logging: true name: prod-spoke-0 networks: - - {} + - {} project: fast2-prod-net-spoke-0 timeouts: null module.spokes-dmz["primary"].google_compute_router.cr: bgp: - - advertise_mode: CUSTOM - advertised_groups: [] - advertised_ip_ranges: - - description: Default route. - range: 0.0.0.0/0 - asn: 64512 - keepalive_interval: 20 + - advertise_mode: CUSTOM + advertised_groups: [] + advertised_ip_ranges: + - description: Default route. + range: 0.0.0.0/0 + asn: 64512 + keepalive_interval: 20 description: null encrypted_interconnect_router: null name: prod-spoke-dmz-ew1-cr @@ -3307,10 +3306,10 @@ values: labels: null linked_interconnect_attachments: [] linked_router_appliance_instances: - - instances: - - {} - - {} - site_to_site_data_transfer: false + - instances: + - {} + - {} + site_to_site_data_transfer: false linked_vpc_network: [] linked_vpn_tunnels: [] location: europe-west1 @@ -3319,13 +3318,13 @@ values: timeouts: null module.spokes-dmz["secondary"].google_compute_router.cr: bgp: - - advertise_mode: CUSTOM - advertised_groups: [] - advertised_ip_ranges: - - description: Default route. - range: 0.0.0.0/0 - asn: 64512 - keepalive_interval: 20 + - advertise_mode: CUSTOM + advertised_groups: [] + advertised_ip_ranges: + - description: Default route. + range: 0.0.0.0/0 + asn: 64512 + keepalive_interval: 20 description: null encrypted_interconnect_router: null name: prod-spoke-dmz-ew4-cr @@ -3412,10 +3411,10 @@ values: labels: null linked_interconnect_attachments: [] linked_router_appliance_instances: - - instances: - - {} - - {} - site_to_site_data_transfer: false + - instances: + - {} + - {} + site_to_site_data_transfer: false linked_vpc_network: [] linked_vpn_tunnels: [] location: europe-west4 @@ -3424,23 +3423,23 @@ values: timeouts: null module.spokes-landing["primary"].google_compute_router.cr: bgp: - - advertise_mode: CUSTOM - advertised_groups: [] - advertised_ip_ranges: - - description: GCP landing primary. - range: 10.64.0.0/17 - - description: GCP dev primary. - range: 10.68.0.0/16 - - description: GCP prod primary. - range: 10.72.0.0/16 - - description: GCP landing secondary. - range: 10.80.0.0/17 - - description: GCP dev secondary. - range: 10.84.0.0/16 - - description: GCP prod secondary. - range: 10.88.0.0/16 - asn: 64515 - keepalive_interval: 20 + - advertise_mode: CUSTOM + advertised_groups: [] + advertised_ip_ranges: + - description: GCP landing primary. + range: 10.64.0.0/17 + - description: GCP dev primary. + range: 10.68.0.0/16 + - description: GCP prod primary. + range: 10.72.0.0/16 + - description: GCP landing secondary. + range: 10.80.0.0/17 + - description: GCP dev secondary. + range: 10.84.0.0/16 + - description: GCP prod secondary. + range: 10.88.0.0/16 + asn: 64515 + keepalive_interval: 20 description: null encrypted_interconnect_router: null name: prod-spoke-landing-ew1-cr @@ -3527,10 +3526,10 @@ values: labels: null linked_interconnect_attachments: [] linked_router_appliance_instances: - - instances: - - {} - - {} - site_to_site_data_transfer: false + - instances: + - {} + - {} + site_to_site_data_transfer: false linked_vpc_network: [] linked_vpn_tunnels: [] location: europe-west1 @@ -3539,23 +3538,23 @@ values: timeouts: null module.spokes-landing["secondary"].google_compute_router.cr: bgp: - - advertise_mode: CUSTOM - advertised_groups: [] - advertised_ip_ranges: - - description: GCP landing primary. - range: 10.64.0.0/17 - - description: GCP dev primary. - range: 10.68.0.0/16 - - description: GCP prod primary. - range: 10.72.0.0/16 - - description: GCP landing secondary. - range: 10.80.0.0/17 - - description: GCP dev secondary. - range: 10.84.0.0/16 - - description: GCP prod secondary. - range: 10.88.0.0/16 - asn: 64515 - keepalive_interval: 20 + - advertise_mode: CUSTOM + advertised_groups: [] + advertised_ip_ranges: + - description: GCP landing primary. + range: 10.64.0.0/17 + - description: GCP dev primary. + range: 10.68.0.0/16 + - description: GCP prod primary. + range: 10.72.0.0/16 + - description: GCP landing secondary. + range: 10.80.0.0/17 + - description: GCP dev secondary. + range: 10.84.0.0/16 + - description: GCP prod secondary. + range: 10.88.0.0/16 + asn: 64515 + keepalive_interval: 20 description: null encrypted_interconnect_router: null name: prod-spoke-landing-ew4-cr @@ -3642,10 +3641,10 @@ values: labels: null linked_interconnect_attachments: [] linked_router_appliance_instances: - - instances: - - {} - - {} - site_to_site_data_transfer: false + - instances: + - {} + - {} + site_to_site_data_transfer: false linked_vpc_network: [] linked_vpn_tunnels: [] location: europe-west4 @@ -3703,3 +3702,4 @@ outputs: shared_vpc_self_links: __missing__ tfvars: __missing__ vpn_gateway_endpoints: __missing__ + diff --git a/tests/fast/stages_multitenant/s0_bootstrap_tenant/simple.tfvars b/tests/fast/stages_multitenant/s0_bootstrap_tenant/simple.tfvars index 52ca76a3db..e3691e9ca5 100644 --- a/tests/fast/stages_multitenant/s0_bootstrap_tenant/simple.tfvars +++ b/tests/fast/stages_multitenant/s0_bootstrap_tenant/simple.tfvars @@ -16,7 +16,7 @@ custom_roles = { groups = { gcp-billing-admins = "gcp-billing-admins", gcp-devops = "gcp-devops", - gcp-network-admins = "gcp-network-admins", + gcp-network-admins = "gcp-vpc-network-admins", gcp-organization-admins = "gcp-organization-admins", gcp-security-admins = "gcp-security-admins", gcp-support = "gcp-support" diff --git a/tests/fast/stages_multitenant/s0_bootstrap_tenant/simple.yaml b/tests/fast/stages_multitenant/s0_bootstrap_tenant/simple.yaml index 3e84c00ef6..f6f0d3ea26 100644 --- a/tests/fast/stages_multitenant/s0_bootstrap_tenant/simple.yaml +++ b/tests/fast/stages_multitenant/s0_bootstrap_tenant/simple.yaml @@ -14,7 +14,7 @@ counts: google_bigquery_default_service_account: 2 - google_folder: 2 + google_folder: 1 google_folder_iam_binding: 5 google_organization_iam_member: 39 google_project: 2 @@ -30,4 +30,4 @@ counts: google_tags_tag_binding: 1 google_tags_tag_value: 1 modules: 19 - resources: 129 + resources: 128 diff --git a/tests/fast/stages_multitenant/s1_resman_tenant/simple.tfvars b/tests/fast/stages_multitenant/s1_resman_tenant/simple.tfvars index 33cf461989..9cc9d46c69 100644 --- a/tests/fast/stages_multitenant/s1_resman_tenant/simple.tfvars +++ b/tests/fast/stages_multitenant/s1_resman_tenant/simple.tfvars @@ -34,7 +34,7 @@ fast_features = { } groups = { gcp-devops = "gcp-devops", - gcp-network-admins = "gcp-network-admins", + gcp-network-admins = "gcp-vpc-network-admins", gcp-security-admins = "gcp-security-admins", } organization = { diff --git a/tests/fixtures.py b/tests/fixtures.py index 50b6d8ad6a..1d725135f4 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -186,8 +186,13 @@ def plan_validator(module_path, inventory_paths, basedir, tf_var_files=None, # print(yaml.dump({'counts': summary.counts})) if 'values' in inventory: - validate_plan_object(inventory['values'], summary.values, relative_path, - "") + try: + validate_plan_object(inventory['values'], summary.values, relative_path, + "") + except AssertionError: + print(f'\n{path}') + print(yaml.dump({'values': summary.values})) + raise if 'counts' in inventory: try: @@ -199,6 +204,7 @@ def plan_validator(module_path, inventory_paths, basedir, tf_var_files=None, assert plan_count == expected_count, \ f'{relative_path}: count of {type_} resources failed. Got {plan_count}, expected {expected_count}' except AssertionError: + print(f'\n{path}') print(yaml.dump({'counts': summary.counts})) raise @@ -218,6 +224,7 @@ def plan_validator(module_path, inventory_paths, basedir, tf_var_files=None, f'{relative_path}: output {output_name} failed. Got `{plan_output}`, expected `{expected_output}`' except AssertionError: if _buffer: + print(f'\n{path}') print(yaml.dump(_buffer)) raise return summary diff --git a/tests/fixtures/cloudsql-instance.tf b/tests/fixtures/cloudsql-instance.tf new file mode 100644 index 0000000000..6fed8d6ada --- /dev/null +++ b/tests/fixtures/cloudsql-instance.tf @@ -0,0 +1,33 @@ +/** + * 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 "cloudsql-instance" { + source = "./fabric/modules/cloudsql-instance" + project_id = var.project_id + network_config = { + connectivity = { + psc_allowed_consumer_projects = [var.project_id] + } + } + ## define a consumer project with an endpoint within the project + name = "db" + region = var.region + availability_type = "REGIONAL" + database_version = "POSTGRES_13" + tier = "db-g1-small" + gcp_deletion_protection = false + terraform_deletion_protection = false +} diff --git a/tests/fixtures/cloudsql-kms-iam-grant.tf b/tests/fixtures/cloudsql-kms-iam-grant.tf new file mode 100644 index 0000000000..9ea53a0268 --- /dev/null +++ b/tests/fixtures/cloudsql-kms-iam-grant.tf @@ -0,0 +1,23 @@ +/** + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +resource "google_kms_crypto_key_iam_binding" "encrypt_decrypt" { + crypto_key_id = var.kms_key.id + members = [ + "serviceAccount:service-${var.project_number}@gcp-sa-cloud-sql.iam.gserviceaccount.com" + ] + role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" +} diff --git a/tests/modules/cloudsql_instance/examples/insights.yaml b/tests/modules/cloudsql_instance/examples/insights.yaml index 84a4245ddf..a2c46f5b9b 100644 --- a/tests/modules/cloudsql_instance/examples/insights.yaml +++ b/tests/modules/cloudsql_instance/examples/insights.yaml @@ -17,11 +17,11 @@ values: database_version: POSTGRES_13 name: db project: project-id - region: europe-west1 + region: europe-west8 settings: - activation_policy: ALWAYS availability_type: ZONAL - deletion_protection_enabled: true + deletion_protection_enabled: false disk_autoresize: true disk_type: PD_SSD insights_config: diff --git a/tests/modules/cloudsql_instance/examples/psc.yaml b/tests/modules/cloudsql_instance/examples/psc.yaml new file mode 100644 index 0000000000..722700d7bd --- /dev/null +++ b/tests/modules/cloudsql_instance/examples/psc.yaml @@ -0,0 +1,38 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +values: + module.db.google_sql_database_instance.primary: + database_version: POSTGRES_13 + deletion_protection: false + name: myprefix-db + project: project-id + region: europe-west8 + settings: + - activation_policy: ALWAYS + availability_type: REGIONAL + deletion_protection_enabled: false + ip_configuration: + - ipv4_enabled: false + private_network: null + psc_config: + - allowed_consumer_projects: + - project-id + psc_enabled: true + tier: db-g1-small + +counts: + google_sql_database_instance: 1 + modules: 1 + resources: 1 diff --git a/tests/modules/cloudsql_instance/examples/public-ip.yaml b/tests/modules/cloudsql_instance/examples/public-ip.yaml index f3ca86d3a5..e216ee3b0f 100644 --- a/tests/modules/cloudsql_instance/examples/public-ip.yaml +++ b/tests/modules/cloudsql_instance/examples/public-ip.yaml @@ -17,30 +17,11 @@ values: database_version: MYSQL_8_0 name: db project: project-id - region: europe-west1 + region: europe-west8 settings: - activation_policy: ALWAYS availability_type: ZONAL - deletion_protection_enabled: true - disk_autoresize: true - disk_type: PD_SSD - insights_config: [] - ip_configuration: - - allocated_ip_range: null - authorized_networks: [] - ipv4_enabled: true - private_network: projects/xxx/global/networks/aaa - tier: db-g1-small - module.db.google_sql_database_instance.replicas["replica1"]: - database_version: MYSQL_8_0 - master_instance_name: db - name: replica1 - project: project-id - region: europe-west3 - settings: - - activation_policy: ALWAYS - availability_type: ZONAL - deletion_protection_enabled: true + deletion_protection_enabled: false disk_autoresize: true disk_type: PD_SSD insights_config: [] @@ -52,4 +33,4 @@ values: tier: db-g1-small counts: - google_sql_database_instance: 2 + google_sql_database_instance: 1 diff --git a/tests/modules/cloudsql_instance/examples/replicas.yaml b/tests/modules/cloudsql_instance/examples/replicas.yaml index 1ed30f9bc9..bb337d4457 100644 --- a/tests/modules/cloudsql_instance/examples/replicas.yaml +++ b/tests/modules/cloudsql_instance/examples/replicas.yaml @@ -18,7 +18,7 @@ values: database_version: POSTGRES_13 name: myprefix-db project: project-id - region: europe-west1 + region: europe-west8 module.db.google_sql_database_instance.replicas["replica1"]: clone: [] database_version: POSTGRES_13 diff --git a/tests/modules/cloudsql_instance/examples/simple.yaml b/tests/modules/cloudsql_instance/examples/simple.yaml index 5103c12b4e..4221eb288c 100644 --- a/tests/modules/cloudsql_instance/examples/simple.yaml +++ b/tests/modules/cloudsql_instance/examples/simple.yaml @@ -16,10 +16,10 @@ values: module.db.google_sql_database_instance.primary: clone: [] database_version: POSTGRES_13 - deletion_protection: true + deletion_protection: false name: db - project: my-db-project - region: europe-west1 + project: test-db-prj + region: europe-west8 restore_backup_context: [] root_password: null settings: @@ -30,7 +30,7 @@ values: collation: null data_cache_config: [] database_flags: [] - deletion_protection_enabled: true + deletion_protection_enabled: false deny_maintenance_period: [] disk_autoresize: true disk_autoresize_limit: 0 @@ -54,25 +54,25 @@ values: module.project.google_project.project[0]: auto_create_network: false billing_account: 123456-123456-123456 - folder_id: null + folder_id: '1122334455' labels: null - name: my-db-project - org_id: '1122334455' - project_id: my-db-project + name: test-db-prj + org_id: null + project_id: test-db-prj skip_delete: false timeouts: null module.project.google_project_iam_member.servicenetworking[0]: condition: [] - project: my-db-project + project: test-db-prj role: roles/servicenetworking.serviceAgent module.project.google_project_service.project_services["servicenetworking.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: my-db-project + project: test-db-prj service: servicenetworking.googleapis.com timeouts: null module.project.google_project_service_identity.servicenetworking[0]: - project: my-db-project + project: test-db-prj service: servicenetworking.googleapis.com timeouts: null module.vpc.google_compute_global_address.psa_ranges["servicenetworking-googleapis-com-cloud-sql"]: @@ -82,7 +82,7 @@ values: ip_version: null name: servicenetworking-googleapis-com-cloud-sql prefix_length: 16 - project: my-db-project + project: test-db-prj purpose: VPC_PEERING timeouts: null module.vpc.google_compute_network.network[0]: @@ -92,14 +92,14 @@ values: enable_ula_internal_ipv6: null name: my-network network_firewall_policy_enforcement_order: AFTER_CLASSIC_FIREWALL - project: my-db-project + project: test-db-prj routing_mode: GLOBAL timeouts: null module.vpc.google_compute_network_peering_routes_config.psa_routes["servicenetworking.googleapis.com"]: export_custom_routes: false import_custom_routes: false network: my-network - project: my-db-project + project: test-db-prj timeouts: null module.vpc.google_compute_route.gateway["private-googleapis"]: description: Terraform-managed. @@ -111,7 +111,7 @@ values: next_hop_instance: null next_hop_vpn_tunnel: null priority: 1000 - project: my-db-project + project: test-db-prj tags: null timeouts: null module.vpc.google_compute_route.gateway["restricted-googleapis"]: @@ -124,11 +124,11 @@ values: next_hop_instance: null next_hop_vpn_tunnel: null priority: 1000 - project: my-db-project + project: test-db-prj tags: null timeouts: null module.vpc.google_service_networking_connection.psa_connection["servicenetworking.googleapis.com"]: - deletion_policy: null + deletion_policy: ABANDON reserved_peering_ranges: - servicenetworking-googleapis-com-cloud-sql service: servicenetworking.googleapis.com @@ -141,11 +141,11 @@ counts: google_compute_route: 2 google_project: 1 google_project_iam_member: 1 - google_project_service: 1 - google_project_service_identity: 1 + google_project_service: 2 + google_project_service_identity: 2 google_service_networking_connection: 1 google_sql_database_instance: 1 modules: 3 - resources: 11 + resources: 14 outputs: {} diff --git a/tests/modules/net_address/examples/psc-service-attachment.yaml b/tests/modules/net_address/examples/psc-service-attachment.yaml new file mode 100644 index 0000000000..7c3eaca02a --- /dev/null +++ b/tests/modules/net_address/examples/psc-service-attachment.yaml @@ -0,0 +1,29 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +values: + module.addresses.google_compute_forwarding_rule.psc_consumer["cloudsql-one"]: + load_balancing_scheme: '' + name: cloudsql-one + project: project-id + recreate_closed_psc: true + region: europe-west8 + subnetwork: subnet_self_link + module.addresses.google_compute_address.psc["cloudsql-one"]: + address: 10.0.16.32 + address_type: INTERNAL + description: Terraform managed. + name: cloudsql-one + project: project-id + subnetwork: subnet_self_link diff --git a/tests/modules/net_cloudnat/examples/hybrid.yaml b/tests/modules/net_cloudnat/examples/hybrid.yaml new file mode 100644 index 0000000000..4dd1939598 --- /dev/null +++ b/tests/modules/net_cloudnat/examples/hybrid.yaml @@ -0,0 +1,94 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +values: + module.vpc1-nat.google_compute_router.router[0]: + bgp: [] + description: null + encrypted_interconnect_router: null + name: vpc1-nat-nat + project: project-id + region: europe-west8 + module.vpc1-nat.google_compute_router_nat.nat: + drain_nat_ips: null + enable_dynamic_port_allocation: true + enable_endpoint_independent_mapping: false + icmp_idle_timeout_sec: 30 + log_config: + - enable: false + filter: ALL + max_ports_per_vm: null + name: vpc1-nat + nat_ip_allocate_option: null + nat_ips: null + project: project-id + region: europe-west8 + router: vpc1-nat-nat + rules: + - action: + - source_nat_active_ips: [] + source_nat_drain_ips: [] + source_nat_drain_ranges: [] + description: private nat + match: nexthop.is_hybrid + rule_number: 0 + source_subnetwork_ip_ranges_to_nat: LIST_OF_SUBNETWORKS + subnetwork: + - secondary_ip_range_names: [] + source_ip_ranges_to_nat: + - ALL_IP_RANGES + tcp_established_idle_timeout_sec: 1200 + tcp_time_wait_timeout_sec: 120 + tcp_transitory_idle_timeout_sec: 30 + type: PRIVATE + udp_idle_timeout_sec: 30 + module.vpc1.google_compute_network.network[0]: + auto_create_subnetworks: false + delete_default_routes_on_create: false + description: Terraform-managed. + enable_ula_internal_ipv6: null + name: vpc1 + network_firewall_policy_enforcement_order: AFTER_CLASSIC_FIREWALL + project: project-id + routing_mode: GLOBAL + module.vpc1.google_compute_subnetwork.private_nat["europe-west8/vpc1-nat"]: + description: Terraform-managed private NAT subnet. + ip_cidr_range: 192.168.15.0/24 + ipv6_access_type: null + log_config: [] + name: vpc1-nat + network: vpc1 + project: project-id + purpose: PRIVATE_NAT + region: europe-west8 + role: null + module.vpc1.google_compute_subnetwork.subnetwork["europe-west8/vpc1-subnet"]: + description: Terraform-managed. + ip_cidr_range: 10.0.0.0/24 + ipv6_access_type: null + log_config: [] + name: vpc1-subnet + network: vpc1 + private_ip_google_access: true + project: project-id + region: europe-west8 + role: null + secondary_ip_range: [] + +counts: + google_compute_network: 1 + google_compute_route: 2 + google_compute_router: 1 + google_compute_router_nat: 1 + google_compute_subnetwork: 2 diff --git a/tests/modules/net_vpc/examples/psa-routes.yaml b/tests/modules/net_vpc/examples/psa-routes.yaml index c64353b788..a9a8bfddb3 100644 --- a/tests/modules/net_vpc/examples/psa-routes.yaml +++ b/tests/modules/net_vpc/examples/psa-routes.yaml @@ -84,9 +84,9 @@ values: - servicenetworking-googleapis-com-myrange service: servicenetworking.googleapis.com timeouts: null - module.vpc.google_service_networking_peered_dns_domain.name["servicenetworking-googleapis-com-gcp-example-com-"]: + module.vpc.google_service_networking_peered_dns_domain.name["servicenetworking-googleapis-com-gcp-example-com"]: dns_suffix: gcp.example.com. - name: servicenetworking-googleapis-com-gcp-example-com- + name: servicenetworking-googleapis-com-gcp-example-com network: my-network project: project-id service: servicenetworking.googleapis.com diff --git a/tests/modules/organization/examples/tags.yaml b/tests/modules/organization/examples/tags.yaml index bed4b46188..cce3674346 100644 --- a/tests/modules/organization/examples/tags.yaml +++ b/tests/modules/organization/examples/tags.yaml @@ -23,11 +23,20 @@ values: purpose_data: null short_name: environment timeouts: null + module.org.google_tags_tag_key_iam_binding.bindings["environment:viewer"]: + condition: [] + members: + - group:gcp-support@example.org + role: roles/resourcemanager.tagViewer module.org.google_tags_tag_key_iam_binding.default["environment:roles/resourcemanager.tagAdmin"]: condition: [] members: - group:organization-admins@example.org role: roles/resourcemanager.tagAdmin + module.org.google_tags_tag_key_iam_member.bindings["environment:user_app1"]: + condition: [] + member: group:app1-team@example.org + role: roles/resourcemanager.tagUser module.org.google_tags_tag_value.default["environment/dev"]: description: Managed by the Terraform organization module. short_name: dev @@ -36,14 +45,28 @@ values: description: 'Environment: production.' short_name: prod timeouts: null + module.org.google_tags_tag_value_iam_binding.bindings["environment/prod:admin"]: + condition: [] + members: + - group:gcp-support@example.org + role: roles/resourcemanager.tagAdmin module.org.google_tags_tag_value_iam_binding.default["environment/prod:roles/resourcemanager.tagViewer"]: condition: [] members: - - group:organization-admins@example.org + - group:app1-team@example.org role: roles/resourcemanager.tagViewer + module.org.google_tags_tag_value_iam_member.bindings["environment/dev:user_app2"]: + condition: [] + member: group:app2-team@example.org + role: roles/resourcemanager.tagUser counts: google_tags_tag_binding: 1 google_tags_tag_key: 1 - google_tags_tag_key_iam_binding: 1 + google_tags_tag_key_iam_binding: 2 + google_tags_tag_key_iam_member: 1 google_tags_tag_value: 2 + google_tags_tag_value_iam_binding: 2 + google_tags_tag_value_iam_member: 1 + modules: 1 + resources: 10 diff --git a/tests/modules/organization/test_plan_org_policies_modules.py b/tests/modules/organization/test_plan_org_policies_modules.py index 632b45e726..f8839fc251 100644 --- a/tests/modules/organization/test_plan_org_policies_modules.py +++ b/tests/modules/organization/test_plan_org_policies_modules.py @@ -37,8 +37,8 @@ def test_policy_implementation(): '@@ -55,2 +55,2 @@\n', '- name = "projects/${local.project.project_id}/policies/${k}"\n', '- parent = "projects/${local.project.project_id}"\n', - '+ name = "${local.folder.name}/policies/${k}"\n', - '+ parent = local.folder.name\n', + '+ name = "${local.folder_id}/policies/${k}"\n', + '+ parent = local.folder_id\n', ] diff2 = difflib.unified_diff(lines['folder'], lines['organization'], 'folder', @@ -50,8 +50,8 @@ def test_policy_implementation(): '-# tfdoc:file:description Folder-level organization policies.\n', '+# tfdoc:file:description Organization-level organization policies.\n', '@@ -55,2 +55,2 @@\n', - '- name = "${local.folder.name}/policies/${k}"\n', - '- parent = local.folder.name\n', + '- name = "${local.folder_id}/policies/${k}"\n', + '- parent = local.folder_id\n', '+ name = "${var.organization_id}/policies/${k}"\n', '+ parent = var.organization_id\n', '@@ -113,0 +114,9 @@\n', diff --git a/tests/modules/pubsub/examples/subscriptions.yaml b/tests/modules/pubsub/examples/subscriptions.yaml index 89acf08b22..267f4ebc5c 100644 --- a/tests/modules/pubsub/examples/subscriptions.yaml +++ b/tests/modules/pubsub/examples/subscriptions.yaml @@ -20,7 +20,8 @@ values: enable_exactly_once_delivery: false enable_message_ordering: false filter: null - labels: null + labels: + test: default message_retention_duration: 604800s name: test-pull project: project-id @@ -52,7 +53,8 @@ values: topic: my-topic module.pubsub.google_pubsub_topic.default: kms_key_name: null - labels: null + labels: + test: default message_retention_duration: null name: my-topic project: project-id diff --git a/tests/modules/vpc_sc/examples/factory.yaml b/tests/modules/vpc_sc/examples/factory.yaml index 475c4d1e89..4496566709 100644 --- a/tests/modules/vpc_sc/examples/factory.yaml +++ b/tests/modules/vpc_sc/examples/factory.yaml @@ -81,9 +81,27 @@ values: - access_level: '*' resource: null ingress_to: - - operations: [] + - operations: + - method_selectors: + - method: ProjectsService.Get + permission: null + - method: RegionsService.Get + permission: null + service_name: compute.googleapis.com resources: - '*' + - ingress_from: + - identities: + - serviceAccount:test-tf@myproject.iam.gserviceaccount.com + identity_type: null + sources: + - resource: null + ingress_to: + - operations: + - method_selectors: [] + service_name: '*' + resources: + - projects/1234567890 resources: - projects/11111 - projects/111111