From 68dea5530a93789c440f94cd10793661afb0db8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Legrand?= Date: Mon, 30 Oct 2023 17:26:06 +0100 Subject: [PATCH 01/29] Handling SQL IP address issue (#1825) * Handling SQL IP address issue * reverting one change * Improving this fix based on wiktor's feedback * formatting --- .../network-dashboard/src/plugins/discover-cai.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blueprints/cloud-operations/network-dashboard/src/plugins/discover-cai.py b/blueprints/cloud-operations/network-dashboard/src/plugins/discover-cai.py index 246ebfe0d6..5a87d93b4f 100644 --- a/blueprints/cloud-operations/network-dashboard/src/plugins/discover-cai.py +++ b/blueprints/cloud-operations/network-dashboard/src/plugins/discover-cai.py @@ -217,7 +217,7 @@ def _handle_sql_instances(resource, data): 'self_link': _self_link(data['selfLink']), 'ipAddresses': [ i['ipAddress'] - for i in data.get('ipAddresses') + for i in data.get('ipAddresses', []) if i['type'] == 'PRIVATE' ], 'region': data['region'], From 96c1342d5512f7add149c1883764766b4302ab09 Mon Sep 17 00:00:00 2001 From: devuonocar Date: Mon, 30 Oct 2023 18:23:33 +0100 Subject: [PATCH 02/29] Add public_access_prevention --- modules/gcs/README.md | 1 + modules/gcs/main.tf | 1 + modules/gcs/variables.tf | 6 ++++++ 3 files changed, 8 insertions(+) diff --git a/modules/gcs/README.md b/modules/gcs/README.md index 8a26958d62..a04f965681 100644 --- a/modules/gcs/README.md +++ b/modules/gcs/README.md @@ -196,6 +196,7 @@ module "bucket" { | [notification_config](variables.tf#L169) | GCS Notification configuration. | object({…}) | | null | | [objects_to_upload](variables.tf#L183) | Objects to be uploaded to bucket. | map(object({…})) | | {} | | [prefix](variables.tf#L209) | Optional prefix used to generate the bucket name. | string | | null | +| [public_access_prevention](variables.tf#L224) | Prevents public access to a bucket. Acceptable values are inherited or enforced. If inherited, the bucket uses public access prevention, only if the bucket is subject to the public access prevention organization policy constraint. | string | | "inherited" | | [requester_pays](variables.tf#L224) | Enables Requester Pays on a storage bucket. | bool | | null | | [retention_policy](variables.tf#L230) | Bucket retention policy. | object({…}) | | null | | [storage_class](variables.tf#L239) | Bucket storage class. | string | | "MULTI_REGIONAL" | diff --git a/modules/gcs/main.tf b/modules/gcs/main.tf index 1341e707cd..c19c7912e0 100644 --- a/modules/gcs/main.tf +++ b/modules/gcs/main.tf @@ -29,6 +29,7 @@ resource "google_storage_bucket" "bucket" { labels = var.labels default_event_based_hold = var.default_event_based_hold requester_pays = var.requester_pays + public_access_prevention = var.public_access_prevention versioning { enabled = var.versioning } diff --git a/modules/gcs/variables.tf b/modules/gcs/variables.tf index 350c74baf5..4f7b9274ee 100644 --- a/modules/gcs/variables.tf +++ b/modules/gcs/variables.tf @@ -221,6 +221,12 @@ variable "project_id" { type = string } +variable "public_access_prevention" { + description = "Prevents public access to a bucket. Acceptable values are inherited or enforced. If inherited, the bucket uses public access prevention, only if the bucket is subject to the public access prevention organization policy constraint." + type = string + default = "inherited" +} + variable "requester_pays" { description = "Enables Requester Pays on a storage bucket." type = bool From e52af055047c6aa582991061d60bd279831ae75a Mon Sep 17 00:00:00 2001 From: devuonocar Date: Mon, 30 Oct 2023 18:34:55 +0100 Subject: [PATCH 03/29] Update README.md --- modules/gcs/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/gcs/README.md b/modules/gcs/README.md index a04f965681..326baa19c3 100644 --- a/modules/gcs/README.md +++ b/modules/gcs/README.md @@ -197,12 +197,12 @@ module "bucket" { | [objects_to_upload](variables.tf#L183) | Objects to be uploaded to bucket. | map(object({…})) | | {} | | [prefix](variables.tf#L209) | Optional prefix used to generate the bucket name. | string | | null | | [public_access_prevention](variables.tf#L224) | Prevents public access to a bucket. Acceptable values are inherited or enforced. If inherited, the bucket uses public access prevention, only if the bucket is subject to the public access prevention organization policy constraint. | string | | "inherited" | -| [requester_pays](variables.tf#L224) | Enables Requester Pays on a storage bucket. | bool | | null | -| [retention_policy](variables.tf#L230) | Bucket retention policy. | object({…}) | | null | -| [storage_class](variables.tf#L239) | Bucket storage class. | string | | "MULTI_REGIONAL" | -| [uniform_bucket_level_access](variables.tf#L249) | Allow using object ACLs (false) or not (true, this is the recommended behavior) , defaults to true (which is the recommended practice, but not the behavior of storage API). | bool | | true | -| [versioning](variables.tf#L255) | Enable versioning, defaults to false. | bool | | false | -| [website](variables.tf#L261) | Bucket website. | object({…}) | | null | +| [requester_pays](variables.tf#L230) | Enables Requester Pays on a storage bucket. | bool | | null | +| [retention_policy](variables.tf#L236) | Bucket retention policy. | object({…}) | | null | +| [storage_class](variables.tf#L245) | Bucket storage class. | string | | "MULTI_REGIONAL" | +| [uniform_bucket_level_access](variables.tf#L255) | Allow using object ACLs (false) or not (true, this is the recommended behavior) , defaults to true (which is the recommended practice, but not the behavior of storage API). | bool | | true | +| [versioning](variables.tf#L261) | Enable versioning, defaults to false. | bool | | false | +| [website](variables.tf#L267) | Bucket website. | object({…}) | | null | ## Outputs From 103388bcc9a7e1c965061d9cab0b4ccd91986c68 Mon Sep 17 00:00:00 2001 From: devuonocar Date: Tue, 31 Oct 2023 10:47:28 +0100 Subject: [PATCH 04/29] Update default value --- modules/gcs/README.md | 2 +- modules/gcs/variables.tf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/gcs/README.md b/modules/gcs/README.md index 326baa19c3..993e0435ff 100644 --- a/modules/gcs/README.md +++ b/modules/gcs/README.md @@ -196,7 +196,7 @@ module "bucket" { | [notification_config](variables.tf#L169) | GCS Notification configuration. | object({…}) | | null | | [objects_to_upload](variables.tf#L183) | Objects to be uploaded to bucket. | map(object({…})) | | {} | | [prefix](variables.tf#L209) | Optional prefix used to generate the bucket name. | string | | null | -| [public_access_prevention](variables.tf#L224) | Prevents public access to a bucket. Acceptable values are inherited or enforced. If inherited, the bucket uses public access prevention, only if the bucket is subject to the public access prevention organization policy constraint. | string | | "inherited" | +| [public_access_prevention](variables.tf#L224) | Prevents public access to a bucket. Acceptable values are inherited or enforced. If inherited, the bucket uses public access prevention, only if the bucket is subject to the public access prevention organization policy constraint. | string | | null | | [requester_pays](variables.tf#L230) | Enables Requester Pays on a storage bucket. | bool | | null | | [retention_policy](variables.tf#L236) | Bucket retention policy. | object({…}) | | null | | [storage_class](variables.tf#L245) | Bucket storage class. | string | | "MULTI_REGIONAL" | diff --git a/modules/gcs/variables.tf b/modules/gcs/variables.tf index 4f7b9274ee..de8a6abd83 100644 --- a/modules/gcs/variables.tf +++ b/modules/gcs/variables.tf @@ -224,7 +224,7 @@ variable "project_id" { variable "public_access_prevention" { description = "Prevents public access to a bucket. Acceptable values are inherited or enforced. If inherited, the bucket uses public access prevention, only if the bucket is subject to the public access prevention organization policy constraint." type = string - default = "inherited" + default = null } variable "requester_pays" { From 8d06afcdb8e8e8a110f4c8832735c8cbb6c2ee57 Mon Sep 17 00:00:00 2001 From: alealr Date: Tue, 31 Oct 2023 14:35:27 +0000 Subject: [PATCH 05/29] Updating wording --- fast/stages/0-bootstrap/README.md | 2 +- modules/gcve-private-cloud/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fast/stages/0-bootstrap/README.md b/fast/stages/0-bootstrap/README.md index 1a9f1bbbd8..9ed7528916 100644 --- a/fast/stages/0-bootstrap/README.md +++ b/fast/stages/0-bootstrap/README.md @@ -72,7 +72,7 @@ A full reference of IAM roles managed by this stage [is available here](./IAM.md It's often desirable to have organization policies deployed before any other resource in the org, so as to ensure compliance with specific requirements (e.g. location restrictions), or control the configuration of specific resources (e.g. default network at project creation or service account grants). -To cover this use case, organization policies have been moved from the resource management to the bootstrap stage in FAST versions after 26.0.0. They are managed via the usual factory approach, and a [sample set of data files](./data/org-policies/) is included with this stage. They are not applied during the initial run when the `bootstrap_user` variable is set, to work around incompatibilies with user credentials. +To cover this use case, organization policies have been moved from the resource management to the bootstrap stage in FAST versions after 26.0.0. They are managed via the usual factory approach, and a [sample set of data files](./data/org-policies/) is included with this stage. They are not applied during the initial run when the `bootstrap_user` variable is set, to work around incompatibilities with user credentials. The only current exception to the factory approach is the `iam.allowedPolicyMemberDomains` constraint, which is managed in code so as to be able to auto-allow the organization's domain. More domains can be added via the `org_policies_config` variable, which also serves as an umbrella for future policies that will need to be managed in code. diff --git a/modules/gcve-private-cloud/README.md b/modules/gcve-private-cloud/README.md index 901b307971..0e3a9ef7b3 100644 --- a/modules/gcve-private-cloud/README.md +++ b/modules/gcve-private-cloud/README.md @@ -2,7 +2,7 @@ This module implements the creation and management of a Google Cloud VMWare Engine Private Cloud with its management cluster. If configured, it also creates the VMWare engine network or it can work with an existing one. The creation of the private connection with the user VPC requires the execution of the [Google SDK command](https://cloud.google.com/sdk/gcloud/reference/vmware/private-connections/create#--routing-mode) the module provides as an output. -To understand the limits and to propertly configure the vSphere/vSAN subnets CIDR range please refer to the [GCVE public documetation](https://cloud.google.com/vmware-engine/docs/quickstart-networking-requirements). +To understand the limits and to properly configure the vSphere/vSAN subnets CIDR range please refer to the [GCVE public documentation](https://cloud.google.com/vmware-engine/docs/quickstart-networking-requirements). Be aware that the deployment of this module might require up to 2 hours depending on the selected private cloud target zone. From 17707da60a17b6601b0258d0621a8b652f0d5be8 Mon Sep 17 00:00:00 2001 From: cmalpe Date: Wed, 1 Nov 2023 07:58:09 +0000 Subject: [PATCH 06/29] added stack_type field --- modules/net-vpc-peering/README.md | 1 + modules/net-vpc-peering/main.tf | 2 ++ modules/net-vpc-peering/variables.tf | 6 ++++++ 3 files changed, 9 insertions(+) diff --git a/modules/net-vpc-peering/README.md b/modules/net-vpc-peering/README.md index 0998d7b3ed..3046ffd64d 100644 --- a/modules/net-vpc-peering/README.md +++ b/modules/net-vpc-peering/README.md @@ -82,6 +82,7 @@ module "peering" { | [peer_create_peering](variables.tf#L22) | Create the peering on the remote side. If false, only the peering from this network to the remote network is created. | bool | | true | | [prefix](variables.tf#L33) | Optional name prefix for the network peerings. | string | | null | | [routes_config](variables.tf#L43) | Control import/export for local and remote peer. Remote configuration is only used when creating remote peering. | object({…}) | | {} | +| [stack_type](variables.tf#L63) | IP version(s) of traffic and routes that are allowed to be imported or exported between peer networks. Possible values: IPV4_ONLY, IPV4_IPV6 | string | | "IPV4_ONLY" | ## Outputs diff --git a/modules/net-vpc-peering/main.tf b/modules/net-vpc-peering/main.tf index 2d88a0b41b..bb754ae8c2 100644 --- a/modules/net-vpc-peering/main.tf +++ b/modules/net-vpc-peering/main.tf @@ -36,6 +36,7 @@ resource "google_compute_network_peering" "local_network_peering" { import_subnet_routes_with_public_ip = try( var.routes_config.local.public_import, null ) + stack_type = var.stack_type } resource "google_compute_network_peering" "peer_network_peering" { @@ -55,5 +56,6 @@ resource "google_compute_network_peering" "peer_network_peering" { import_subnet_routes_with_public_ip = try( var.routes_config.peer.public_import, null ) + stack_type = var.stack_type depends_on = [google_compute_network_peering.local_network_peering] } diff --git a/modules/net-vpc-peering/variables.tf b/modules/net-vpc-peering/variables.tf index ade807415b..4f1ad113f8 100644 --- a/modules/net-vpc-peering/variables.tf +++ b/modules/net-vpc-peering/variables.tf @@ -59,3 +59,9 @@ variable "routes_config" { nullable = false default = {} } + +variable "stack_type" { + description = "IP version(s) of traffic and routes that are allowed to be imported or exported between peer networks. Possible values: IPV4_ONLY, IPV4_IPV6" + type = string + default = "IPV4_ONLY" +} \ No newline at end of file From f1972550fee4dc48a8724a4ed5f5a9aad66e75c9 Mon Sep 17 00:00:00 2001 From: cmalpe Date: Wed, 1 Nov 2023 08:02:36 +0000 Subject: [PATCH 07/29] fixed linting for variables file --- modules/net-vpc-peering/variables.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/net-vpc-peering/variables.tf b/modules/net-vpc-peering/variables.tf index 4f1ad113f8..aa3aec47c7 100644 --- a/modules/net-vpc-peering/variables.tf +++ b/modules/net-vpc-peering/variables.tf @@ -61,7 +61,7 @@ variable "routes_config" { } variable "stack_type" { - description = "IP version(s) of traffic and routes that are allowed to be imported or exported between peer networks. Possible values: IPV4_ONLY, IPV4_IPV6" + description = "IP version(s) of traffic and routes that are allowed to be imported or exported between peer networks. Possible values: IPV4_ONLY, IPV4_IPV6." type = string default = "IPV4_ONLY" } \ No newline at end of file From 103107656954b0bd706fe95310ccfd2e520ae5e9 Mon Sep 17 00:00:00 2001 From: cmalpe Date: Wed, 1 Nov 2023 09:18:49 +0000 Subject: [PATCH 08/29] added validation for stack_type --- modules/net-vpc-peering/README.md | 2 +- modules/net-vpc-peering/variables.tf | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/net-vpc-peering/README.md b/modules/net-vpc-peering/README.md index 3046ffd64d..1def1ad19a 100644 --- a/modules/net-vpc-peering/README.md +++ b/modules/net-vpc-peering/README.md @@ -82,7 +82,7 @@ module "peering" { | [peer_create_peering](variables.tf#L22) | Create the peering on the remote side. If false, only the peering from this network to the remote network is created. | bool | | true | | [prefix](variables.tf#L33) | Optional name prefix for the network peerings. | string | | null | | [routes_config](variables.tf#L43) | Control import/export for local and remote peer. Remote configuration is only used when creating remote peering. | object({…}) | | {} | -| [stack_type](variables.tf#L63) | IP version(s) of traffic and routes that are allowed to be imported or exported between peer networks. Possible values: IPV4_ONLY, IPV4_IPV6 | string | | "IPV4_ONLY" | +| [stack_type](variables.tf#L63) | IP version(s) of traffic and routes that are allowed to be imported or exported between peer networks. Possible values: IPV4_ONLY, IPV4_IPV6. | string | | null | ## Outputs diff --git a/modules/net-vpc-peering/variables.tf b/modules/net-vpc-peering/variables.tf index aa3aec47c7..9058da1ded 100644 --- a/modules/net-vpc-peering/variables.tf +++ b/modules/net-vpc-peering/variables.tf @@ -63,5 +63,9 @@ variable "routes_config" { variable "stack_type" { description = "IP version(s) of traffic and routes that are allowed to be imported or exported between peer networks. Possible values: IPV4_ONLY, IPV4_IPV6." type = string - default = "IPV4_ONLY" + default = null + validation { + condition = var.stack_type == "IPV4_ONLY" || var.stack_type == "IPV4_IPV6" || var.stack_type == null + error_message = "The stack_type must be either 'IPV4_ONLY' or 'IPV4_IPV6'." + } } \ No newline at end of file From a0ae43fc6f4dfddcd4bd1c99d03a8a7714ace9bb Mon Sep 17 00:00:00 2001 From: lcaggio Date: Wed, 1 Nov 2023 17:53:06 +0100 Subject: [PATCH 09/29] [Minimal Data Platform] Fix Landing and curated IAM (#1832) * Fix IAM on Minimal DP * fix --- .../data-solutions/data-platform-minimal/01-landing.tf | 5 +++-- .../data-solutions/data-platform-minimal/03-curated.tf | 8 ++++---- blueprints/data-solutions/data-platform-minimal/IAM.md | 5 +++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/blueprints/data-solutions/data-platform-minimal/01-landing.tf b/blueprints/data-solutions/data-platform-minimal/01-landing.tf index 2b4d5165fa..3539e001ac 100644 --- a/blueprints/data-solutions/data-platform-minimal/01-landing.tf +++ b/blueprints/data-solutions/data-platform-minimal/01-landing.tf @@ -22,8 +22,9 @@ locals { "roles/storage.objectViewer" = [ module.processing-sa-cmp-0.iam_email ] - "roles/storage.objectAdmin" = [ - module.processing-sa-0.iam_email + "roles/storage.admin" = [ + module.processing-sa-0.iam_email, + local.groups_iam.data-engineers ] } # this only works because the service account module uses a static output diff --git a/blueprints/data-solutions/data-platform-minimal/03-curated.tf b/blueprints/data-solutions/data-platform-minimal/03-curated.tf index 81112c9b88..faf9301129 100644 --- a/blueprints/data-solutions/data-platform-minimal/03-curated.tf +++ b/blueprints/data-solutions/data-platform-minimal/03-curated.tf @@ -58,11 +58,11 @@ locals { ] "roles/storage.objectViewer" = [ module.cur-sa-0.iam_email, - local.groups_iam.data-analysts, - local.groups_iam.data-engineers + local.groups_iam.data-analysts ] - "roles/storage.objectAdmin" = [ - module.processing-sa-0.iam_email + "roles/storage.admin" = [ + module.processing-sa-0.iam_email, + local.groups_iam.data-engineers ] } # this only works because the service account module uses a static output diff --git a/blueprints/data-solutions/data-platform-minimal/IAM.md b/blueprints/data-solutions/data-platform-minimal/IAM.md index d5c1ccbb34..ea796fbf0b 100644 --- a/blueprints/data-solutions/data-platform-minimal/IAM.md +++ b/blueprints/data-solutions/data-platform-minimal/IAM.md @@ -16,15 +16,16 @@ Legend: + additive, conditional. | members | roles | |---|---| |gcp-data-analysts
group|[roles/bigquery.dataViewer](https://cloud.google.com/iam/docs/understanding-roles#bigquery.dataViewer)
[roles/bigquery.jobUser](https://cloud.google.com/iam/docs/understanding-roles#bigquery.jobUser)
[roles/datacatalog.tagTemplateViewer](https://cloud.google.com/iam/docs/understanding-roles#datacatalog.tagTemplateViewer)
[roles/datacatalog.viewer](https://cloud.google.com/iam/docs/understanding-roles#datacatalog.viewer)
[roles/storage.objectViewer](https://cloud.google.com/iam/docs/understanding-roles#storage.objectViewer) | -|gcp-data-engineers
group|[roles/bigquery.dataViewer](https://cloud.google.com/iam/docs/understanding-roles#bigquery.dataViewer)
[roles/bigquery.jobUser](https://cloud.google.com/iam/docs/understanding-roles#bigquery.jobUser)
[roles/datacatalog.tagTemplateViewer](https://cloud.google.com/iam/docs/understanding-roles#datacatalog.tagTemplateViewer)
[roles/datacatalog.viewer](https://cloud.google.com/iam/docs/understanding-roles#datacatalog.viewer)
[roles/storage.objectViewer](https://cloud.google.com/iam/docs/understanding-roles#storage.objectViewer) | +|gcp-data-engineers
group|[roles/bigquery.dataViewer](https://cloud.google.com/iam/docs/understanding-roles#bigquery.dataViewer)
[roles/bigquery.jobUser](https://cloud.google.com/iam/docs/understanding-roles#bigquery.jobUser)
[roles/datacatalog.tagTemplateViewer](https://cloud.google.com/iam/docs/understanding-roles#datacatalog.tagTemplateViewer)
[roles/datacatalog.viewer](https://cloud.google.com/iam/docs/understanding-roles#datacatalog.viewer)
[roles/storage.admin](https://cloud.google.com/iam/docs/understanding-roles#storage.admin) | |SERVICE_IDENTITY_service-networking
serviceAccount|[roles/servicenetworking.serviceAgent](https://cloud.google.com/iam/docs/understanding-roles#servicenetworking.serviceAgent) +| |cur-sa-0
serviceAccount|[roles/bigquery.dataViewer](https://cloud.google.com/iam/docs/understanding-roles#bigquery.dataViewer)
[roles/bigquery.jobUser](https://cloud.google.com/iam/docs/understanding-roles#bigquery.jobUser)
[roles/datacatalog.tagTemplateViewer](https://cloud.google.com/iam/docs/understanding-roles#datacatalog.tagTemplateViewer)
[roles/datacatalog.viewer](https://cloud.google.com/iam/docs/understanding-roles#datacatalog.viewer)
[roles/storage.objectViewer](https://cloud.google.com/iam/docs/understanding-roles#storage.objectViewer) | -|prc-0
serviceAccount|[roles/bigquery.dataOwner](https://cloud.google.com/iam/docs/understanding-roles#bigquery.dataOwner)
[roles/bigquery.jobUser](https://cloud.google.com/iam/docs/understanding-roles#bigquery.jobUser)
[roles/storage.objectAdmin](https://cloud.google.com/iam/docs/understanding-roles#storage.objectAdmin) | +|prc-0
serviceAccount|[roles/bigquery.dataOwner](https://cloud.google.com/iam/docs/understanding-roles#bigquery.dataOwner)
[roles/bigquery.jobUser](https://cloud.google.com/iam/docs/understanding-roles#bigquery.jobUser)
[roles/storage.admin](https://cloud.google.com/iam/docs/understanding-roles#storage.admin) | ## Project lnd | members | roles | |---|---| +|gcp-data-engineers
group|[roles/storage.admin](https://cloud.google.com/iam/docs/understanding-roles#storage.admin) | |lnd-sa-0
serviceAccount|[roles/storage.objectCreator](https://cloud.google.com/iam/docs/understanding-roles#storage.objectCreator) | |prc-0
serviceAccount|[roles/storage.objectAdmin](https://cloud.google.com/iam/docs/understanding-roles#storage.objectAdmin) | |prc-cmp-0
serviceAccount|[roles/storage.objectViewer](https://cloud.google.com/iam/docs/understanding-roles#storage.objectViewer) | From de0325b3a32584693c1b63860d6250d36ea8f6b1 Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Thu, 2 Nov 2023 08:24:50 +0100 Subject: [PATCH 10/29] Avoid map-related casting errors in project factory (#1836) * try to repro pf example error * repro * repro * pf fix * remove extra file * FAST stage --- .../factories/project-factory/README.md | 83 ++++++++-- .../factories/project-factory/factory.tf | 25 ++- .../factories/project-factory/variables.tf | 18 +-- fast/stages/3-project-factory/dev/README.md | 4 +- fast/stages/3-project-factory/dev/main.tf | 2 +- .../stages/3-project-factory/dev/variables.tf | 22 +-- .../project_factory/examples/example.yaml | 148 +++++++++++++----- 7 files changed, 204 insertions(+), 98 deletions(-) diff --git a/blueprints/factories/project-factory/README.md b/blueprints/factories/project-factory/README.md index d2d07c43d6..2e67158277 100644 --- a/blueprints/factories/project-factory/README.md +++ b/blueprints/factories/project-factory/README.md @@ -55,11 +55,9 @@ module "project-factory" { prefix = "test-pf" } # location where the yaml files are read from - factory_data = { - data_path = "data" - } + factory_data_path = "data" } -# tftest modules=6 resources=17 files=prj-app-1,prj-app-2 +# tftest modules=7 resources=26 files=prj-app-1,prj-app-2,prj-app-3 inventory=example.yaml ``` ```yaml @@ -72,7 +70,8 @@ service_encryption_key_ids: compute: - projects/kms-central-prj/locations/europe-west3/keyRings/my-keyring/cryptoKeys/europe3-gce services: -- storage.googleapis.com + - container.googleapis.com + - storage.googleapis.com service_accounts: app-1-be: iam_project_roles: @@ -86,29 +85,35 @@ service_accounts: ```yaml labels: - app: app-1 + app: app-2 team: foo parent: folders/12345678 service_accounts: app-2-be: {} -org_policies: - compute.disableGuestAttributesAccess: - rules: - - enforce: false - iam.disableServiceAccountKeyCreation: - rules: - - enforce: false +services: +- compute.googleapis.com +- run.googleapis.com +- storage.googleapis.com shared_vpc_service_config: host_project: foo-host # tftest-file id=prj-app-2 path=data/prj-app-2.yaml ``` + +```yaml +parent: folders/12345678 +services: +- run.googleapis.com +- storage.googleapis.com + +# tftest-file id=prj-app-3 path=data/prj-app-3.yaml +``` ## Variables | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [factory_data](variables.tf#L88) | Project data from either YAML files or externally parsed data. | object({…}) | ✓ | | +| [factory_data_path](variables.tf#L88) | Path to folder with YAML project description data files. | string | ✓ | | | [data_defaults](variables.tf#L17) | Optional default values used when corresponding project data from files are missing. | object({…}) | | {} | | [data_merges](variables.tf#L46) | Optional values that will be merged with corresponding data from files. Combines with `data_defaults`, file data, and `data_overrides`. | object({…}) | | {} | | [data_overrides](variables.tf#L66) | Optional values that override corresponding data from files. Takes precedence over file data and `data_defaults`. | object({…}) | | {} | @@ -120,3 +125,53 @@ shared_vpc_service_config: | [projects](outputs.tf#L17) | Project module outputs. | | | [service_accounts](outputs.tf#L22) | Service account emails. | | +## Tests + +These tests validate fixes to the project factory. + +```hcl +module "project-factory" { + source = "./fabric/blueprints/factories/project-factory" + data_defaults = { + billing_account = "012345-67890A-ABCDEF" + } + data_merges = { + labels = { + owner = "foo" + } + services = [ + "compute.googleapis.com" + ] + } + data_overrides = { + prefix = "foo" + } + factory_data_path = "data" +} +# tftest modules=4 resources=14 files=test-0,test-1,test-2 +``` + +```yaml +parent: folders/1234567890 +services: + - iam.googleapis.com + - contactcenteraiplatform.googleapis.com + - container.googleapis.com +# tftest-file id=test-0 path=data/test-0.yaml +``` + +```yaml +parent: folders/1234567890 +services: + - iam.googleapis.com + - contactcenteraiplatform.googleapis.com +# tftest-file id=test-1 path=data/test-1.yaml +``` + +```yaml +parent: folders/1234567890 +services: + - iam.googleapis.com + - storage.googleapis.com +# tftest-file id=test-2 path=data/test-2.yaml +``` diff --git a/blueprints/factories/project-factory/factory.tf b/blueprints/factories/project-factory/factory.tf index e0351a0aa1..b2187f717b 100644 --- a/blueprints/factories/project-factory/factory.tf +++ b/blueprints/factories/project-factory/factory.tf @@ -15,19 +15,18 @@ */ locals { - _data = ( - var.factory_data.data != null - ? var.factory_data.data - : { - for f in fileset("${local._data_path}", "**/*.yaml") : - trimsuffix(f, ".yaml") => yamldecode(file("${local._data_path}/${f}")) - } - ) - _data_path = var.factory_data.data_path == null ? null : pathexpand( - var.factory_data.data_path - ) + # turn the set of file names into a list for index-based access later on + _factory_files = [ + for f in fileset("${pathexpand(var.factory_data_path)}", "**/*.yaml") : f + ] + # use a list to store data to avoid map enforcing the same type for all + _factory_data = [ + for f in local._factory_files : + yamldecode(file("${pathexpand(var.factory_data_path)}/${f}")) + ] + # assemble final data, emulating optionals and using defaults and merges projects = { - for k, v in local._data : k => merge(v, { + for i, v in local._factory_data : trimsuffix(local._factory_files[i], ".yaml") => { billing_account = try(coalesce( var.data_overrides.billing_account, try(v.billing_account, null), @@ -96,7 +95,7 @@ locals { try(v.service_accounts, null), var.data_defaults.service_accounts ) - }) + } } service_accounts = flatten([ for k, v in local.projects : [ diff --git a/blueprints/factories/project-factory/variables.tf b/blueprints/factories/project-factory/variables.tf index 55578562f9..a0ff81ebd3 100644 --- a/blueprints/factories/project-factory/variables.tf +++ b/blueprints/factories/project-factory/variables.tf @@ -85,18 +85,8 @@ variable "data_overrides" { default = {} } -variable "factory_data" { - description = "Project data from either YAML files or externally parsed data." - type = object({ - data = optional(map(any)) - data_path = optional(string) - }) - nullable = false - validation { - condition = ( - (var.factory_data.data != null ? 1 : 0) + - (var.factory_data.data_path != null ? 1 : 0) - ) == 1 - error_message = "One of data or data_path needs to be set." - } +variable "factory_data_path" { + description = "Path to folder with YAML project description data files." + type = string + nullable = false } diff --git a/fast/stages/3-project-factory/dev/README.md b/fast/stages/3-project-factory/dev/README.md index 03bfa86c5e..07b748c50f 100644 --- a/fast/stages/3-project-factory/dev/README.md +++ b/fast/stages/3-project-factory/dev/README.md @@ -79,8 +79,8 @@ terraform apply | name | description | type | required | default | producer | |---|---|:---:|:---:|:---:|:---:| | [billing_account](variables.tf#L19) | Billing account id. If billing account is not part of the same org set `is_org_level` to false. | object({…}) | ✓ | | 0-bootstrap | -| [prefix](variables.tf#L51) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 0-bootstrap | -| [factory_data](variables.tf#L32) | Project data from either YAML files or externally parsed data. | object({…}) | | {…} | | +| [prefix](variables.tf#L39) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 0-bootstrap | +| [factory_data_path](variables.tf#L32) | Path to folder containing YAML project data files. | string | | "data/projects" | | ## Outputs diff --git a/fast/stages/3-project-factory/dev/main.tf b/fast/stages/3-project-factory/dev/main.tf index 4f23b49281..48867a9984 100644 --- a/fast/stages/3-project-factory/dev/main.tf +++ b/fast/stages/3-project-factory/dev/main.tf @@ -33,7 +33,7 @@ module "projects" { data_overrides = { prefix = "${var.prefix}-dev" } - factory_data = var.factory_data + factory_data_path = var.factory_data_path } diff --git a/fast/stages/3-project-factory/dev/variables.tf b/fast/stages/3-project-factory/dev/variables.tf index c7165e3ced..5a8ef4f870 100644 --- a/fast/stages/3-project-factory/dev/variables.tf +++ b/fast/stages/3-project-factory/dev/variables.tf @@ -29,23 +29,11 @@ variable "billing_account" { } } -variable "factory_data" { - description = "Project data from either YAML files or externally parsed data." - type = object({ - data = optional(map(any)) - data_path = optional(string) - }) - nullable = false - default = { - data_path = "data/projects" - } - validation { - condition = ( - (var.factory_data.data != null ? 1 : 0) + - (var.factory_data.data_path != null ? 1 : 0) - ) == 1 - error_message = "One of data or data_path needs to be set." - } +variable "factory_data_path" { + description = "Path to folder containing YAML project data files." + type = string + nullable = false + default = "data/projects" } variable "prefix" { diff --git a/tests/blueprints/factories/project_factory/examples/example.yaml b/tests/blueprints/factories/project_factory/examples/example.yaml index 859ec2ee29..71391a526a 100644 --- a/tests/blueprints/factories/project_factory/examples/example.yaml +++ b/tests/blueprints/factories/project_factory/examples/example.yaml @@ -30,6 +30,10 @@ values: module.project-factory.module.projects["prj-app-1"].google_project.project[0]: auto_create_network: false billing_account: 012345-67890A-BCDEF0 + effective_labels: + app: app-1 + environment: test + team: foo folder_id: '12345678' labels: app: app-1 @@ -39,6 +43,16 @@ values: org_id: null project_id: test-pf-prj-app-1 skip_delete: false + terraform_labels: + app: app-1 + environment: test + team: foo + timeouts: null + module.project-factory.module.projects["prj-app-1"].google_project_service.project_services["container.googleapis.com"]: + disable_dependent_services: false + disable_on_destroy: false + project: test-pf-prj-app-1 + service: container.googleapis.com timeouts: null module.project-factory.module.projects["prj-app-1"].google_project_service.project_services["stackdriver.googleapis.com"]: disable_dependent_services: false @@ -52,6 +66,14 @@ values: project: test-pf-prj-app-1 service: storage.googleapis.com timeouts: null + module.project-factory.module.projects["prj-app-2"].data.google_storage_project_service_account.gcs_sa[0]: + project: test-pf-prj-app-2 + user_project: null + module.project-factory.module.projects["prj-app-2"].google_compute_shared_vpc_service_project.shared_vpc_service[0]: + deletion_policy: null + host_project: foo-host + service_project: test-pf-prj-app-2 + timeouts: null module.project-factory.module.projects["prj-app-2"].google_essential_contacts_contact.contact["admin@example.com"]: email: admin@example.com language_tag: en @@ -59,44 +81,38 @@ values: - ALL parent: projects/test-pf-prj-app-2 timeouts: null - ? module.project-factory.module.projects["prj-app-2"].google_org_policy_policy.default["compute.disableGuestAttributesAccess"] - : name: projects/test-pf-prj-app-2/policies/compute.disableGuestAttributesAccess - parent: projects/test-pf-prj-app-2 - spec: - - inherit_from_parent: null - reset: null - rules: - - allow_all: null - condition: [] - deny_all: null - enforce: 'FALSE' - values: [] - timeouts: null - ? module.project-factory.module.projects["prj-app-2"].google_org_policy_policy.default["iam.disableServiceAccountKeyCreation"] - : name: projects/test-pf-prj-app-2/policies/iam.disableServiceAccountKeyCreation - parent: projects/test-pf-prj-app-2 - spec: - - inherit_from_parent: null - reset: null - rules: - - allow_all: null - condition: [] - deny_all: null - enforce: 'FALSE' - values: [] - timeouts: null module.project-factory.module.projects["prj-app-2"].google_project.project[0]: auto_create_network: false billing_account: 012345-67890A-ABCDEF + effective_labels: + app: app-2 + environment: test + team: foo folder_id: '12345678' labels: - app: app-1 + app: app-2 environment: test team: foo name: test-pf-prj-app-2 org_id: null project_id: test-pf-prj-app-2 skip_delete: false + terraform_labels: + app: app-2 + environment: test + team: foo + timeouts: null + module.project-factory.module.projects["prj-app-2"].google_project_service.project_services["compute.googleapis.com"]: + disable_dependent_services: false + disable_on_destroy: false + project: test-pf-prj-app-2 + service: compute.googleapis.com + timeouts: null + module.project-factory.module.projects["prj-app-2"].google_project_service.project_services["run.googleapis.com"]: + disable_dependent_services: false + disable_on_destroy: false + project: test-pf-prj-app-2 + service: run.googleapis.com timeouts: null module.project-factory.module.projects["prj-app-2"].google_project_service.project_services["stackdriver.googleapis.com"]: disable_dependent_services: false @@ -104,37 +120,95 @@ values: project: test-pf-prj-app-2 service: stackdriver.googleapis.com timeouts: null + module.project-factory.module.projects["prj-app-2"].google_project_service.project_services["storage.googleapis.com"]: + disable_dependent_services: false + disable_on_destroy: false + project: test-pf-prj-app-2 + service: storage.googleapis.com + timeouts: null + module.project-factory.module.projects["prj-app-3"].data.google_storage_project_service_account.gcs_sa[0]: + project: test-pf-prj-app-3 + user_project: null + module.project-factory.module.projects["prj-app-3"].google_essential_contacts_contact.contact["admin@example.com"]: + email: admin@example.com + language_tag: en + notification_category_subscriptions: + - ALL + parent: projects/test-pf-prj-app-3 + timeouts: null + module.project-factory.module.projects["prj-app-3"].google_project.project[0]: + auto_create_network: false + billing_account: 012345-67890A-ABCDEF + effective_labels: + environment: test + folder_id: '12345678' + labels: + environment: test + name: test-pf-prj-app-3 + org_id: null + project_id: test-pf-prj-app-3 + skip_delete: false + terraform_labels: + environment: test + timeouts: null + module.project-factory.module.projects["prj-app-3"].google_project_service.project_services["run.googleapis.com"]: + disable_dependent_services: false + disable_on_destroy: false + project: test-pf-prj-app-3 + service: run.googleapis.com + timeouts: null + module.project-factory.module.projects["prj-app-3"].google_project_service.project_services["stackdriver.googleapis.com"]: + disable_dependent_services: false + disable_on_destroy: false + project: test-pf-prj-app-3 + service: stackdriver.googleapis.com + timeouts: null + module.project-factory.module.projects["prj-app-3"].google_project_service.project_services["storage.googleapis.com"]: + disable_dependent_services: false + disable_on_destroy: false + project: test-pf-prj-app-3 + service: storage.googleapis.com + timeouts: null + ? module.project-factory.module.service-accounts["prj-app-1-app-1-be"].google_project_iam_member.project-roles["test-pf-prj-app-1-roles/logging.logWriter"] + : condition: [] + project: test-pf-prj-app-1 + role: roles/logging.logWriter + ? module.project-factory.module.service-accounts["prj-app-1-app-1-be"].google_project_iam_member.project-roles["test-pf-prj-app-1-roles/monitoring.metricWriter"] + : condition: [] + project: test-pf-prj-app-1 + role: roles/monitoring.metricWriter module.project-factory.module.service-accounts["prj-app-1-app-1-be"].google_service_account.service_account[0]: account_id: app-1-be description: null disabled: false - display_name: Terraform-managed. + display_name: null project: test-pf-prj-app-1 timeouts: null module.project-factory.module.service-accounts["prj-app-1-app-1-fe"].google_service_account.service_account[0]: account_id: app-1-fe description: null disabled: false - display_name: Terraform-managed. + display_name: Test app 1 frontend. project: test-pf-prj-app-1 timeouts: null module.project-factory.module.service-accounts["prj-app-2-app-2-be"].google_service_account.service_account[0]: account_id: app-2-be description: null disabled: false - display_name: Terraform-managed. + display_name: null project: test-pf-prj-app-2 timeouts: null counts: - google_essential_contacts_contact: 2 + google_compute_shared_vpc_service_project: 1 + google_essential_contacts_contact: 3 google_kms_crypto_key_iam_member: 1 - google_org_policy_policy: 2 - google_project: 2 - google_project_service: 3 + google_project: 3 + google_project_iam_member: 2 + google_project_service: 10 google_service_account: 3 - google_storage_project_service_account: 1 - modules: 6 - resources: 14 + google_storage_project_service_account: 3 + modules: 7 + resources: 26 outputs: {} From 2664161c24a1ff21301425c77b1abab653c3cbb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Niesiob=C4=99dzki?= Date: Thu, 2 Nov 2023 08:43:06 +0000 Subject: [PATCH 11/29] Simplify #1836 fix, Avoid map-related casting errors in project factory --- .../factories/project-factory/factory.tf | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/blueprints/factories/project-factory/factory.tf b/blueprints/factories/project-factory/factory.tf index b2187f717b..eabb551ad1 100644 --- a/blueprints/factories/project-factory/factory.tf +++ b/blueprints/factories/project-factory/factory.tf @@ -15,18 +15,17 @@ */ locals { - # turn the set of file names into a list for index-based access later on - _factory_files = [ - for f in fileset("${pathexpand(var.factory_data_path)}", "**/*.yaml") : f - ] - # use a list to store data to avoid map enforcing the same type for all - _factory_data = [ - for f in local._factory_files : - yamldecode(file("${pathexpand(var.factory_data_path)}/${f}")) - ] - # assemble final data, emulating optionals and using defaults and merges + _data = ( + { + for f in fileset(local._data_path, "**/*.yaml") : + trimsuffix(f, ".yaml") => yamldecode(file("${local._data_path}/${f}")) + } + ) + _data_path = var.factory_data_path == null ? null : pathexpand( + var.factory_data_path + ) projects = { - for i, v in local._factory_data : trimsuffix(local._factory_files[i], ".yaml") => { + for k, v in local._data : k => merge(v, { billing_account = try(coalesce( var.data_overrides.billing_account, try(v.billing_account, null), @@ -95,7 +94,7 @@ locals { try(v.service_accounts, null), var.data_defaults.service_accounts ) - } + }) } service_accounts = flatten([ for k, v in local.projects : [ From 26248ba5f5ba1b22dc15f2d616838008a488eb83 Mon Sep 17 00:00:00 2001 From: apichick Date: Thu, 2 Nov 2023 13:52:46 +0100 Subject: [PATCH 12/29] Added create_before_destroy = true for self-managed certificates --- modules/net-lb-app-ext/main.tf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/net-lb-app-ext/main.tf b/modules/net-lb-app-ext/main.tf index ebe438ec13..94a79d9996 100644 --- a/modules/net-lb-app-ext/main.tf +++ b/modules/net-lb-app-ext/main.tf @@ -53,6 +53,9 @@ resource "google_compute_ssl_certificate" "default" { name = "${var.name}-${each.key}" certificate = trimspace(each.value.certificate) private_key = trimspace(each.value.private_key) + lifecycle { + create_before_destroy = true + } } resource "google_compute_managed_ssl_certificate" "default" { From 7de94c40eb00fbbbbd00c122bc421c13d23ee8a5 Mon Sep 17 00:00:00 2001 From: Ludo Date: Thu, 2 Nov 2023 23:20:36 +0100 Subject: [PATCH 13/29] update changelog --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a71669a2d..67c75dd857 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ All notable changes to this project will be documented in this file. ### BLUEPRINTS +- [[#1838](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1838)] Simplify #1836 fix, Avoid map-related casting errors in project factory ([wiktorn](https://github.com/wiktorn)) +- [[#1836](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1836)] **incompatible change:** Avoid map-related casting errors in project factory ([ludoo](https://github.com/ludoo)) +- [[#1832](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1832)] [Minimal Data Platform] Fix Landing and curated IAM ([lcaggio](https://github.com/lcaggio)) +- [[#1825](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1825)] Handling SQL IP address issue ([aurelienlegrand](https://github.com/aurelienlegrand)) - [[#1821](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1821)] [net-address] enable ipv6 ([LucaPrete](https://github.com/LucaPrete)) - [[#1814](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1814)] **incompatible change:** Allow specifying arbitrary project roles for service accounts in project factory ([ludoo](https://github.com/ludoo)) - [[#1812](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1812)] Stop wrapping yamldecode with try() ([sruffilli](https://github.com/sruffilli)) @@ -21,12 +25,15 @@ All notable changes to this project will be documented in this file. ### DOCUMENTATION +- [[#1832](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1832)] [Minimal Data Platform] Fix Landing and curated IAM ([lcaggio](https://github.com/lcaggio)) +- [[#1831](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1831)] Update wording in FAST and gcve module READMEs ([bluPhy](https://github.com/bluPhy)) - [[#1782](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1782)] Add upper cap to versions, update copyright notices ([sruffilli](https://github.com/sruffilli)) - [[#1773](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1773)] Add service usage consumer role to IaC SAs, refactor delegated grants in FAST ([ludoo](https://github.com/ludoo)) - [[#1743](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1743)] Billing account module ([ludoo](https://github.com/ludoo)) ### FAST +- [[#1836](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1836)] **incompatible change:** Avoid map-related casting errors in project factory ([ludoo](https://github.com/ludoo)) - [[#1818](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1818)] FAST: rename VPC-related files to `net-*` ([sruffilli](https://github.com/sruffilli)) - [[#1812](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1812)] Stop wrapping yamldecode with try() ([sruffilli](https://github.com/sruffilli)) - [[#1810](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1810)] FAST: Add access transparency logs to the default sinks ([sruffilli](https://github.com/sruffilli)) @@ -49,6 +56,10 @@ All notable changes to this project will be documented in this file. ### MODULES +- [[#1839](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1839)] Added create_before_destroy = true for self-managed certificates ([apichick](https://github.com/apichick)) +- [[#1833](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1833)] Net VPC Peering: added stack_type field ([cmalpe](https://github.com/cmalpe)) +- [[#1826](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1826)] Add public_access_prevention field to GCS module ([devuonocar](https://github.com/devuonocar)) +- [[#1817](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1817)] KMS module: Import job feature ([cmalpe](https://github.com/cmalpe)) - [[#1822](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1822)] Billing budget factory ([ludoo](https://github.com/ludoo)) - [[#1821](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1821)] [net-address] enable ipv6 ([LucaPrete](https://github.com/LucaPrete)) - [[#1820](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1820)] Added iam_bindings and iam_bindings_additive to apigee module ([apichick](https://github.com/apichick)) From 3191dbb769a28d04658479207a5aeb3c4bfd60fe Mon Sep 17 00:00:00 2001 From: apichick Date: Thu, 2 Nov 2023 09:37:17 +0100 Subject: [PATCH 14/29] Added envoy as SNI dynamic forward proxy to cloud-config-container --- .../envoy-sni-dyn-fwd-proxy/README.md | 57 +++++++++++++++++++ .../envoy-sni-dyn-fwd-proxy/files/envoy.yaml | 56 ++++++++++++++++++ .../envoy-sni-dyn-fwd-proxy/main.tf | 44 ++++++++++++++ .../envoy-sni-dyn-fwd-proxy/outputs.tf | 20 +++++++ .../envoy-sni-dyn-fwd-proxy/variables.tf | 20 +++++++ .../envoy-sni-dyn-fwd-proxy/versions.tf | 28 +++++++++ 6 files changed, 225 insertions(+) create mode 100644 modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/README.md create mode 100644 modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/files/envoy.yaml create mode 100644 modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/main.tf create mode 100644 modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/outputs.tf create mode 100644 modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/variables.tf create mode 100644 modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/versions.tf diff --git a/modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/README.md b/modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/README.md new file mode 100644 index 0000000000..76d1b19d4c --- /dev/null +++ b/modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/README.md @@ -0,0 +1,57 @@ +# Containerized Envoy as SNI dynamic forward proxy on Container Optimized OS + +This module manages a `cloud-config` configuration that starts a containerized [Envoy SNI Dynamic forward proxy]https://www.envoyproxy.io/docs/envoy/latest/configuration/listeners/network_filters/sni_dynamic_forward_proxy_filter) service on Container Optimized OS running on port 443. + +This module depends on the cos-generic-metadata module being in the parent folder. If you change its location be sure to adjust the source attribute in main.tf. + +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. + +## Examples + +### Default configuration + +This example will create a `cloud-config` that uses the module's defaults, creating a simple hello web server showing host name and request id. + +```hcl +module "cos-envoy-sni-dyn-fwd-proxy" { + source = "./fabric/modules/cloud-config-container/envoy-sni-dyn-fwd-proxy" + envoy_image = "envoyproxy/envoy:v1.28-latest" +} + +module "vm-envoy-sni-dyn-fwd-proxy" { + source = "./fabric/modules/compute-vm" + project_id = "my-project" + zone = "europe-west8-b" + name = "cos-envoy-sni-dyn-fw-proxy" + network_interfaces = [{ + network = "default" + subnetwork = "gce" + }] + metadata = { + user-data = module.cos-envoy-sni-dyn-fwd-proxy.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 = ["https-server", "ssh"] +} +# tftest modules=1 resources=1 +``` + +## Variables + +| name | description | type | required | default | +|---|---|:---:|:---:|:---:| +| [envoy_image](variables.tf#L17) | Image. | string | ✓ | | + +## 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/envoy-sni-dyn-fwd-proxy/files/envoy.yaml b/modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/files/envoy.yaml new file mode 100644 index 0000000000..55a5e08fb1 --- /dev/null +++ b/modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/files/envoy.yaml @@ -0,0 +1,56 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +admin: + address: + socket_address: + protocol: TCP + address: 127.0.0.1 + port_value: 9991 +static_resources: + listeners: + - name: listener + address: + socket_address: + protocol: TCP + address: 0.0.0.0 + port_value: 8443 + listener_filters: + - name: envoy.filters.listener.tls_inspector + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector + filter_chains: + - filters: + - name: envoy.filters.network.sni_dynamic_forward_proxy + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.sni_dynamic_forward_proxy.v3.FilterConfig + port_value: 443 + dns_cache_config: + name: dynamic_forward_proxy_cache_config + dns_lookup_family: V4_ONLY + - name: envoy.tcp_proxy + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy + stat_prefix: tcp + cluster: dynamic_forward_proxy_cluster + clusters: + - name: dynamic_forward_proxy_cluster + lb_policy: CLUSTER_PROVIDED + cluster_type: + name: envoy.clusters.dynamic_forward_proxy + typed_config: + "@type": type.googleapis.com/envoy.extensions.clusters.dynamic_forward_proxy.v3.ClusterConfig + dns_cache_config: + name: dynamic_forward_proxy_cache_config + dns_lookup_family: V4_ONLY% diff --git a/modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/main.tf b/modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/main.tf new file mode 100644 index 0000000000..f0b7cdfb2c --- /dev/null +++ b/modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/main.tf @@ -0,0 +1,44 @@ +/** + * 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. + */ + +module "cos-envoy" { + source = "../cos-generic-metadata" + container_image = var.envoy_image + container_name = "envoy" + container_args = "-c /etc/envoy/envoy.yaml --log-level info --allow-unknown-static-fields" + container_volumes = [ + { host = "/etc/envoy/", container = "/etc/envoy/" } + ] + docker_args = "--network host --pid host" + files = { + "/etc/envoy/envoy.yaml" = { + content = file("${path.module}/files/envoy.yaml") + owner = "root" + permissions = "0644" + } + } + run_commands = [ + "iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8443", + "iptables -A INPUT -p tcp --dport 8443 -j ACCEPT", + "iptables -t mangle -I PREROUTING -p tcp --dport 8443 -j DROP", + "systemctl daemon-reload", + "systemctl start envoy", + ] + users = [{ + username = "envoy", + uid = 1337 + }] +} diff --git a/modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/outputs.tf b/modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/outputs.tf new file mode 100644 index 0000000000..417c73e7d7 --- /dev/null +++ b/modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/outputs.tf @@ -0,0 +1,20 @@ +/** + * 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. + */ + +output "cloud_config" { + description = "Rendered cloud-config file to be passed as user-data instance metadata." + value = module.cos-envoy.cloud_config +} diff --git a/modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/variables.tf b/modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/variables.tf new file mode 100644 index 0000000000..3868a17424 --- /dev/null +++ b/modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/variables.tf @@ -0,0 +1,20 @@ +/** + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +variable "envoy_image" { + description = "Image." + type = string +} 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 new file mode 100644 index 0000000000..0a97638929 --- /dev/null +++ b/modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/versions.tf @@ -0,0 +1,28 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +terraform { + required_version = ">= 1.4.4" + required_providers { + google = { + source = "hashicorp/google" + version = ">= 5.0.0, < 6.0.0" # tftest + } + google-beta = { + source = "hashicorp/google-beta" + version = ">= 5.0.0, < 6.0.0" # tftest + } + } +} + From b40ad91629526237339d389fa434905314b46641 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Niesiob=C4=99dzki?= Date: Fri, 3 Nov 2023 17:02:00 +0000 Subject: [PATCH 15/29] Bump provider version to 5.4.0 --- default-versions.tf | 4 +-- .../alloydb-instance/versions.tf | 4 +-- modules/__experimental/net-neg/versions.tf | 4 +-- .../project-iam-magic/versions.tf | 29 +++++++++++++++++++ modules/api-gateway/versions.tf | 4 +-- modules/apigee/versions.tf | 4 +-- modules/artifact-registry/versions.tf | 4 +-- modules/bigquery-dataset/versions.tf | 4 +-- modules/bigtable-instance/versions.tf | 4 +-- modules/billing-account/versions.tf | 4 +-- modules/binauthz/versions.tf | 4 +-- .../__need_fixing/onprem/versions.tf | 4 +-- .../coredns/versions.tf | 4 +-- .../cos-generic-metadata/versions.tf | 4 +-- .../envoy-sni-dyn-fwd-proxy/versions.tf | 4 +-- .../envoy-traffic-director/versions.tf | 4 +-- .../cloud-config-container/mysql/versions.tf | 4 +-- .../nginx-tls/versions.tf | 4 +-- .../cloud-config-container/nginx/versions.tf | 4 +-- .../simple-nva/versions.tf | 4 +-- .../cloud-config-container/squid/versions.tf | 4 +-- modules/cloud-function-v1/versions.tf | 4 +-- modules/cloud-function-v2/versions.tf | 4 +-- modules/cloud-identity-group/versions.tf | 4 +-- modules/cloud-run/versions.tf | 4 +-- modules/cloudsql-instance/versions.tf | 4 +-- modules/compute-mig/versions.tf | 4 +-- modules/compute-vm/versions.tf | 4 +-- modules/container-registry/versions.tf | 4 +-- modules/data-catalog-policy-tag/versions.tf | 4 +-- modules/datafusion/versions.tf | 4 +-- modules/dataplex-datascan/versions.tf | 4 +-- modules/dataplex/versions.tf | 4 +-- modules/dataproc/versions.tf | 4 +-- modules/dns-response-policy/versions.tf | 4 +-- modules/dns/versions.tf | 4 +-- modules/endpoints/versions.tf | 4 +-- modules/folder/versions.tf | 4 +-- modules/gcs/versions.tf | 4 +-- modules/gcve-private-cloud/versions.tf | 4 +-- modules/gke-cluster-autopilot/versions.tf | 4 +-- modules/gke-cluster-standard/versions.tf | 4 +-- modules/gke-hub/versions.tf | 4 +-- modules/gke-nodepool/versions.tf | 4 +-- modules/iam-service-account/versions.tf | 4 +-- modules/kms/versions.tf | 4 +-- modules/logging-bucket/versions.tf | 4 +-- modules/ncc-spoke-ra/versions.tf | 4 +-- modules/net-address/versions.tf | 4 +-- modules/net-cloudnat/versions.tf | 4 +-- modules/net-firewall-policy/versions.tf | 4 +-- .../net-ipsec-over-interconnect/versions.tf | 4 +-- modules/net-lb-app-ext/versions.tf | 4 +-- modules/net-lb-app-int/versions.tf | 4 +-- modules/net-lb-ext/versions.tf | 4 +-- modules/net-lb-int/versions.tf | 4 +-- modules/net-lb-proxy-int/versions.tf | 4 +-- modules/net-swp/versions.tf | 4 +-- modules/net-vlan-attachment/versions.tf | 4 +-- modules/net-vpc-firewall/versions.tf | 4 +-- modules/net-vpc-peering/versions.tf | 4 +-- modules/net-vpc/versions.tf | 4 +-- modules/net-vpn-dynamic/versions.tf | 4 +-- modules/net-vpn-ha/versions.tf | 4 +-- modules/net-vpn-static/versions.tf | 4 +-- modules/organization/versions.tf | 4 +-- modules/project/versions.tf | 4 +-- modules/projects-data-source/versions.tf | 4 +-- modules/pubsub/versions.tf | 4 +-- modules/secret-manager/versions.tf | 4 +-- modules/service-directory/versions.tf | 4 +-- modules/source-repository/versions.tf | 4 +-- modules/vpc-sc/versions.tf | 4 +-- 73 files changed, 173 insertions(+), 144 deletions(-) create mode 100644 modules/__experimental/project-iam-magic/versions.tf diff --git a/default-versions.tf b/default-versions.tf index af3463955f..3adb51d3bd 100644 --- a/default-versions.tf +++ b/default-versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/__experimental/alloydb-instance/versions.tf b/modules/__experimental/alloydb-instance/versions.tf index af3463955f..3adb51d3bd 100644 --- a/modules/__experimental/alloydb-instance/versions.tf +++ b/modules/__experimental/alloydb-instance/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/__experimental/net-neg/versions.tf b/modules/__experimental/net-neg/versions.tf index af3463955f..3adb51d3bd 100644 --- a/modules/__experimental/net-neg/versions.tf +++ b/modules/__experimental/net-neg/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/__experimental/project-iam-magic/versions.tf b/modules/__experimental/project-iam-magic/versions.tf new file mode 100644 index 0000000000..2ce9578209 --- /dev/null +++ b/modules/__experimental/project-iam-magic/versions.tf @@ -0,0 +1,29 @@ +# 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 +# +# 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.4.4" + required_providers { + google = { + source = "hashicorp/google" + version = ">= 4.71.0" # tftest + } + google-beta = { + source = "hashicorp/google-beta" + version = ">= 4.71.0" # tftest + } + } +} + + diff --git a/modules/api-gateway/versions.tf b/modules/api-gateway/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/apigee/versions.tf b/modules/apigee/versions.tf index af3463955f..3adb51d3bd 100644 --- a/modules/apigee/versions.tf +++ b/modules/apigee/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/artifact-registry/versions.tf b/modules/artifact-registry/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/bigquery-dataset/versions.tf b/modules/bigquery-dataset/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/bigtable-instance/versions.tf b/modules/bigtable-instance/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/billing-account/versions.tf b/modules/billing-account/versions.tf index 0cc9b9727b..cee7f9c764 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/binauthz/versions.tf b/modules/binauthz/versions.tf index af3463955f..3adb51d3bd 100644 --- a/modules/binauthz/versions.tf +++ b/modules/binauthz/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/cloud-config-container/__need_fixing/onprem/versions.tf b/modules/cloud-config-container/__need_fixing/onprem/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/cloud-config-container/coredns/versions.tf b/modules/cloud-config-container/coredns/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.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 af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.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 0a97638929..ceb6930fb3 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.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 af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/cloud-config-container/mysql/versions.tf b/modules/cloud-config-container/mysql/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.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 af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/cloud-config-container/nginx/versions.tf b/modules/cloud-config-container/nginx/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/cloud-config-container/simple-nva/versions.tf b/modules/cloud-config-container/simple-nva/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/cloud-config-container/squid/versions.tf b/modules/cloud-config-container/squid/versions.tf index af3463955f..3adb51d3bd 100644 --- a/modules/cloud-config-container/squid/versions.tf +++ b/modules/cloud-config-container/squid/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/cloud-function-v1/versions.tf b/modules/cloud-function-v1/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/cloud-function-v2/versions.tf b/modules/cloud-function-v2/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/cloud-identity-group/versions.tf b/modules/cloud-identity-group/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/cloud-run/versions.tf b/modules/cloud-run/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/cloudsql-instance/versions.tf b/modules/cloudsql-instance/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/compute-mig/versions.tf b/modules/compute-mig/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/compute-vm/versions.tf b/modules/compute-vm/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/container-registry/versions.tf b/modules/container-registry/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/data-catalog-policy-tag/versions.tf b/modules/data-catalog-policy-tag/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/datafusion/versions.tf b/modules/datafusion/versions.tf index af3463955f..3adb51d3bd 100644 --- a/modules/datafusion/versions.tf +++ b/modules/datafusion/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/dataplex-datascan/versions.tf b/modules/dataplex-datascan/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/dataplex/versions.tf b/modules/dataplex/versions.tf index af3463955f..3adb51d3bd 100644 --- a/modules/dataplex/versions.tf +++ b/modules/dataplex/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/dataproc/versions.tf b/modules/dataproc/versions.tf index af3463955f..3adb51d3bd 100644 --- a/modules/dataproc/versions.tf +++ b/modules/dataproc/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/dns-response-policy/versions.tf b/modules/dns-response-policy/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/dns/versions.tf b/modules/dns/versions.tf index af3463955f..3adb51d3bd 100644 --- a/modules/dns/versions.tf +++ b/modules/dns/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/endpoints/versions.tf b/modules/endpoints/versions.tf index af3463955f..3adb51d3bd 100644 --- a/modules/endpoints/versions.tf +++ b/modules/endpoints/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/folder/versions.tf b/modules/folder/versions.tf index af3463955f..3adb51d3bd 100644 --- a/modules/folder/versions.tf +++ b/modules/folder/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/gcs/versions.tf b/modules/gcs/versions.tf index af3463955f..3adb51d3bd 100644 --- a/modules/gcs/versions.tf +++ b/modules/gcs/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/gcve-private-cloud/versions.tf b/modules/gcve-private-cloud/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/gke-cluster-autopilot/versions.tf b/modules/gke-cluster-autopilot/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/gke-cluster-standard/versions.tf b/modules/gke-cluster-standard/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/gke-hub/versions.tf b/modules/gke-hub/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/gke-nodepool/versions.tf b/modules/gke-nodepool/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/iam-service-account/versions.tf b/modules/iam-service-account/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/kms/versions.tf b/modules/kms/versions.tf index af3463955f..3adb51d3bd 100644 --- a/modules/kms/versions.tf +++ b/modules/kms/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/logging-bucket/versions.tf b/modules/logging-bucket/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/ncc-spoke-ra/versions.tf b/modules/ncc-spoke-ra/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/net-address/versions.tf b/modules/net-address/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/net-cloudnat/versions.tf b/modules/net-cloudnat/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/net-firewall-policy/versions.tf b/modules/net-firewall-policy/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/net-ipsec-over-interconnect/versions.tf b/modules/net-ipsec-over-interconnect/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/net-lb-app-ext/versions.tf b/modules/net-lb-app-ext/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/net-lb-app-int/versions.tf b/modules/net-lb-app-int/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/net-lb-ext/versions.tf b/modules/net-lb-ext/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/net-lb-int/versions.tf b/modules/net-lb-int/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/net-lb-proxy-int/versions.tf b/modules/net-lb-proxy-int/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/net-swp/versions.tf b/modules/net-swp/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/net-vlan-attachment/versions.tf b/modules/net-vlan-attachment/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/net-vpc-firewall/versions.tf b/modules/net-vpc-firewall/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/net-vpc-peering/versions.tf b/modules/net-vpc-peering/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/net-vpc/versions.tf b/modules/net-vpc/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/net-vpn-dynamic/versions.tf b/modules/net-vpn-dynamic/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/net-vpn-ha/versions.tf b/modules/net-vpn-ha/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/net-vpn-static/versions.tf b/modules/net-vpn-static/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/organization/versions.tf b/modules/organization/versions.tf index af3463955f..3adb51d3bd 100644 --- a/modules/organization/versions.tf +++ b/modules/organization/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/project/versions.tf b/modules/project/versions.tf index af3463955f..3adb51d3bd 100644 --- a/modules/project/versions.tf +++ b/modules/project/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/projects-data-source/versions.tf b/modules/projects-data-source/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/pubsub/versions.tf b/modules/pubsub/versions.tf index af3463955f..3adb51d3bd 100644 --- a/modules/pubsub/versions.tf +++ b/modules/pubsub/versions.tf @@ -17,11 +17,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/secret-manager/versions.tf b/modules/secret-manager/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/service-directory/versions.tf b/modules/service-directory/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/source-repository/versions.tf b/modules/source-repository/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } diff --git a/modules/vpc-sc/versions.tf b/modules/vpc-sc/versions.tf index af3463955f..3adb51d3bd 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.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } google-beta = { source = "hashicorp/google-beta" - version = ">= 5.0.0, < 6.0.0" # tftest + version = ">= 5.4.0, < 6.0.0" # tftest } } } From fe485414e67b5a0ffb11ce1c65871834e05cfa77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Niesiob=C4=99dzki?= Date: Fri, 3 Nov 2023 18:04:19 +0100 Subject: [PATCH 16/29] Add end-to-end tests for project module (#1823) * Add end-to-end tests for project module * Add inventory to data tests * Add files to end-to-end test cases * Review fixes - use named groups --------- Co-authored-by: Ludovico Magnocavallo --- modules/compute-vm/README.md | 2 +- modules/project/README.md | 411 ++++++++++++++---- modules/project/logging.tf | 3 +- modules/project/service-agents.yaml | 8 +- tests/examples/test_plan.py | 30 +- tests/examples/variables.tf | 6 +- tests/examples_e2e/README.md | 9 +- .../setup_module/e2e_tests.tfvars.tftpl | 10 +- tests/examples_e2e/setup_module/main.tf | 23 +- tests/examples_e2e/setup_module/variables.tf | 3 + tests/examples_e2e/test_plan.py | 10 +- tests/examples_e2e/variables.tf | 92 ---- tests/fixtures.py | 11 +- tests/modules/project/examples/basic.yaml | 10 +- tests/modules/project/examples/data.yaml | 338 ++++++++++++++ .../project/examples/iam-authoritative.yaml | 12 +- .../examples/iam-bindings-additive.yaml | 14 +- .../project/examples/iam-bindings.yaml | 14 +- tests/modules/project/examples/iam-group.yaml | 16 +- .../project/examples/logging-data-access.yaml | 10 +- tests/modules/project/examples/logging.yaml | 20 +- .../project/examples/org-policies.yaml | 34 +- .../examples/shared-vpc-auto-grants.yaml | 16 +- .../modules/project/examples/shared-vpc.yaml | 18 +- 24 files changed, 827 insertions(+), 293 deletions(-) delete mode 100644 tests/examples_e2e/variables.tf create mode 100644 tests/modules/project/examples/data.yaml diff --git a/modules/compute-vm/README.md b/modules/compute-vm/README.md index 052d71b76b..450ccad730 100644 --- a/modules/compute-vm/README.md +++ b/modules/compute-vm/README.md @@ -516,7 +516,7 @@ module "kms-vm-example" { } encryption = { encrypt_boot = true - kms_key_self_link = var.kms_key.self_link + kms_key_self_link = var.kms_key.id } } # tftest modules=1 resources=3 inventory=cmek.yaml diff --git a/modules/project/README.md b/modules/project/README.md index 43dfbc7044..9d94d9f2d1 100644 --- a/modules/project/README.md +++ b/modules/project/README.md @@ -11,15 +11,16 @@ This module implements the creation and management of one GCP project including - [Authoritative IAM](#authoritative-iam) - [Additive IAM](#additive-iam) - [Service Identities and Authoritative IAM](#service-identities-and-authoritative-iam) - - [Service Identities Requiring Manual Iam Grants](#service-identities-requiring-manual-iam-grants) + - [Service Identities Requiring Manual IAM Grants](#service-identities-requiring-manual-iam-grants) - [Shared VPC](#shared-vpc) - [Organization Policies](#organization-policies) - [Organization Policy Factory](#organization-policy-factory) - [Log Sinks](#log-sinks) - [Data Access Logs](#data-access-logs) -- [Cloud Kms Encryption Keys](#cloud-kms-encryption-keys) +- [Cloud KMS Encryption Keys](#cloud-kms-encryption-keys) - [Tags](#tags) - [Outputs](#outputs) + - [Managing project related configuration without creating it](#managing-project-related-configuration-without-creating-it) - [Files](#files) - [Variables](#variables) - [Outputs](#outputs) @@ -30,16 +31,16 @@ This module implements the creation and management of one GCP project including ```hcl module "project" { source = "./fabric/modules/project" - billing_account = "123456-123456-123456" - name = "myproject" - parent = "folders/1234567890" - prefix = "foo" + billing_account = var.billing_account_id + name = "project" + parent = var.folder_id + prefix = var.prefix services = [ "container.googleapis.com", "stackdriver.googleapis.com" ] } -# tftest modules=1 resources=3 inventory=basic.yaml +# tftest modules=1 resources=3 inventory=basic.yaml e2e ``` ## IAM @@ -65,10 +66,10 @@ locals { module "project" { source = "./fabric/modules/project" - billing_account = "123456-123456-123456" - name = "project-example" - parent = "folders/1234567890" - prefix = "foo" + billing_account = var.billing_account_id + name = "project" + parent = var.folder_id + prefix = var.prefix services = [ "container.googleapis.com", "stackdriver.googleapis.com" @@ -87,12 +88,12 @@ The `group_iam` variable uses group email addresses as keys and is a convenient ```hcl module "project" { source = "./fabric/modules/project" - billing_account = "123456-123456-123456" - name = "project-example" - parent = "folders/1234567890" - prefix = "foo" + billing_account = var.billing_account_id + name = "project" + parent = var.folder_id + prefix = var.prefix group_iam = { - "gcp-security-admins@example.com" = [ + (var.group_email) = [ "roles/cloudasset.owner", "roles/cloudsupport.techSupportEditor", "roles/iam.securityReviewer", @@ -100,7 +101,7 @@ module "project" { ] } } -# tftest modules=1 resources=5 inventory=iam-group.yaml +# tftest modules=1 resources=5 inventory=iam-group.yaml e2e ``` The `iam_bindings` variable behaves like a more verbose version of `iam`, and allows setting binding-level IAM conditions. @@ -108,10 +109,10 @@ The `iam_bindings` variable behaves like a more verbose version of `iam`, and al ```hcl module "project" { source = "./fabric/modules/project" - billing_account = "123456-123456-123456" - name = "project-example" - parent = "folders/1234567890" - prefix = "foo" + billing_account = var.billing_account_id + name = "project" + parent = var.folder_id + prefix = var.prefix services = [ "container.googleapis.com", "stackdriver.googleapis.com" @@ -119,7 +120,7 @@ module "project" { iam_bindings = { iam_admin_conditional = { members = [ - "group:test-admins@example.org" + "group:${var.group_email}" ] role = "roles/resourcemanager.projectIamAdmin" condition = { @@ -135,7 +136,7 @@ module "project" { } } } -# tftest modules=1 resources=4 inventory=iam-bindings.yaml +# tftest modules=1 resources=4 inventory=iam-bindings.yaml e2e ``` ### Additive IAM @@ -146,19 +147,22 @@ The `iam_bindings_additive` variable allows setting individual role/principal bi ```hcl module "project" { - source = "./fabric/modules/project" - name = "project-1" + source = "./fabric/modules/project" + billing_account = var.billing_account_id + name = "project" + parent = var.folder_id + prefix = var.prefix services = [ "compute.googleapis.com" ] iam_bindings_additive = { group-owner = { - member = "group:p1-owners@example.org" + member = "group:${var.group_email}" role = "roles/owner" } } } -# tftest modules=1 resources=3 inventory=iam-bindings-additive.yaml +# tftest modules=1 resources=3 inventory=iam-bindings-additive.yaml e2e ``` ### Service Identities and Authoritative IAM @@ -167,23 +171,21 @@ As mentioned above, there are cases where authoritative management of specific I ```hcl module "project" { - source = "./fabric/modules/project" - name = "project-example" - group_iam = { - "foo@example.com" = [ - "roles/editor" - ] - } + source = "./fabric/modules/project" + billing_account = var.billing_account_id + name = "project" + parent = var.folder_id + prefix = var.prefix iam = { "roles/editor" = [ "serviceAccount:${module.project.service_accounts.cloud_services}" ] } } -# tftest modules=1 resources=2 +# tftest modules=1 resources=2 e2e ``` -### Service Identities Requiring Manual Iam Grants +### Service Identities Requiring Manual IAM Grants The module will create service identities at project creation instead of creating of them at the time of first use. This allows granting these service identities roles in other projects, something which is usually necessary in a Shared VPC context. @@ -191,15 +193,21 @@ You can grant roles to service identities using the following construct: ```hcl module "project" { - source = "./fabric/modules/project" - name = "project-example" + source = "./fabric/modules/project" + billing_account = var.billing_account_id + name = "project" + parent = var.folder_id + prefix = var.prefix + services = [ + "apigee.googleapis.com", + ] iam = { "roles/apigee.serviceAgent" = [ "serviceAccount:${module.project.service_accounts.robots.apigee}" ] } } -# tftest modules=1 resources=2 +# tftest modules=1 resources=4 e2e ``` This table lists all affected services and roles that you need to grant to service identities @@ -225,16 +233,26 @@ You can enable Shared VPC Host at the project level and manage project service a ```hcl module "host-project" { - source = "./fabric/modules/project" - name = "my-host-project" + source = "./fabric/modules/project" + billing_account = var.billing_account_id + name = "host" + parent = var.folder_id + prefix = var.prefix shared_vpc_host_config = { enabled = true } } module "service-project" { - source = "./fabric/modules/project" - name = "my-service-project" + source = "./fabric/modules/project" + billing_account = var.billing_account_id + name = "service" + parent = var.folder_id + prefix = var.prefix + services = [ + "container.googleapis.com", + "run.googleapis.com" + ] shared_vpc_service_config = { host_project = module.host-project.project_id service_identity_iam = { @@ -250,23 +268,29 @@ module "service-project" { } } } -# tftest modules=2 resources=8 inventory=shared-vpc.yaml +# tftest modules=2 resources=10 inventory=shared-vpc.yaml e2e ``` The module allows also granting necessary permissions in host project to service identities by specifying which services will be used in service project in `grant_iam_for_services`. ```hcl module "host-project" { - source = "./fabric/modules/project" - name = "my-host-project" + source = "./fabric/modules/project" + billing_account = var.billing_account_id + name = "host" + parent = var.folder_id + prefix = var.prefix shared_vpc_host_config = { enabled = true } } module "service-project" { - source = "./fabric/modules/project" - name = "my-service-project" + source = "./fabric/modules/project" + billing_account = var.billing_account_id + name = "service" + parent = var.folder_id + prefix = var.prefix services = [ "container.googleapis.com", ] @@ -275,7 +299,7 @@ module "service-project" { service_iam_grants = module.service-project.services } } -# tftest modules=2 resources=9 inventory=shared-vpc-auto-grants.yaml +# tftest modules=2 resources=9 inventory=shared-vpc-auto-grants.yaml e2e ``` ## Organization Policies @@ -285,10 +309,10 @@ To manage organization policies, the `orgpolicy.googleapis.com` service should b ```hcl module "project" { source = "./fabric/modules/project" - billing_account = "123456-123456-123456" - name = "project-example" - parent = "folders/1234567890" - prefix = "foo" + billing_account = var.billing_account_id + name = "project" + parent = var.folder_id + prefix = var.prefix org_policies = { "compute.disableGuestAttributesAccess" = { rules = [{ enforce = true }] @@ -334,7 +358,7 @@ module "project" { } } } -# tftest modules=1 resources=8 inventory=org-policies.yaml +# tftest modules=1 resources=8 inventory=org-policies.yaml e2e ``` ### Organization Policy Factory @@ -348,13 +372,13 @@ The example below deploys a few organization policies split between two YAML fil ```hcl module "project" { source = "./fabric/modules/project" - billing_account = "123456-123456-123456" - name = "project-example" - parent = "folders/1234567890" - prefix = "foo" + billing_account = var.billing_account_id + name = "project" + parent = var.folder_id + prefix = var.prefix org_policies_data_path = "configs/org-policies/" } -# tftest modules=1 resources=8 files=boolean,list inventory=org-policies.yaml +# tftest modules=1 resources=8 files=boolean,list inventory=org-policies.yaml e2e ``` ```yaml @@ -415,6 +439,7 @@ module "gcs" { source = "./fabric/modules/gcs" project_id = var.project_id name = "gcs_sink" + prefix = var.prefix force_destroy = true } @@ -422,6 +447,7 @@ module "dataset" { source = "./fabric/modules/bigquery-dataset" project_id = var.project_id id = "bq_sink" + options = { delete_contents_on_destroy = true } } module "pubsub" { @@ -433,15 +459,19 @@ module "pubsub" { module "bucket" { source = "./fabric/modules/logging-bucket" parent_type = "project" - parent = "my-project" + parent = var.project_id id = "bucket" } module "project-host" { source = "./fabric/modules/project" - name = "my-project" - billing_account = "123456-123456-123456" - parent = "folders/1234567890" + name = "project" + billing_account = var.billing_account_id + parent = var.folder_id + prefix = var.prefix + services = [ + "logging.googleapis.com" + ] logging_sinks = { warnings = { destination = module.gcs.id @@ -471,7 +501,7 @@ module "project-host" { no-gce-instances = "resource.type=gce_instance" } } -# tftest modules=5 resources=14 inventory=logging.yaml +# tftest modules=5 resources=15 inventory=logging.yaml e2e ``` ## Data Access Logs @@ -483,13 +513,14 @@ This example shows how to set a non-authoritative access log configuration: ```hcl module "project" { source = "./fabric/modules/project" - name = "my-project" - billing_account = "123456-123456-123456" - parent = "folders/1234567890" + name = "project" + billing_account = var.billing_account_id + parent = var.folder_id + prefix = var.prefix logging_data_access = { allServices = { # logs for principals listed here will be excluded - ADMIN_READ = ["group:organization-admins@example.org"] + ADMIN_READ = ["group:${var.group_email}"] } "storage.googleapis.com" = { DATA_READ = [] @@ -497,33 +528,34 @@ module "project" { } } } -# tftest modules=1 resources=3 inventory=logging-data-access.yaml +# tftest modules=1 resources=3 inventory=logging-data-access.yaml e2e ``` -## Cloud Kms Encryption Keys +## Cloud KMS Encryption Keys The module offers a simple, centralized way to assign `roles/cloudkms.cryptoKeyEncrypterDecrypter` to service identities. ```hcl module "project" { - source = "./fabric/modules/project" - name = "my-project" - prefix = "foo" + source = "./fabric/modules/project" + billing_account = var.billing_account_id + name = "project" + prefix = var.prefix + parent = var.folder_id services = [ "compute.googleapis.com", "storage.googleapis.com" ] service_encryption_key_ids = { compute = [ - "projects/kms-central-prj/locations/europe-west3/keyRings/my-keyring/cryptoKeys/europe3-gce", - "projects/kms-central-prj/locations/europe-west4/keyRings/my-keyring/cryptoKeys/europe4-gce" + var.kms_key.id ] storage = [ - "projects/kms-central-prj/locations/europe/keyRings/my-keyring/cryptoKeys/europe-gcs" + var.kms_key.id ] } } -# tftest modules=1 resources=7 +# tftest modules=1 resources=6 e2e ``` ## Tags @@ -548,7 +580,8 @@ module "org" { module "project" { source = "./fabric/modules/project" - name = "test-project" + name = "project" + parent = var.folder_id tag_bindings = { env-prod = module.org.tag_values["environment/prod"].id foo = "tagValues/12345678" @@ -565,8 +598,11 @@ One non-obvious output is `service_accounts`, which offers a simple way to disco ```hcl module "project" { - source = "./fabric/modules/project" - name = "project-example" + source = "./fabric/modules/project" + billing_account = var.billing_account_id + name = "project" + prefix = var.prefix + parent = var.folder_id services = [ "compute.googleapis.com" ] @@ -575,9 +611,222 @@ module "project" { output "compute_robot" { value = module.project.service_accounts.robots.compute } -# tftest modules=1 resources=2 inventory:outputs.yaml +# tftest modules=1 resources=2 inventory:outputs.yaml e2e ``` +### Managing project related configuration without creating it + +The module offers managing all related resources without ever touching the project itself by using `project_create = false` + +```hcl +module "create-project" { + source = "./fabric/modules/project" + billing_account = var.billing_account_id + name = "project" + parent = var.folder_id + prefix = var.prefix +} + +module "project" { + source = "./fabric/modules/project" + depends_on = [module.create-project] + billing_account = var.billing_account_id + name = "project" + parent = var.folder_id + prefix = var.prefix + project_create = false + + group_iam = { + (var.group_email) = [ + "roles/cloudasset.owner", + "roles/cloudsupport.techSupportEditor", + "roles/iam.securityReviewer", + "roles/logging.admin", + ] + } + iam_bindings = { + iam_admin_conditional = { + members = [ + "group:${var.group_email}" + ] + role = "roles/resourcemanager.projectIamAdmin" + condition = { + title = "delegated_network_user_one" + expression = <<-END + api.getAttribute( + 'iam.googleapis.com/modifiedGrantsByRole', [] + ).hasOnly([ + 'roles/compute.networkAdmin' + ]) + END + } + } + } + iam_bindings_additive = { + group-owner = { + member = "group:${var.group_email}" + role = "roles/owner" + } + } + iam = { + "roles/editor" = [ + "serviceAccount:${module.project.service_accounts.cloud_services}" + ] + "roles/apigee.serviceAgent" = [ + "serviceAccount:${module.project.service_accounts.robots.apigee}" + ] + } + logging_data_access = { + allServices = { + # logs for principals listed here will be excluded + ADMIN_READ = ["group:${var.group_email}"] + } + "storage.googleapis.com" = { + DATA_READ = [] + DATA_WRITE = [] + } + } + logging_sinks = { + warnings = { + destination = module.gcs.id + filter = "severity=WARNING" + type = "storage" + } + info = { + destination = module.dataset.id + filter = "severity=INFO" + type = "bigquery" + } + notice = { + destination = module.pubsub.id + filter = "severity=NOTICE" + type = "pubsub" + } + debug = { + destination = module.bucket.id + filter = "severity=DEBUG" + exclusions = { + no-compute = "logName:compute" + } + type = "logging" + } + } + logging_exclusions = { + no-gce-instances = "resource.type=gce_instance" + } + org_policies = { + "compute.disableGuestAttributesAccess" = { + rules = [{ enforce = true }] + } + "compute.skipDefaultNetworkCreation" = { + rules = [{ enforce = true }] + } + "iam.disableServiceAccountKeyCreation" = { + rules = [{ enforce = true }] + } + "iam.disableServiceAccountKeyUpload" = { + rules = [ + { + condition = { + expression = "resource.matchTagId('tagKeys/1234', 'tagValues/1234')" + title = "condition" + description = "test condition" + location = "somewhere" + } + enforce = true + }, + { + enforce = false + } + ] + } + "iam.allowedPolicyMemberDomains" = { + rules = [{ + allow = { + values = ["C0xxxxxxx", "C0yyyyyyy"] + } + }] + } + "compute.trustedImageProjects" = { + rules = [{ + allow = { + values = ["projects/my-project"] + } + }] + } + "compute.vmExternalIpAccess" = { + rules = [{ deny = { all = true } }] + } + } + shared_vpc_service_config = { + host_project = module.host-project.project_id + service_iam_grants = module.project.services + service_identity_iam = { + "roles/cloudasset.owner" = [ + "cloudservices", "container-engine" + ] + } + } + services = [ + "apigee.googleapis.com", + "bigquery.googleapis.com", + "container.googleapis.com", + "logging.googleapis.com", + "run.googleapis.com", + "storage.googleapis.com", + ] + service_encryption_key_ids = { + compute = [ + var.kms_key.id + ] + storage = [ + var.kms_key.id + ] + } +} + +module "host-project" { + source = "./fabric/modules/project" + billing_account = var.billing_account_id + name = "host" + parent = var.folder_id + prefix = var.prefix + shared_vpc_host_config = { + enabled = true + } +} + +module "gcs" { + source = "./fabric/modules/gcs" + project_id = var.project_id + name = "gcs_sink" + prefix = var.prefix + force_destroy = true +} + +module "dataset" { + source = "./fabric/modules/bigquery-dataset" + project_id = var.project_id + id = "bq_sink" + options = { delete_contents_on_destroy = true } +} + +module "pubsub" { + source = "./fabric/modules/pubsub" + project_id = var.project_id + name = "pubsub_sink" +} + +module "bucket" { + source = "./fabric/modules/logging-bucket" + parent_type = "project" + parent = var.project_id + id = "bucket" +} +# tftest modules=7 resources=53 inventory=data.yaml e2e +``` + + ## Files diff --git a/modules/project/logging.tf b/modules/project/logging.tf index 0181f04f56..6694c176a2 100644 --- a/modules/project/logging.tf +++ b/modules/project/logging.tf @@ -69,7 +69,8 @@ resource "google_logging_project_sink" "sink" { depends_on = [ google_project_iam_binding.authoritative, google_project_iam_binding.bindings, - google_project_iam_member.bindings + google_project_iam_member.bindings, + google_project_service.project_services ] } diff --git a/modules/project/service-agents.yaml b/modules/project/service-agents.yaml index c8eff2df97..eb38dc4cc9 100644 --- a/modules/project/service-agents.yaml +++ b/modules/project/service-agents.yaml @@ -18,7 +18,7 @@ service_agent: "service-%s@gcp-sa-adsdatahub.iam.gserviceaccount.com" - name: "aiplatform" service_agent: "service-%s@gcp-sa-aiplatform.iam.gserviceaccount.com" - jit: true + jit: true # roles/aiplatform.customCodeServiceAgent - name: "aiplatform-cc" service_agent: "service-%s@gcp-sa-aiplatform-cc.iam.gserviceaccount.com" - name: "alloydb" @@ -37,7 +37,7 @@ service_agent: "service-%s@gcp-sa-apigateway-mgmt.iam.gserviceaccount.com" - name: "apigee" service_agent: "service-%s@gcp-sa-apigee.iam.gserviceaccount.com" - jit: true #roles/apigee.serviceAgent + jit: true # roles/apigee.serviceAgent - name: "apigeeregistry" service_agent: "service-%s@gcp-sa-apigeeregistry.iam.gserviceaccount.com" - name: "appdevelopmentexperience" @@ -221,7 +221,7 @@ service_agent: "service-%s@gcp-sa-healthcare.iam.gserviceaccount.com" - name: "iap" service_agent: "service-%s@gcp-sa-iap.iam.gserviceaccount.com" - jit: true + jit: true # none - name: "identitytoolkit" service_agent: "service-%s@gcp-sa-identitytoolkit.iam.gserviceaccount.com" - name: "ids" @@ -314,7 +314,7 @@ service_agent: "service-%s@gcp-sa-spectrumsas.iam.gserviceaccount.com" - name: "secretmanager" service_agent: "service-%s@gcp-sa-secretmanager.iam.gserviceaccount.com" - jit: true + jit: true # none - name: "securedlandingzone" service_agent: "service-%s@gcp-sa-slz.iam.gserviceaccount.com" - name: "securitycenter-notification" diff --git a/tests/examples/test_plan.py b/tests/examples/test_plan.py index 3ff2992ed5..22525698ed 100644 --- a/tests/examples/test_plan.py +++ b/tests/examples/test_plan.py @@ -18,9 +18,18 @@ from pathlib import Path BASE_PATH = Path(__file__).parent -COUNT_TEST_RE = re.compile(r'# tftest +modules=(\d+) +resources=(\d+)' + - r'(?: +files=([\w@,_-]+))?' + - r'(?: +inventory=([\w\-.]+))?') +COUNT_TEST_RE = re.compile(r'# tftest +modules=(?P\d+) +resources=(?P\d+)' + + r'(?: +files=(?P[\w@,_-]+))?' + + r'(?: +inventory=(?P[\w\-.]+))?') + + +def prepare_files(example, test_path, line): + if line is not None: + requested_files = line.split(',') + for f in requested_files: + destination = test_path / example.files[f].path + destination.parent.mkdir(parents=True, exist_ok=True) + destination.write_text(example.files[f].content) def test_example(plan_validator, tmp_path, example): @@ -33,21 +42,16 @@ def test_example(plan_validator, tmp_path, example): if assets_path.exists(): (tmp_path / 'assets').symlink_to(assets_path) - expected_modules = int(match.group(1)) - expected_resources = int(match.group(2)) + expected_modules = int(match.group("modules")) + expected_resources = int(match.group("resources")) - if match.group(3) is not None: - requested_files = match.group(3).split(',') - for f in requested_files: - destination = tmp_path / example.files[f].path - destination.parent.mkdir(parents=True, exist_ok=True) - destination.write_text(example.files[f].content) + prepare_files(example, tmp_path, match.group("files")) inventory = [] - if match.group(4) is not None: + if match.group("inventory") is not None: python_test_path = str(example.module).replace('-', '_') inventory = BASE_PATH.parent / python_test_path / 'examples' - inventory = inventory / match.group(4) + inventory = inventory / match.group("inventory") # TODO: force plan_validator to never copy files (we're already # running from a temp dir) diff --git a/tests/examples/variables.tf b/tests/examples/variables.tf index 9a65aa7a52..ebdbb155cb 100644 --- a/tests/examples/variables.tf +++ b/tests/examples/variables.tf @@ -22,9 +22,13 @@ variable "billing_account_id" { default = "123456-123456-123456" } +variable "group_email" { + default = "organization-admins@example.org" +} + variable "kms_key" { default = { - self_link = "kms_key_self_link" + id = "kms_key_self_link" } } diff --git a/tests/examples_e2e/README.md b/tests/examples_e2e/README.md index 027ef21c8a..bab4337288 100644 --- a/tests/examples_e2e/README.md +++ b/tests/examples_e2e/README.md @@ -9,7 +9,7 @@ Prepare following information: * prepare service account that has necessary permissions (able to assign billing account to project, resource creation etc) # How does it work -Each test case is provided by additional environment defined in [variables.tf](./variables.tf). This simplifies writing the examples as this follows the same structure as for non-end-to-end tests, and allows multiple, independent and concurrent runs of tests. +Each test case is provided by additional environment defined in [variables.tf](../examples/variables.tf). This simplifies writing the examples as this follows the same structure as for non-end-to-end tests, and allows multiple, independent and concurrent runs of tests. The test environment can be provisioned automatically during the test run (which now takes ~2 minutes) and destroyed and the end, when of the tests (Option 1 below), which is targeting automated runs in CI/CD pipeline, or can be provisioned manually to reduce test time, which might be typical use case for tests run locally. @@ -18,6 +18,7 @@ The test environment can be provisioned automatically during the test run (which ## Create `e2e.tfvars` file ```hcl billing_account = "123456-123456-123456" # billing account id to associate projects +group_email = "group@example.org" # existing group within organization organization_id = "1234567890" # your organization id parent = "folders/1234567890" # folder under which test resources will be created prefix = "your-unique-prefix" # unique prefix for projects @@ -27,15 +28,17 @@ region = "europe-west4" # region to use ``` And set environment variable pointing to the file: ```bash +export TF_VAR_prefix="your-unique-prefix" # unique prefix for projects, no longer than 7 characters export TFTEST_E2E_SETUP_TFVARS_PATH= ``` Or set above variables in environment: ```bash export TF_VAR_billing_account="123456-123456-123456" # billing account id to associate projects +export TF_VAR_group_email="group@example.org" # existing group within organization export TF_VAR_organization_id="1234567890" # your organization id export TF_VAR_parent="folders/1234567890" # folder under which test resources will be created -export TF_VAR_prefix="your-unique-prefix" # unique prefix for projects +export TF_VAR_prefix="your-unique-prefix" # unique prefix for projects, no longer than 7 characters export TF_VAR_region="europe-west4" # region to use ``` @@ -55,6 +58,7 @@ pytest tests/examples_e2e In `tests/examples_e2e/setup_module` create `terraform.tfvars` with following values: ```hcl billing_account = "123456-123456-123456" # billing account id to associate projects +group_email = "group@example.org" # existing group within organization organization_id = "1234567890" # your organization id parent = "folders/1234567890" # folder under which test resources will be created prefix = "your-unique-prefix" # unique prefix for projects @@ -79,6 +83,7 @@ This will generate also `tests/examples_e2e/setup_module/e2e_tests.tfvars` for y ## Setup your environment ```bash export TFTEST_E2E_TFVARS_PATH=`pwd`/tests/examples_e2e/setup_module/e2e_tests.tfvars # generated above +export TF_VAR_prefix="your-unique-prefix" # unique prefix for projects, no longer than 7 characters ``` ## Run tests diff --git a/tests/examples_e2e/setup_module/e2e_tests.tfvars.tftpl b/tests/examples_e2e/setup_module/e2e_tests.tfvars.tftpl index c21d77422a..31a34d3df5 100644 --- a/tests/examples_e2e/setup_module/e2e_tests.tfvars.tftpl +++ b/tests/examples_e2e/setup_module/e2e_tests.tfvars.tftpl @@ -12,14 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -bucket= "${bucket}" +bucket = "${bucket}" billing_account_id = "${billing_account_id}" -kms_key= { - self_link = "kms_key_self_link" +kms_key = { + id = "${kms_key_id}" } +group_email = "${group_email}" organization_id = "${organization_id}" -folder_id = "${folder_id}" -prefix = "${prefix}" +folder_id = "folders/${folder_id}" project_id = "${project_id}" region = "${region}" service_account = { diff --git a/tests/examples_e2e/setup_module/main.tf b/tests/examples_e2e/setup_module/main.tf index 9bc5a9799c..e781d779bc 100644 --- a/tests/examples_e2e/setup_module/main.tf +++ b/tests/examples_e2e/setup_module/main.tf @@ -13,11 +13,14 @@ # limitations under the License. locals { - prefix = "${var.prefix}-${var.timestamp}-${var.suffix}" + prefix = "${var.prefix}-${var.timestamp}${var.suffix}" services = [ # trimmed down list of services, to be extended as needed + "apigee.googleapis.com", + "bigquery.googleapis.com", "cloudbuild.googleapis.com", "cloudfunctions.googleapis.com", + "cloudkms.googleapis.com", "cloudresourcemanager.googleapis.com", "compute.googleapis.com", "iam.googleapis.com", @@ -77,14 +80,28 @@ resource "google_service_account" "service_account" { depends_on = [google_project_service.project_service] } +resource "google_kms_key_ring" "keyring" { + name = "keyring" + project = google_project.project.project_id + location = var.region + depends_on = [google_project_service.project_service] +} + +resource "google_kms_crypto_key" "key" { + name = "crypto-key-example" + key_ring = google_kms_key_ring.keyring.id + rotation_period = "100000s" +} + resource "local_file" "terraform_tfvars" { filename = "e2e_tests.tfvars" content = templatefile("e2e_tests.tfvars.tftpl", { bucket = google_storage_bucket.bucket.name billing_account_id = var.billing_account - organization_id = var.organization_id folder_id = google_folder.folder.folder_id - prefix = local.prefix + group_email = var.group_email + kms_key_id = google_kms_crypto_key.key.id + organization_id = var.organization_id project_id = google_project.project.project_id region = var.region service_account = { diff --git a/tests/examples_e2e/setup_module/variables.tf b/tests/examples_e2e/setup_module/variables.tf index d936cb2080..16f110df0a 100644 --- a/tests/examples_e2e/setup_module/variables.tf +++ b/tests/examples_e2e/setup_module/variables.tf @@ -15,6 +15,9 @@ variable "billing_account" { type = string } +variable "group_email" { + type = string +} variable "organization_id" { type = string } diff --git a/tests/examples_e2e/test_plan.py b/tests/examples_e2e/test_plan.py index 84579b6b41..c9936b9bbf 100644 --- a/tests/examples_e2e/test_plan.py +++ b/tests/examples_e2e/test_plan.py @@ -14,16 +14,14 @@ import re from pathlib import Path +from ..examples.test_plan import COUNT_TEST_RE, prepare_files BASE_PATH = Path(__file__).parent -COUNT_TEST_RE = re.compile(r'# tftest +modules=(\d+) +resources=(\d+)' + - r'(?: +files=([\w@,_-]+))?' + - r'(?: +inventory=([\w\-.]+))?') def test_example(e2e_validator, tmp_path, examples_e2e, e2e_tfvars_path): (tmp_path / 'fabric').symlink_to(BASE_PATH.parents[1]) - (tmp_path / 'variables.tf').symlink_to(BASE_PATH / 'variables.tf') + (tmp_path / 'variables.tf').symlink_to(BASE_PATH.parent / 'examples' / 'variables.tf') (tmp_path / 'main.tf').write_text(examples_e2e.code) assets_path = BASE_PATH.parent / str(examples_e2e.module).replace( '-', '_') / 'assets' @@ -31,5 +29,9 @@ def test_example(e2e_validator, tmp_path, examples_e2e, e2e_tfvars_path): (tmp_path / 'assets').symlink_to(assets_path) (tmp_path / 'terraform.tfvars').symlink_to(e2e_tfvars_path) + # add files the same way as it is done for examples + if match := COUNT_TEST_RE.search(examples_e2e.code): + prepare_files(examples_e2e, tmp_path, match.group("files")) + e2e_validator(module_path=tmp_path, extra_files=[], tf_var_files=[(tmp_path / 'terraform.tfvars')]) diff --git a/tests/examples_e2e/variables.tf b/tests/examples_e2e/variables.tf deleted file mode 100644 index 9a65aa7a52..0000000000 --- a/tests/examples_e2e/variables.tf +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright 2023 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# common variables used for examples - -variable "bucket" { - default = "bucket" -} - -variable "billing_account_id" { - default = "123456-123456-123456" -} - -variable "kms_key" { - default = { - self_link = "kms_key_self_link" - } -} - -variable "organization_id" { - default = "organizations/1122334455" -} - -variable "folder_id" { - default = "folders/1122334455" -} - -variable "prefix" { - default = "test" -} - -variable "project_id" { - default = "project-id" -} - -variable "region" { - default = "region" -} - -variable "service_account" { - default = { - id = "service_account_id" - email = "service_account_email" - iam_email = "service_account_iam_email" - } -} - -variable "subnet" { - default = { - name = "subnet_name" - region = "subnet_region" - cidr = "subnet_cidr" - self_link = "subnet_self_link" - } -} - -variable "vpc" { - default = { - name = "vpc_name" - self_link = "projects/xxx/global/networks/aaa" - id = "projects/xxx/global/networks/aaa" - } -} - -variable "vpc1" { - default = { - name = "vpc_name" - self_link = "projects/xxx/global/networks/bbb" - } -} - -variable "vpc2" { - default = { - name = "vpc2_name" - self_link = "projects/xxx/global/networks/ccc" - } -} - -variable "zone" { - default = "zone" -} diff --git a/tests/fixtures.py b/tests/fixtures.py index caa9c9456f..01a89f423c 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -298,9 +298,12 @@ def e2e_validator(module_path, extra_files, tf_var_files, basedir=None): tf.setup(extra_files=extra_files, upgrade=True) tf_var_files = [(basedir / x).resolve() for x in tf_var_files or []] + # to allow different tests to create projects (or other globally unique resources) with the same name + # bump prefix forward on each test execution + prefix = f'{os.environ.get("TF_VAR_prefix")}-{int(time.time())}{os.environ.get("PYTEST_XDIST_WORKER", "0")[-2:]}' try: - apply = tf.apply(tf_var_file=tf_var_files) - plan = tf.plan(output=True, tf_var_file=tf_var_files) + apply = tf.apply(tf_var_file=tf_var_files, tf_vars={"prefix": prefix}) + plan = tf.plan(output=True, tf_var_file=tf_var_files, tf_vars={"prefix": prefix}) changes = {} for resource_name, value in plan.resource_changes.items(): if value.get('change', {}).get('actions') != ['no-op']: @@ -324,7 +327,7 @@ def e2e_validator(module_path, extra_files, tf_var_files, basedir=None): # If above did not fail, this should not either, but left as a safety check assert changes == {}, f'Plan not empty for following resources: {", ".join(changes.keys())}' finally: - destroy = tf.destroy(tf_var_file=tf_var_files) + destroy = tf.destroy(tf_var_file=tf_var_files, tf_vars={'prefix': prefix}) @pytest.fixture(name='e2e_validator') @@ -371,7 +374,7 @@ def e2e_tfvars_path(): tf = tftest.TerraformTest(test_path, binary=binary) tf_vars_file = None tf_vars = { - 'suffix': os.environ.get("PYTEST_XDIST_WORKER", "0"), + 'suffix': os.environ.get("PYTEST_XDIST_WORKER", "0")[-2:], # take at most 2 last chars for suffix 'timestamp': str(int(time.time())) } if 'TFTEST_E2E_SETUP_TFVARS_PATH' in os.environ: diff --git a/tests/modules/project/examples/basic.yaml b/tests/modules/project/examples/basic.yaml index 56e6ecc02f..919a0581ee 100644 --- a/tests/modules/project/examples/basic.yaml +++ b/tests/modules/project/examples/basic.yaml @@ -17,21 +17,21 @@ values: module.project.google_project.project[0]: auto_create_network: false billing_account: 123456-123456-123456 - folder_id: '1234567890' + folder_id: '1122334455' labels: null - name: foo-myproject + name: test-project org_id: null - project_id: foo-myproject + project_id: test-project skip_delete: false module.project.google_project_service.project_services["container.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: foo-myproject + project: test-project service: container.googleapis.com module.project.google_project_service.project_services["stackdriver.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: foo-myproject + project: test-project service: stackdriver.googleapis.com counts: diff --git a/tests/modules/project/examples/data.yaml b/tests/modules/project/examples/data.yaml new file mode 100644 index 0000000000..b7ec3d23aa --- /dev/null +++ b/tests/modules/project/examples/data.yaml @@ -0,0 +1,338 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +values: + module.bucket.google_logging_project_bucket_config.bucket[0]: + bucket_id: bucket + project: project-id + module.create-project.google_project.project[0]: + billing_account: 123456-123456-123456 + folder_id: '1122334455' + name: test-project + project_id: test-project + module.dataset.google_bigquery_dataset.default: + dataset_id: bq_sink + delete_contents_on_destroy: true + project: project-id + module.gcs.google_storage_bucket.bucket: + name: test-gcs_sink + project: project-id + module.host-project.google_compute_shared_vpc_host_project.shared_vpc_host[0]: + project: test-host + module.host-project.google_project.project[0]: + billing_account: 123456-123456-123456 + folder_id: '1122334455' + name: test-host + project_id: test-host + module.project.data.google_bigquery_default_service_account.bq_sa[0]: + project: test-project + module.project.data.google_project.project[0]: + project_id: test-project + module.project.data.google_storage_project_service_account.gcs_sa[0]: + project: test-project + module.project.google_bigquery_dataset_iam_member.bq-sinks-binding["info"]: + role: roles/bigquery.dataEditor + module.project.google_compute_shared_vpc_service_project.shared_vpc_service[0]: + host_project: test-host + service_project: test-project + module.project.google_kms_crypto_key_iam_member.service_identity_cmek["compute.kms_key_self_link"]: + crypto_key_id: kms_key_self_link + role: roles/cloudkms.cryptoKeyEncrypterDecrypter + module.project.google_kms_crypto_key_iam_member.service_identity_cmek["storage.kms_key_self_link"]: + crypto_key_id: kms_key_self_link + role: roles/cloudkms.cryptoKeyEncrypterDecrypter + module.project.google_logging_project_exclusion.logging-exclusion["no-gce-instances"]: + filter: resource.type=gce_instance + name: no-gce-instances + project: test-project + module.project.google_logging_project_sink.sink["debug"]: + exclusions: + - description: null + disabled: false + filter: logName:compute + name: no-compute + filter: severity=DEBUG + name: debug + project: test-project + module.project.google_logging_project_sink.sink["info"]: + exclusions: [] + filter: severity=INFO + name: info + project: test-project + module.project.google_logging_project_sink.sink["notice"]: + destination: pubsub.googleapis.com/projects/project-id/topics/pubsub_sink + disabled: false + exclusions: [] + filter: severity=NOTICE + name: notice + project: test-project + module.project.google_logging_project_sink.sink["warnings"]: + destination: storage.googleapis.com/test-gcs_sink + disabled: false + exclusions: [] + filter: severity=WARNING + name: warnings + project: test-project + module.project.google_org_policy_policy.default["compute.disableGuestAttributesAccess"]: + name: projects/test-project/policies/compute.disableGuestAttributesAccess + parent: projects/test-project + spec: + - inherit_from_parent: null + rules: + - allow_all: null + condition: [] + deny_all: null + enforce: 'TRUE' + values: [] + module.project.google_org_policy_policy.default["compute.skipDefaultNetworkCreation"]: + name: projects/test-project/policies/compute.skipDefaultNetworkCreation + parent: projects/test-project + spec: + - inherit_from_parent: null + rules: + - allow_all: null + condition: [] + deny_all: null + enforce: 'TRUE' + values: [] + module.project.google_org_policy_policy.default["compute.trustedImageProjects"]: + name: projects/test-project/policies/compute.trustedImageProjects + parent: projects/test-project + spec: + - inherit_from_parent: null + rules: + - allow_all: null + condition: [] + deny_all: null + enforce: null + values: + - allowed_values: + - projects/my-project + denied_values: null + module.project.google_org_policy_policy.default["compute.vmExternalIpAccess"]: + name: projects/test-project/policies/compute.vmExternalIpAccess + parent: projects/test-project + spec: + - inherit_from_parent: null + rules: + - allow_all: null + condition: [] + deny_all: 'TRUE' + enforce: null + values: [] + module.project.google_org_policy_policy.default["iam.allowedPolicyMemberDomains"]: + name: projects/test-project/policies/iam.allowedPolicyMemberDomains + parent: projects/test-project + spec: + - inherit_from_parent: null + rules: + - allow_all: null + condition: [] + deny_all: null + enforce: null + values: + - allowed_values: + - C0xxxxxxx + - C0yyyyyyy + denied_values: null + module.project.google_org_policy_policy.default["iam.disableServiceAccountKeyCreation"]: + name: projects/test-project/policies/iam.disableServiceAccountKeyCreation + parent: projects/test-project + spec: + - inherit_from_parent: null + rules: + - allow_all: null + condition: [] + deny_all: null + enforce: 'TRUE' + values: [] + module.project.google_org_policy_policy.default["iam.disableServiceAccountKeyUpload"]: + name: projects/test-project/policies/iam.disableServiceAccountKeyUpload + parent: projects/test-project + spec: + - inherit_from_parent: null + rules: + - allow_all: null + condition: + - description: test condition + expression: resource.matchTagId('tagKeys/1234', 'tagValues/1234') + location: somewhere + title: condition + deny_all: null + enforce: 'TRUE' + values: [] + - allow_all: null + condition: [] + deny_all: null + enforce: 'FALSE' + values: [] + module.project.google_project_iam_audit_config.default["allServices"]: + audit_log_config: + - exempted_members: + - group:organization-admins@example.org + log_type: ADMIN_READ + project: test-project + service: allServices + module.project.google_project_iam_audit_config.default["storage.googleapis.com"]: + audit_log_config: + - exempted_members: [] + log_type: DATA_READ + - exempted_members: [] + log_type: DATA_WRITE + project: test-project + service: storage.googleapis.com + module.project.google_project_iam_binding.authoritative["roles/apigee.serviceAgent"]: + condition: [] + project: test-project + role: roles/apigee.serviceAgent + module.project.google_project_iam_binding.authoritative["roles/cloudasset.owner"]: + condition: [] + project: test-project + role: roles/cloudasset.owner + module.project.google_project_iam_binding.authoritative["roles/cloudsupport.techSupportEditor"]: + condition: [] + project: test-project + role: roles/cloudsupport.techSupportEditor + module.project.google_project_iam_binding.authoritative["roles/editor"]: + condition: [] + project: test-project + role: roles/editor + module.project.google_project_iam_binding.authoritative["roles/iam.securityReviewer"]: + condition: [] + project: test-project + role: roles/iam.securityReviewer + module.project.google_project_iam_binding.authoritative["roles/logging.admin"]: + condition: [] + project: test-project + role: roles/logging.admin + module.project.google_project_iam_binding.bindings["iam_admin_conditional"]: + condition: + - description: null + expression: "api.getAttribute(\n 'iam.googleapis.com/modifiedGrantsByRole',\ + \ []\n).hasOnly([\n 'roles/compute.networkAdmin'\n])\n" + title: delegated_network_user_one + members: + - group:organization-admins@example.org + project: test-project + role: roles/resourcemanager.projectIamAdmin + module.project.google_project_iam_member.bindings["group-owner"]: + condition: [] + member: group:organization-admins@example.org + project: test-project + role: roles/owner + module.project.google_project_iam_member.bucket-sinks-binding["debug"]: + condition: + - title: debug bucket writer + role: roles/logging.bucketWriter + module.project.google_project_iam_member.shared_vpc_host_robots["roles/cloudasset.owner:cloudservices"]: + condition: [] + project: test-host + role: roles/cloudasset.owner + module.project.google_project_iam_member.shared_vpc_host_robots["roles/cloudasset.owner:container-engine"]: + condition: [] + project: test-host + role: roles/cloudasset.owner + module.project.google_project_iam_member.shared_vpc_host_robots["roles/compute.networkUser:cloudservices"]: + condition: [] + project: test-host + role: roles/compute.networkUser + module.project.google_project_iam_member.shared_vpc_host_robots["roles/compute.networkUser:container"]: + condition: [] + project: test-host + role: roles/compute.networkUser + module.project.google_project_iam_member.shared_vpc_host_robots["roles/compute.securityAdmin:container"]: + condition: [] + project: test-host + role: roles/compute.securityAdmin + module.project.google_project_iam_member.shared_vpc_host_robots["roles/container.hostServiceAgentUser:container"]: + condition: [] + project: test-host + role: roles/container.hostServiceAgentUser + module.project.google_project_iam_member.shared_vpc_host_robots["roles/vpcaccess.user:run"]: + condition: [] + project: test-host + role: roles/vpcaccess.user + module.project.google_project_service.project_services["apigee.googleapis.com"]: + disable_dependent_services: false + disable_on_destroy: false + project: test-project + service: apigee.googleapis.com + module.project.google_project_service.project_services["bigquery.googleapis.com"]: + disable_dependent_services: false + disable_on_destroy: false + project: test-project + service: bigquery.googleapis.com + module.project.google_project_service.project_services["container.googleapis.com"]: + disable_dependent_services: false + disable_on_destroy: false + project: test-project + service: container.googleapis.com + module.project.google_project_service.project_services["logging.googleapis.com"]: + disable_dependent_services: false + disable_on_destroy: false + project: test-project + service: logging.googleapis.com + module.project.google_project_service.project_services["run.googleapis.com"]: + disable_dependent_services: false + disable_on_destroy: false + project: test-project + service: run.googleapis.com + module.project.google_project_service.project_services["storage.googleapis.com"]: + disable_dependent_services: false + disable_on_destroy: false + project: test-project + service: storage.googleapis.com + module.project.google_project_service_identity.jit_si["apigee.googleapis.com"]: + project: test-project + service: apigee.googleapis.com + module.project.google_pubsub_topic_iam_member.pubsub-sinks-binding["notice"]: + condition: [] + project: project-id + role: roles/pubsub.publisher + topic: pubsub_sink + module.project.google_storage_bucket_iam_member.gcs-sinks-binding["warnings"]: + bucket: test-gcs_sink + condition: [] + role: roles/storage.objectCreator + module.pubsub.google_pubsub_topic.default: + name: pubsub_sink + project: project-id + +counts: + google_bigquery_dataset: 1 + google_bigquery_dataset_iam_member: 1 + google_bigquery_default_service_account: 1 + google_compute_shared_vpc_host_project: 1 + google_compute_shared_vpc_service_project: 1 + google_kms_crypto_key_iam_member: 2 + google_logging_project_bucket_config: 1 + google_logging_project_exclusion: 1 + google_logging_project_sink: 4 + google_org_policy_policy: 7 + google_project: 3 + google_project_iam_audit_config: 2 + google_project_iam_binding: 7 + google_project_iam_member: 9 + google_project_service: 6 + google_project_service_identity: 1 + google_pubsub_topic: 1 + google_pubsub_topic_iam_member: 1 + google_storage_bucket: 1 + google_storage_bucket_iam_member: 1 + google_storage_project_service_account: 1 + modules: 7 + resources: 53 + +outputs: {} diff --git a/tests/modules/project/examples/iam-authoritative.yaml b/tests/modules/project/examples/iam-authoritative.yaml index eeb77aa6e5..d889a88312 100644 --- a/tests/modules/project/examples/iam-authoritative.yaml +++ b/tests/modules/project/examples/iam-authoritative.yaml @@ -16,29 +16,29 @@ values: module.project.google_project.project[0]: auto_create_network: false billing_account: 123456-123456-123456 - folder_id: '1234567890' + folder_id: '1122334455' labels: null - name: foo-project-example + name: test-project org_id: null - project_id: foo-project-example + project_id: test-project skip_delete: false timeouts: null module.project.google_project_iam_binding.authoritative["roles/container.hostServiceAgentUser"]: condition: [] members: - serviceAccount:my_gke_service_account - project: foo-project-example + project: test-project role: roles/container.hostServiceAgentUser module.project.google_project_service.project_services["container.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: foo-project-example + project: test-project service: container.googleapis.com timeouts: null module.project.google_project_service.project_services["stackdriver.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: foo-project-example + project: test-project service: stackdriver.googleapis.com timeouts: null diff --git a/tests/modules/project/examples/iam-bindings-additive.yaml b/tests/modules/project/examples/iam-bindings-additive.yaml index 390781f97c..2276622bb3 100644 --- a/tests/modules/project/examples/iam-bindings-additive.yaml +++ b/tests/modules/project/examples/iam-bindings-additive.yaml @@ -15,23 +15,23 @@ values: module.project.google_project.project[0]: auto_create_network: false - billing_account: null - folder_id: null + billing_account: 123456-123456-123456 + folder_id: '1122334455' labels: null - name: project-1 + name: test-project org_id: null - project_id: project-1 + project_id: test-project skip_delete: false timeouts: null module.project.google_project_iam_member.bindings["group-owner"]: condition: [] - member: group:p1-owners@example.org - project: project-1 + member: group:organization-admins@example.org + project: test-project role: roles/owner module.project.google_project_service.project_services["compute.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: project-1 + project: test-project service: compute.googleapis.com timeouts: null diff --git a/tests/modules/project/examples/iam-bindings.yaml b/tests/modules/project/examples/iam-bindings.yaml index c9fee92524..eddc582083 100644 --- a/tests/modules/project/examples/iam-bindings.yaml +++ b/tests/modules/project/examples/iam-bindings.yaml @@ -16,11 +16,11 @@ values: module.project.google_project.project[0]: auto_create_network: false billing_account: 123456-123456-123456 - folder_id: '1234567890' + folder_id: '1122334455' labels: null - name: foo-project-example + name: test-project org_id: null - project_id: foo-project-example + project_id: test-project skip_delete: false timeouts: null module.project.google_project_iam_binding.bindings["iam_admin_conditional"]: @@ -30,19 +30,19 @@ values: \ []\n).hasOnly([\n 'roles/compute.networkAdmin'\n])\n" title: delegated_network_user_one members: - - group:test-admins@example.org - project: foo-project-example + - group:organization-admins@example.org + project: test-project role: roles/resourcemanager.projectIamAdmin module.project.google_project_service.project_services["container.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: foo-project-example + project: test-project service: container.googleapis.com timeouts: null module.project.google_project_service.project_services["stackdriver.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: foo-project-example + project: test-project service: stackdriver.googleapis.com timeouts: null diff --git a/tests/modules/project/examples/iam-group.yaml b/tests/modules/project/examples/iam-group.yaml index 0ca2ecdba9..73f14b80a6 100644 --- a/tests/modules/project/examples/iam-group.yaml +++ b/tests/modules/project/examples/iam-group.yaml @@ -17,26 +17,26 @@ values: module.project.google_project_iam_binding.authoritative["roles/cloudasset.owner"]: condition: [] members: - - group:gcp-security-admins@example.com - project: foo-project-example + - group:organization-admins@example.org + project: test-project role: roles/cloudasset.owner module.project.google_project_iam_binding.authoritative["roles/cloudsupport.techSupportEditor"]: condition: [] members: - - group:gcp-security-admins@example.com - project: foo-project-example + - group:organization-admins@example.org + project: test-project role: roles/cloudsupport.techSupportEditor module.project.google_project_iam_binding.authoritative["roles/iam.securityReviewer"]: condition: [] members: - - group:gcp-security-admins@example.com - project: foo-project-example + - group:organization-admins@example.org + project: test-project role: roles/iam.securityReviewer module.project.google_project_iam_binding.authoritative["roles/logging.admin"]: condition: [] members: - - group:gcp-security-admins@example.com - project: foo-project-example + - group:organization-admins@example.org + project: test-project role: roles/logging.admin counts: diff --git a/tests/modules/project/examples/logging-data-access.yaml b/tests/modules/project/examples/logging-data-access.yaml index 3b35bbdc38..50d3886450 100644 --- a/tests/modules/project/examples/logging-data-access.yaml +++ b/tests/modules/project/examples/logging-data-access.yaml @@ -16,11 +16,11 @@ values: module.project.google_project.project[0]: auto_create_network: false billing_account: 123456-123456-123456 - folder_id: '1234567890' + folder_id: '1122334455' labels: null - name: my-project + name: test-project org_id: null - project_id: my-project + project_id: test-project skip_delete: false timeouts: null module.project.google_project_iam_audit_config.default["allServices"]: @@ -28,7 +28,7 @@ values: - exempted_members: - group:organization-admins@example.org log_type: ADMIN_READ - project: my-project + project: test-project service: allServices module.project.google_project_iam_audit_config.default["storage.googleapis.com"]: audit_log_config: @@ -36,7 +36,7 @@ values: log_type: DATA_READ - exempted_members: [] log_type: DATA_WRITE - project: my-project + project: test-project service: storage.googleapis.com counts: diff --git a/tests/modules/project/examples/logging.yaml b/tests/modules/project/examples/logging.yaml index 9634d8d102..7e96968afe 100644 --- a/tests/modules/project/examples/logging.yaml +++ b/tests/modules/project/examples/logging.yaml @@ -21,7 +21,7 @@ values: disabled: null filter: resource.type=gce_instance name: no-gce-instances - project: my-project + project: test-project module.project-host.google_logging_project_sink.sink["debug"]: description: debug (Terraform-managed). disabled: false @@ -32,7 +32,7 @@ values: name: no-compute filter: severity=DEBUG name: debug - project: my-project + project: test-project unique_writer_identity: true module.project-host.google_logging_project_sink.sink["info"]: description: info (Terraform-managed). @@ -40,7 +40,7 @@ values: exclusions: [] filter: severity=INFO name: info - project: my-project + project: test-project unique_writer_identity: true module.project-host.google_logging_project_sink.sink["notice"]: description: notice (Terraform-managed). @@ -48,25 +48,25 @@ values: exclusions: [] filter: severity=NOTICE name: notice - project: my-project + project: test-project unique_writer_identity: true module.project-host.google_logging_project_sink.sink["warnings"]: description: warnings (Terraform-managed). - destination: storage.googleapis.com/gcs_sink + destination: storage.googleapis.com/test-gcs_sink disabled: false exclusions: [] filter: severity=WARNING name: warnings - project: my-project + project: test-project unique_writer_identity: true module.project-host.google_project.project[0]: auto_create_network: false billing_account: 123456-123456-123456 - folder_id: '1234567890' + folder_id: '1122334455' labels: null - name: my-project + name: test-project org_id: null - project_id: my-project + project_id: test-project skip_delete: false module.project-host.google_project_iam_member.bucket-sinks-binding["debug"]: condition: @@ -76,7 +76,7 @@ values: condition: [] role: roles/pubsub.publisher module.project-host.google_storage_bucket_iam_member.gcs-sinks-binding["warnings"]: - bucket: gcs_sink + bucket: test-gcs_sink condition: [] role: roles/storage.objectCreator diff --git a/tests/modules/project/examples/org-policies.yaml b/tests/modules/project/examples/org-policies.yaml index d4dddc75bf..6539c32c41 100644 --- a/tests/modules/project/examples/org-policies.yaml +++ b/tests/modules/project/examples/org-policies.yaml @@ -14,8 +14,8 @@ values: module.project.google_org_policy_policy.default["compute.disableGuestAttributesAccess"]: - name: projects/foo-project-example/policies/compute.disableGuestAttributesAccess - parent: projects/foo-project-example + name: projects/test-project/policies/compute.disableGuestAttributesAccess + parent: projects/test-project spec: - inherit_from_parent: null reset: null @@ -26,8 +26,8 @@ values: enforce: 'TRUE' values: [] module.project.google_org_policy_policy.default["compute.skipDefaultNetworkCreation"]: - name: projects/foo-project-example/policies/compute.skipDefaultNetworkCreation - parent: projects/foo-project-example + name: projects/test-project/policies/compute.skipDefaultNetworkCreation + parent: projects/test-project spec: - inherit_from_parent: null reset: null @@ -38,8 +38,8 @@ values: enforce: 'TRUE' values: [] module.project.google_org_policy_policy.default["compute.trustedImageProjects"]: - name: projects/foo-project-example/policies/compute.trustedImageProjects - parent: projects/foo-project-example + name: projects/test-project/policies/compute.trustedImageProjects + parent: projects/test-project spec: - inherit_from_parent: null reset: null @@ -53,8 +53,8 @@ values: - projects/my-project denied_values: null module.project.google_org_policy_policy.default["compute.vmExternalIpAccess"]: - name: projects/foo-project-example/policies/compute.vmExternalIpAccess - parent: projects/foo-project-example + name: projects/test-project/policies/compute.vmExternalIpAccess + parent: projects/test-project spec: - inherit_from_parent: null reset: null @@ -65,8 +65,8 @@ values: enforce: null values: [] module.project.google_org_policy_policy.default["iam.allowedPolicyMemberDomains"]: - name: projects/foo-project-example/policies/iam.allowedPolicyMemberDomains - parent: projects/foo-project-example + name: projects/test-project/policies/iam.allowedPolicyMemberDomains + parent: projects/test-project spec: - inherit_from_parent: null reset: null @@ -81,8 +81,8 @@ values: - C0yyyyyyy denied_values: null module.project.google_org_policy_policy.default["iam.disableServiceAccountKeyCreation"]: - name: projects/foo-project-example/policies/iam.disableServiceAccountKeyCreation - parent: projects/foo-project-example + name: projects/test-project/policies/iam.disableServiceAccountKeyCreation + parent: projects/test-project spec: - inherit_from_parent: null reset: null @@ -93,8 +93,8 @@ values: enforce: 'TRUE' values: [] module.project.google_org_policy_policy.default["iam.disableServiceAccountKeyUpload"]: - name: projects/foo-project-example/policies/iam.disableServiceAccountKeyUpload - parent: projects/foo-project-example + name: projects/test-project/policies/iam.disableServiceAccountKeyUpload + parent: projects/test-project spec: - inherit_from_parent: null reset: null @@ -115,10 +115,10 @@ values: values: [] module.project.google_project.project[0]: billing_account: 123456-123456-123456 - folder_id: '1234567890' - name: foo-project-example + folder_id: '1122334455' + name: test-project org_id: null - project_id: foo-project-example + project_id: test-project counts: google_org_policy_policy: 7 diff --git a/tests/modules/project/examples/shared-vpc-auto-grants.yaml b/tests/modules/project/examples/shared-vpc-auto-grants.yaml index 226612394b..4dacb377b9 100644 --- a/tests/modules/project/examples/shared-vpc-auto-grants.yaml +++ b/tests/modules/project/examples/shared-vpc-auto-grants.yaml @@ -14,25 +14,25 @@ values: module.host-project.google_compute_shared_vpc_host_project.shared_vpc_host[0]: - project: my-host-project + project: test-host module.host-project.google_project.project[0]: - project_id: my-host-project + project_id: test-host module.service-project.google_compute_shared_vpc_service_project.shared_vpc_service[0]: - host_project: my-host-project - service_project: my-service-project + host_project: test-host + service_project: test-service module.service-project.google_project.project[0]: - project_id: my-service-project + project_id: test-service module.service-project.google_project_iam_member.shared_vpc_host_robots["roles/compute.networkUser:cloudservices"]: condition: [] - project: my-host-project + project: test-host role: roles/compute.networkUser module.service-project.google_project_iam_member.shared_vpc_host_robots["roles/compute.networkUser:container"]: condition: [] - project: my-host-project + project: test-host role: roles/compute.networkUser module.service-project.google_project_iam_member.shared_vpc_host_robots["roles/container.hostServiceAgentUser:container"]: condition: [] - project: my-host-project + project: test-host role: roles/container.hostServiceAgentUser counts: diff --git a/tests/modules/project/examples/shared-vpc.yaml b/tests/modules/project/examples/shared-vpc.yaml index 169c897de2..4277d56b3d 100644 --- a/tests/modules/project/examples/shared-vpc.yaml +++ b/tests/modules/project/examples/shared-vpc.yaml @@ -14,29 +14,29 @@ values: module.host-project.google_compute_shared_vpc_host_project.shared_vpc_host[0]: - project: my-host-project + project: test-host module.host-project.google_project.project[0]: - project_id: my-host-project + project_id: test-host module.service-project.google_compute_shared_vpc_service_project.shared_vpc_service[0]: - host_project: my-host-project - service_project: my-service-project + host_project: test-host + service_project: test-service module.service-project.google_project.project[0]: - project_id: my-service-project + project_id: test-service module.service-project.google_project_iam_member.shared_vpc_host_robots["roles/compute.networkUser:cloudservices"]: condition: [] - project: my-host-project + project: test-host role: roles/compute.networkUser module.service-project.google_project_iam_member.shared_vpc_host_robots["roles/compute.networkUser:container-engine"]: condition: [] - project: my-host-project + project: test-host role: roles/compute.networkUser module.service-project.google_project_iam_member.shared_vpc_host_robots["roles/container.hostServiceAgentUser:container-engine"]: condition: [] - project: my-host-project + project: test-host role: roles/container.hostServiceAgentUser module.service-project.google_project_iam_member.shared_vpc_host_robots["roles/vpcaccess.user:cloudrun"]: condition: [] - project: my-host-project + project: test-host role: roles/vpcaccess.user counts: From aec7fc87c2a1a5d4b4a69aaee00f7d85f7918dee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Niesiob=C4=99dzki?= Date: Sat, 4 Nov 2023 07:31:33 +0000 Subject: [PATCH 17/29] Trim down inventories for Cloud SQL --- .../cloudsql_instance/examples/insights.yaml | 16 ------- .../cloudsql_instance/examples/public-ip.yaml | 44 ------------------- .../cloudsql_instance/examples/simple.yaml | 17 ------- 3 files changed, 77 deletions(-) diff --git a/tests/modules/cloudsql_instance/examples/insights.yaml b/tests/modules/cloudsql_instance/examples/insights.yaml index 1c54188352..84a4245ddf 100644 --- a/tests/modules/cloudsql_instance/examples/insights.yaml +++ b/tests/modules/cloudsql_instance/examples/insights.yaml @@ -20,18 +20,10 @@ values: region: europe-west1 settings: - activation_policy: ALWAYS - active_directory_config: [] - advanced_machine_features: [] availability_type: ZONAL - collation: null - data_cache_config: [] - database_flags: [] deletion_protection_enabled: true - deny_maintenance_period: [] disk_autoresize: true - disk_autoresize_limit: 0 disk_type: PD_SSD - edition: null insights_config: - query_insights_enabled: true query_plans_per_minute: 5 @@ -41,17 +33,9 @@ values: ip_configuration: - allocated_ip_range: null authorized_networks: [] - enable_private_path_for_google_cloud_services: null ipv4_enabled: false private_network: projects/xxx/global/networks/aaa - psc_config: [] - require_ssl: null - maintenance_window: [] - password_validation_policy: [] - pricing_plan: PER_USE - sql_server_audit_config: [] tier: db-g1-small - time_zone: null counts: google_sql_database_instance: 1 diff --git a/tests/modules/cloudsql_instance/examples/public-ip.yaml b/tests/modules/cloudsql_instance/examples/public-ip.yaml index 9ba4622033..f3ca86d3a5 100644 --- a/tests/modules/cloudsql_instance/examples/public-ip.yaml +++ b/tests/modules/cloudsql_instance/examples/public-ip.yaml @@ -18,46 +18,19 @@ values: name: db project: project-id region: europe-west1 - restore_backup_context: [] settings: - activation_policy: ALWAYS - active_directory_config: [] - advanced_machine_features: [] availability_type: ZONAL - backup_configuration: - - backup_retention_settings: - - retained_backups: 7 - retention_unit: COUNT - binary_log_enabled: true - enabled: true - location: null - point_in_time_recovery_enabled: null - start_time: '23:00' - transaction_log_retention_days: 7 - collation: null - data_cache_config: [] - database_flags: [] deletion_protection_enabled: true - deny_maintenance_period: [] disk_autoresize: true - disk_autoresize_limit: 0 disk_type: PD_SSD - edition: null insights_config: [] ip_configuration: - allocated_ip_range: null authorized_networks: [] - enable_private_path_for_google_cloud_services: null ipv4_enabled: true private_network: projects/xxx/global/networks/aaa - psc_config: [] - require_ssl: null - maintenance_window: [] - password_validation_policy: [] - pricing_plan: PER_USE - sql_server_audit_config: [] tier: db-g1-small - time_zone: null module.db.google_sql_database_instance.replicas["replica1"]: database_version: MYSQL_8_0 master_instance_name: db @@ -66,34 +39,17 @@ values: region: europe-west3 settings: - activation_policy: ALWAYS - active_directory_config: [] - advanced_machine_features: [] availability_type: ZONAL - collation: null - data_cache_config: [] - database_flags: [] deletion_protection_enabled: true - deny_maintenance_period: [] disk_autoresize: true - disk_autoresize_limit: 0 disk_type: PD_SSD - edition: null insights_config: [] ip_configuration: - allocated_ip_range: null authorized_networks: [] - enable_private_path_for_google_cloud_services: null ipv4_enabled: true - psc_config: [] private_network: projects/xxx/global/networks/aaa - require_ssl: null - maintenance_window: [] - password_validation_policy: [] - pricing_plan: PER_USE - sql_server_audit_config: [] tier: db-g1-small - time_zone: null - timeouts: null counts: google_sql_database_instance: 2 diff --git a/tests/modules/cloudsql_instance/examples/simple.yaml b/tests/modules/cloudsql_instance/examples/simple.yaml index d4c0558d9c..fdc663e219 100644 --- a/tests/modules/cloudsql_instance/examples/simple.yaml +++ b/tests/modules/cloudsql_instance/examples/simple.yaml @@ -14,39 +14,22 @@ values: module.db.google_sql_database_instance.primary: - clone: [] database_version: POSTGRES_13 name: db project: my-db-project region: europe-west1 settings: - activation_policy: ALWAYS - active_directory_config: [] - advanced_machine_features: [] availability_type: ZONAL - collation: null - data_cache_config: [] - database_flags: [] deletion_protection_enabled: true - deny_maintenance_period: [] disk_autoresize: true - disk_autoresize_limit: 0 disk_type: PD_SSD - edition: null insights_config: [] ip_configuration: - allocated_ip_range: null authorized_networks: [] - enable_private_path_for_google_cloud_services: null ipv4_enabled: false - psc_config: [] - require_ssl: null - maintenance_window: [] - password_validation_policy: [] - pricing_plan: PER_USE - sql_server_audit_config: [] tier: db-g1-small - time_zone: null counts: google_sql_database_instance: 1 From 0f502a8cfb3c3fd128f71e553aa32961b5ccae75 Mon Sep 17 00:00:00 2001 From: Teodelas Date: Mon, 6 Nov 2023 03:56:03 -0500 Subject: [PATCH 18/29] Fix modules to support new Apigee X environment types (#1841) * Update main.tf * Update variables.tf * Update main.tf Updated environment members to be alphabetical order * fixed linting and terraform fmt * removed venv * removed venv directory --------- Co-authored-by: Teo De Las Heras --- .gitignore | 2 ++ modules/apigee/README.md | 9 ++++----- modules/apigee/main.tf | 9 +++++---- modules/apigee/variables.tf | 1 + 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index cbf110dd29..a4e6b621fd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +venv/* +*/venv/* **/.terraform **/terraform.tfstate* **/terraform.tfvars diff --git a/modules/apigee/README.md b/modules/apigee/README.md index 5a05ecb353..24c6f4166a 100644 --- a/modules/apigee/README.md +++ b/modules/apigee/README.md @@ -354,19 +354,18 @@ module "apigee" { } # tftest modules=1 resources=10 ``` - ## Variables | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [project_id](variables.tf#L125) | Project ID. | string | ✓ | | +| [project_id](variables.tf#L126) | 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#L72) | Instances ([REGION] => [INSTANCE]). | map(object({…})) | | {} | -| [organization](variables.tf#L97) | 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 be571a8ae2..4db47ee0fd 100644 --- a/modules/apigee/main.tf +++ b/modules/apigee/main.tf @@ -40,11 +40,11 @@ resource "google_apigee_envgroup" "envgroups" { resource "google_apigee_environment" "environments" { for_each = var.environments - name = each.key - display_name = each.value.display_name - description = each.value.description - deployment_type = each.value.deployment_type api_proxy_type = each.value.api_proxy_type + deployment_type = each.value.deployment_type + description = each.value.description + display_name = each.value.display_name + name = each.key dynamic "node_config" { for_each = try(each.value.node_config, null) != null ? [""] : [] content { @@ -53,6 +53,7 @@ resource "google_apigee_environment" "environments" { } } org_id = local.org_id + type = each.value.type lifecycle { ignore_changes = [ node_config["current_aggregate_node_count"] diff --git a/modules/apigee/variables.tf b/modules/apigee/variables.tf index 7ec2cc2d64..027ad05e47 100644 --- a/modules/apigee/variables.tf +++ b/modules/apigee/variables.tf @@ -50,6 +50,7 @@ variable "environments" { description = optional(string, "Terraform-managed") 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) From 2731a3dc7c9edf9efdf6a1c87953d7615b5bbf1d Mon Sep 17 00:00:00 2001 From: Ludo Date: Mon, 6 Nov 2023 10:03:40 +0100 Subject: [PATCH 19/29] update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 67c75dd857..609382f2c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,6 +56,10 @@ All notable changes to this project will be documented in this file. ### MODULES +- [[#1841](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1841)] Fix modules to support new Apigee X environment types ([Teodelas](https://github.com/Teodelas)) +- [[#1842](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1842)] Bump provider version to 5.4.0 ([wiktorn](https://github.com/wiktorn)) +- [[#1823](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1823)] Add end-to-end tests for project module ([wiktorn](https://github.com/wiktorn)) +- [[#1837](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1837)] Added envoy as SNI dynamic forward proxy to cloud-config-container ([apichick](https://github.com/apichick)) - [[#1839](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1839)] Added create_before_destroy = true for self-managed certificates ([apichick](https://github.com/apichick)) - [[#1833](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1833)] Net VPC Peering: added stack_type field ([cmalpe](https://github.com/cmalpe)) - [[#1826](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1826)] Add public_access_prevention field to GCS module ([devuonocar](https://github.com/devuonocar)) From 0f91a964da3a41ba20820bb6e802c420f869c933 Mon Sep 17 00:00:00 2001 From: apichick Date: Tue, 7 Nov 2023 08:11:23 +0100 Subject: [PATCH 20/29] Added back sink iam flag as module users might not have access to the sink destination and the role might need to be granted somewhere else --- modules/folder/README.md | 12 ++++++------ modules/folder/logging.tf | 2 +- modules/folder/variables.tf | 1 + modules/organization/README.md | 18 +++++++++--------- modules/organization/logging.tf | 2 +- modules/organization/variables.tf | 1 + 6 files changed, 19 insertions(+), 17 deletions(-) diff --git a/modules/folder/README.md b/modules/folder/README.md index 2ba7e9107a..8c75cadd5e 100644 --- a/modules/folder/README.md +++ b/modules/folder/README.md @@ -295,12 +295,12 @@ module "folder" { | [id](variables.tf#L83) | Folder ID in case you use folder_create=false. | string | | null | | [logging_data_access](variables.tf#L89) | 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#L104) | Logging exclusions for this folder in the form {NAME -> FILTER}. | map(string) | | {} | -| [logging_sinks](variables.tf#L111) | Logging sinks to create for the folder. | map(object({…})) | | {} | -| [name](variables.tf#L141) | Folder name. | string | | null | -| [org_policies](variables.tf#L147) | Organization policies applied to this folder keyed by policy name. | map(object({…})) | | {} | -| [org_policies_data_path](variables.tf#L174) | Path containing org policies in YAML format. | string | | null | -| [parent](variables.tf#L180) | Parent in folders/folder_id or organizations/org_id format. | string | | null | -| [tag_bindings](variables.tf#L190) | Tag bindings for this folder, in key => tag value id format. | map(string) | | null | +| [logging_sinks](variables.tf#L111) | Logging sinks to create for the folder. | map(object({…})) | | {} | +| [name](variables.tf#L142) | Folder name. | string | | null | +| [org_policies](variables.tf#L148) | Organization policies applied to this folder keyed by policy name. | map(object({…})) | | {} | +| [org_policies_data_path](variables.tf#L175) | Path containing org policies in YAML format. | string | | null | +| [parent](variables.tf#L181) | Parent in folders/folder_id or organizations/org_id format. | string | | null | +| [tag_bindings](variables.tf#L191) | Tag bindings for this folder, in key => tag value id format. | map(string) | | null | ## Outputs diff --git a/modules/folder/logging.tf b/modules/folder/logging.tf index 8000a02145..033113ff2e 100644 --- a/modules/folder/logging.tf +++ b/modules/folder/logging.tf @@ -22,7 +22,7 @@ locals { type => { for name, sink in var.logging_sinks : name => sink - if sink.type == type + if sink.iam == true && sink.type == type } } } diff --git a/modules/folder/variables.tf b/modules/folder/variables.tf index 1c55168187..91e8e11e81 100644 --- a/modules/folder/variables.tf +++ b/modules/folder/variables.tf @@ -117,6 +117,7 @@ variable "logging_sinks" { disabled = optional(bool, false) exclusions = optional(map(string), {}) filter = string + iam = optional(bool, true) include_children = optional(bool, true) type = string })) diff --git a/modules/organization/README.md b/modules/organization/README.md index 86df8ab3ba..b760f03626 100644 --- a/modules/organization/README.md +++ b/modules/organization/README.md @@ -456,7 +456,7 @@ module "org" { | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [organization_id](variables.tf#L211) | Organization id in organizations/nnnnnn format. | string | ✓ | | +| [organization_id](variables.tf#L212) | 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)) | | {} | | [firewall_policy](variables.tf#L31) | Hierarchical firewall policies to associate to the organization. | object({…}) | | null | @@ -466,14 +466,14 @@ module "org" { | [iam_bindings_additive](variables.tf#L69) | Individual additive IAM bindings. Keys are arbitrary. | map(object({…})) | | {} | | [logging_data_access](variables.tf#L84) | 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#L99) | Logging exclusions for this organization in the form {NAME -> FILTER}. | map(string) | | {} | -| [logging_sinks](variables.tf#L106) | Logging sinks to create for the organization. | map(object({…})) | | {} | -| [network_tags](variables.tf#L136) | 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 organization keyed by policy name. | map(object({…})) | | {} | -| [org_policies_data_path](variables.tf#L185) | Path containing org policies in YAML format. | string | | null | -| [org_policy_custom_constraints](variables.tf#L191) | Organization policy custom constraints keyed by constraint name. | map(object({…})) | | {} | -| [org_policy_custom_constraints_data_path](variables.tf#L205) | Path containing org policy custom constraints in YAML format. | string | | null | -| [tag_bindings](variables.tf#L220) | Tag bindings for this organization, in key => tag value id format. | map(string) | | null | -| [tags](variables.tf#L226) | 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_sinks](variables.tf#L106) | Logging sinks to create for the organization. | map(object({…})) | | {} | +| [network_tags](variables.tf#L137) | 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#L159) | Organization policies applied to this organization keyed by policy name. | map(object({…})) | | {} | +| [org_policies_data_path](variables.tf#L186) | Path containing org policies in YAML format. | string | | null | +| [org_policy_custom_constraints](variables.tf#L192) | Organization policy custom constraints keyed by constraint name. | map(object({…})) | | {} | +| [org_policy_custom_constraints_data_path](variables.tf#L206) | Path containing org policy custom constraints in YAML format. | string | | null | +| [tag_bindings](variables.tf#L221) | Tag bindings for this organization, in key => tag value id format. | map(string) | | null | +| [tags](variables.tf#L227) | 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/logging.tf b/modules/organization/logging.tf index 7719c0fb62..7f0665e3ab 100644 --- a/modules/organization/logging.tf +++ b/modules/organization/logging.tf @@ -21,7 +21,7 @@ locals { for type in ["bigquery", "logging", "pubsub", "storage"] : type => { for name, sink in var.logging_sinks : - name => sink if sink.type == type + name => sink if sink.iam && sink.type == type } } } diff --git a/modules/organization/variables.tf b/modules/organization/variables.tf index c9899e2e1d..f664deaef1 100644 --- a/modules/organization/variables.tf +++ b/modules/organization/variables.tf @@ -112,6 +112,7 @@ variable "logging_sinks" { disabled = optional(bool, false) exclusions = optional(map(string), {}) filter = string + iam = optional(bool, true) include_children = optional(bool, true) type = string })) From 9068bd7729fad0af0d9b2080523ac98c1c050085 Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Wed, 8 Nov 2023 09:20:16 +0100 Subject: [PATCH 21/29] Update README.md --- modules/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/README.md b/modules/README.md index 03c5cf65bc..cefc5e5592 100644 --- a/modules/README.md +++ b/modules/README.md @@ -21,7 +21,7 @@ These modules are used in the examples included in this repository. If you are u ```terraform module "project" { - source = "github.com/GoogleCloudPlatform/cloud-foundation-fabric//modules/project?ref=v13.0.0" + source = "github.com/GoogleCloudPlatform/cloud-foundation-fabric//modules/project?ref=v13.0.0&depth=1" name = "my-project" billing_account = "123456-123456-123456" parent = "organizations/123456" From c7bef582e816f836bf96bb9db24a7a65f7bb2b54 Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Wed, 8 Nov 2023 11:27:44 +0100 Subject: [PATCH 22/29] add support for IAM to vpc sc module (#1846) --- modules/vpc-sc/README.md | 29 +++++++++++++++++--- modules/vpc-sc/iam.tf | 54 +++++++++++++++++++++++++++++++++++++ modules/vpc-sc/variables.tf | 36 +++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 modules/vpc-sc/iam.tf diff --git a/modules/vpc-sc/README.md b/modules/vpc-sc/README.md index 91d90d466d..ee0d63a30f 100644 --- a/modules/vpc-sc/README.md +++ b/modules/vpc-sc/README.md @@ -34,6 +34,8 @@ module "test" { # tftest modules=1 resources=1 inventory=access-policy.yaml ``` +#### Scoped policy + If you need the module to create a scoped policy for you, specify 'scopes' of the policy in the `access_policy_create` variable: ```hcl @@ -49,6 +51,23 @@ module "test" { # tftest modules=1 resources=1 inventory=scoped-access-policy.yaml ``` +#### Access policy IAM + +The usual IAM interface is also implemented here, and can be used with service accounts or user principals: + +```hcl +module "test" { + source = "./fabric/modules/vpc-sc" + access_policy = "12345678" + iam = { + "roles/accesscontextmanager.policyAdmin" = [ + "user:foo@example.org" + ] + } +} +# tftest modules=1 resources=1 +``` + ### Access levels As highlighted above, the `access_levels` type replicates the underlying resource structure. @@ -190,6 +209,7 @@ module "test" { | name | description | resources | |---|---|---| | [access-levels.tf](./access-levels.tf) | Access level resources. | google_access_context_manager_access_level | +| [iam.tf](./iam.tf) | IAM bindings | google_access_context_manager_access_policy_iam_binding · google_access_context_manager_access_policy_iam_member | | [main.tf](./main.tf) | Module-level locals and resources. | google_access_context_manager_access_policy | | [outputs.tf](./outputs.tf) | Module outputs. | | | [service-perimeters-bridge.tf](./service-perimeters-bridge.tf) | Bridge service perimeter resources. | google_access_context_manager_service_perimeter | @@ -205,9 +225,12 @@ module "test" { | [access_levels](variables.tf#L17) | Access level definitions. | map(object({…})) | | {} | | [access_policy_create](variables.tf#L61) | Access Policy configuration, fill in to create. Parent is in 'organizations/123456' format, scopes are in 'folders/456789' or 'projects/project_id' format. | object({…}) | | null | | [egress_policies](variables.tf#L71) | Egress policy definitions that can be referenced in perimeters. | map(object({…})) | | {} | -| [ingress_policies](variables.tf#L102) | Ingress policy definitions that can be referenced in perimeters. | map(object({…})) | | {} | -| [service_perimeters_bridge](variables.tf#L134) | Bridge service perimeters. | map(object({…})) | | {} | -| [service_perimeters_regular](variables.tf#L144) | Regular service perimeters. | map(object({…})) | | {} | +| [iam](variables.tf#L102) | IAM bindings in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | +| [iam_bindings](variables.tf#L108) | Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary. | map(object({…})) | | {} | +| [iam_bindings_additive](variables.tf#L123) | Individual additive IAM bindings. Keys are arbitrary. | map(object({…})) | | {} | +| [ingress_policies](variables.tf#L138) | Ingress policy definitions that can be referenced in perimeters. | map(object({…})) | | {} | +| [service_perimeters_bridge](variables.tf#L170) | Bridge service perimeters. | map(object({…})) | | {} | +| [service_perimeters_regular](variables.tf#L180) | Regular service perimeters. | map(object({…})) | | {} | ## Outputs diff --git a/modules/vpc-sc/iam.tf b/modules/vpc-sc/iam.tf new file mode 100644 index 0000000000..9b475b68fd --- /dev/null +++ b/modules/vpc-sc/iam.tf @@ -0,0 +1,54 @@ +/** + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +# tfdoc:file:description IAM bindings + +resource "google_access_context_manager_access_policy_iam_binding" "authoritative" { + for_each = var.iam + name = local.access_policy + role = each.key + members = each.value +} + +resource "google_access_context_manager_access_policy_iam_binding" "bindings" { + for_each = var.iam_bindings + name = local.access_policy + role = each.value.role + members = each.value.members + dynamic "condition" { + for_each = each.value.condition == null ? [] : [""] + content { + expression = each.value.condition.expression + title = each.value.condition.title + description = each.value.condition.description + } + } +} + +resource "google_access_context_manager_access_policy_iam_member" "bindings" { + for_each = var.iam_bindings_additive + name = local.access_policy + role = each.value.role + member = each.value.member + dynamic "condition" { + for_each = each.value.condition == null ? [] : [""] + content { + expression = each.value.condition.expression + title = each.value.condition.title + description = each.value.condition.description + } + } +} diff --git a/modules/vpc-sc/variables.tf b/modules/vpc-sc/variables.tf index 8ce4b41eb1..008d7ae215 100644 --- a/modules/vpc-sc/variables.tf +++ b/modules/vpc-sc/variables.tf @@ -99,6 +99,42 @@ variable "egress_policies" { } } +variable "iam" { + description = "IAM bindings in {ROLE => [MEMBERS]} format." + type = map(list(string)) + default = {} +} + +variable "iam_bindings" { + description = "Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary." + type = map(object({ + members = list(string) + role = string + condition = optional(object({ + expression = string + title = string + description = optional(string) + })) + })) + nullable = false + default = {} +} + +variable "iam_bindings_additive" { + description = "Individual additive IAM bindings. Keys are arbitrary." + type = map(object({ + member = string + role = string + condition = optional(object({ + expression = string + title = string + description = optional(string) + })) + })) + nullable = false + default = {} +} + variable "ingress_policies" { description = "Ingress policy definitions that can be referenced in perimeters." type = map(object({ From fca89b57ed635ae667683eb35e958bef166ba14d Mon Sep 17 00:00:00 2001 From: Artur Pacan Date: Wed, 8 Nov 2023 11:49:15 +0000 Subject: [PATCH 23/29] Fix validation and dynamic block for optional gpu_driver --- modules/gke-nodepool/main.tf | 5 +---- modules/gke-nodepool/variables.tf | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/modules/gke-nodepool/main.tf b/modules/gke-nodepool/main.tf index 40f7fcf31c..20d4fcad16 100644 --- a/modules/gke-nodepool/main.tf +++ b/modules/gke-nodepool/main.tf @@ -168,10 +168,7 @@ resource "google_container_node_pool" "nodepool" { gpu_partition_size = var.node_config.guest_accelerator.gpu_driver == null ? null : var.node_config.guest_accelerator.gpu_driver.partition_size dynamic "gpu_sharing_config" { - for_each = lookup( - lookup(var.node_config.guest_accelerator, "gpu_driver", {}), - "max_shared_clients_per_gpu" - ) != null ? [""] : [] + for_each = try(var.node_config.guest_accelerator.gpu_driver.max_shared_clients_per_gpu, null) != null ? [""] : [] content { gpu_sharing_strategy = var.node_config.guest_accelerator.gpu_driver.max_shared_clients_per_gpu != null ? "TIME_SHARING" : null max_shared_clients_per_gpu = var.node_config.guest_accelerator.gpu_driver.max_shared_clients_per_gpu diff --git a/modules/gke-nodepool/variables.tf b/modules/gke-nodepool/variables.tf index 17cfd88c5a..caa735884c 100644 --- a/modules/gke-nodepool/variables.tf +++ b/modules/gke-nodepool/variables.tf @@ -100,7 +100,7 @@ variable "node_config" { validation { condition = ( alltrue([ - for k, v in var.node_config.guest_accelerator[*].gpu_driver : contains([ + for k, v in try(var.node_config.guest_accelerator[0].gpu_driver, {}) : contains([ "GPU_DRIVER_VERSION_UNSPECIFIED", "INSTALLATION_DISABLED", "DEFAULT", "LATEST" ], v.version) From 03937f2b6ed964421b7e1252f344cec90fc4bb8d Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Thu, 9 Nov 2023 09:29:46 +0100 Subject: [PATCH 24/29] Support multilevel data and allow overriding project id in project factory (#1851) --- .../factories/project-factory/README.md | 26 ++- .../factories/project-factory/factory.tf | 1 + blueprints/factories/project-factory/main.tf | 2 +- .../project_factory/examples/example.yaml | 169 +++++++++++------- 4 files changed, 129 insertions(+), 69 deletions(-) diff --git a/blueprints/factories/project-factory/README.md b/blueprints/factories/project-factory/README.md index 2e67158277..3988a20607 100644 --- a/blueprints/factories/project-factory/README.md +++ b/blueprints/factories/project-factory/README.md @@ -29,6 +29,10 @@ In addition to the yaml files describing projects, the project factory accepts t Some examples on where to use each of the three sets are provided below. +## Overriding project id + +By default, the project id is derived from the file path relative to the data root. Path slashes are replaced with dashes to allow for multilevel data folders (e.g. `app01/fe.yaml`, `app02/fe.yaml`, etc.). The project id can be overridden by specifying a custom `name` attribute in the yaml file. Refer to the example below for details. + ## Example ```hcl @@ -57,7 +61,7 @@ module "project-factory" { # location where the yaml files are read from factory_data_path = "data" } -# tftest modules=7 resources=26 files=prj-app-1,prj-app-2,prj-app-3 inventory=example.yaml +# tftest modules=8 resources=32 files=app01,app02-be,app03-be,app03-fe inventory=example.yaml ``` ```yaml @@ -80,12 +84,12 @@ service_accounts: app-1-fe: display_name: "Test app 1 frontend." -# tftest-file id=prj-app-1 path=data/prj-app-1.yaml +# tftest-file id=app01 path=data/app01.yaml ``` ```yaml labels: - app: app-2 + app: app02 team: foo parent: folders/12345678 service_accounts: @@ -97,17 +101,29 @@ services: shared_vpc_service_config: host_project: foo-host -# tftest-file id=prj-app-2 path=data/prj-app-2.yaml +# tftest-file id=app02-be path=data/app02/be.yaml ``` ```yaml +name: app03-be-0 parent: folders/12345678 services: - run.googleapis.com - storage.googleapis.com -# tftest-file id=prj-app-3 path=data/prj-app-3.yaml +# tftest-file id=app03-be path=data/app03/be.yaml ``` + +```yaml +name: app03-fe-0 +parent: folders/12345678 +services: +- run.googleapis.com +- storage.googleapis.com + +# tftest-file id=app03-fe path=data/app03/fe.yaml +``` + ## Variables diff --git a/blueprints/factories/project-factory/factory.tf b/blueprints/factories/project-factory/factory.tf index eabb551ad1..3a4295b33f 100644 --- a/blueprints/factories/project-factory/factory.tf +++ b/blueprints/factories/project-factory/factory.tf @@ -44,6 +44,7 @@ locals { try(v.metric_scopes, null), var.data_defaults.metric_scopes ) + name = try(v.name, replace(k, "/", "-")) org_policies = try(v.org_policies, {}) parent = coalesce( var.data_overrides.parent, diff --git a/blueprints/factories/project-factory/main.tf b/blueprints/factories/project-factory/main.tf index 81f1d31652..a23ee5ba76 100644 --- a/blueprints/factories/project-factory/main.tf +++ b/blueprints/factories/project-factory/main.tf @@ -18,7 +18,7 @@ module "projects" { source = "../../../modules/project" for_each = local.projects billing_account = each.value.billing_account - name = each.key + name = each.value.name parent = try(each.value.parent, null) prefix = each.value.prefix auto_create_network = try(each.value.auto_create_network, false) diff --git a/tests/blueprints/factories/project_factory/examples/example.yaml b/tests/blueprints/factories/project_factory/examples/example.yaml index 71391a526a..9e4481b41d 100644 --- a/tests/blueprints/factories/project_factory/examples/example.yaml +++ b/tests/blueprints/factories/project_factory/examples/example.yaml @@ -13,21 +13,21 @@ # limitations under the License. values: - module.project-factory.module.projects["prj-app-1"].data.google_storage_project_service_account.gcs_sa[0]: - project: test-pf-prj-app-1 + module.project-factory.module.projects["app01"].data.google_storage_project_service_account.gcs_sa[0]: + project: test-pf-app01 user_project: null - module.project-factory.module.projects["prj-app-1"].google_essential_contacts_contact.contact["admin@example.com"]: + module.project-factory.module.projects["app01"].google_essential_contacts_contact.contact["admin@example.com"]: email: admin@example.com language_tag: en notification_category_subscriptions: - ALL - parent: projects/test-pf-prj-app-1 + parent: projects/test-pf-app01 timeouts: null - ? module.project-factory.module.projects["prj-app-1"].google_kms_crypto_key_iam_member.service_identity_cmek["compute.projects/kms-central-prj/locations/europe-west3/keyRings/my-keyring/cryptoKeys/europe3-gce"] + ? module.project-factory.module.projects["app01"].google_kms_crypto_key_iam_member.service_identity_cmek["compute.projects/kms-central-prj/locations/europe-west3/keyRings/my-keyring/cryptoKeys/europe3-gce"] : condition: [] crypto_key_id: projects/kms-central-prj/locations/europe-west3/keyRings/my-keyring/cryptoKeys/europe3-gce role: roles/cloudkms.cryptoKeyEncrypterDecrypter - module.project-factory.module.projects["prj-app-1"].google_project.project[0]: + module.project-factory.module.projects["app01"].google_project.project[0]: auto_create_network: false billing_account: 012345-67890A-BCDEF0 effective_labels: @@ -39,104 +39,104 @@ values: app: app-1 environment: test team: foo - name: test-pf-prj-app-1 + name: test-pf-app01 org_id: null - project_id: test-pf-prj-app-1 + project_id: test-pf-app01 skip_delete: false terraform_labels: app: app-1 environment: test team: foo timeouts: null - module.project-factory.module.projects["prj-app-1"].google_project_service.project_services["container.googleapis.com"]: + module.project-factory.module.projects["app01"].google_project_service.project_services["container.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: test-pf-prj-app-1 + project: test-pf-app01 service: container.googleapis.com timeouts: null - module.project-factory.module.projects["prj-app-1"].google_project_service.project_services["stackdriver.googleapis.com"]: + module.project-factory.module.projects["app01"].google_project_service.project_services["stackdriver.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: test-pf-prj-app-1 + project: test-pf-app01 service: stackdriver.googleapis.com timeouts: null - module.project-factory.module.projects["prj-app-1"].google_project_service.project_services["storage.googleapis.com"]: + module.project-factory.module.projects["app01"].google_project_service.project_services["storage.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: test-pf-prj-app-1 + project: test-pf-app01 service: storage.googleapis.com timeouts: null - module.project-factory.module.projects["prj-app-2"].data.google_storage_project_service_account.gcs_sa[0]: - project: test-pf-prj-app-2 + module.project-factory.module.projects["app02/be"].data.google_storage_project_service_account.gcs_sa[0]: + project: test-pf-app02-be user_project: null - module.project-factory.module.projects["prj-app-2"].google_compute_shared_vpc_service_project.shared_vpc_service[0]: + module.project-factory.module.projects["app02/be"].google_compute_shared_vpc_service_project.shared_vpc_service[0]: deletion_policy: null host_project: foo-host - service_project: test-pf-prj-app-2 + service_project: test-pf-app02-be timeouts: null - module.project-factory.module.projects["prj-app-2"].google_essential_contacts_contact.contact["admin@example.com"]: + module.project-factory.module.projects["app02/be"].google_essential_contacts_contact.contact["admin@example.com"]: email: admin@example.com language_tag: en notification_category_subscriptions: - ALL - parent: projects/test-pf-prj-app-2 + parent: projects/test-pf-app02-be timeouts: null - module.project-factory.module.projects["prj-app-2"].google_project.project[0]: + module.project-factory.module.projects["app02/be"].google_project.project[0]: auto_create_network: false billing_account: 012345-67890A-ABCDEF effective_labels: - app: app-2 + app: app02 environment: test team: foo folder_id: '12345678' labels: - app: app-2 + app: app02 environment: test team: foo - name: test-pf-prj-app-2 + name: test-pf-app02-be org_id: null - project_id: test-pf-prj-app-2 + project_id: test-pf-app02-be skip_delete: false terraform_labels: - app: app-2 + app: app02 environment: test team: foo timeouts: null - module.project-factory.module.projects["prj-app-2"].google_project_service.project_services["compute.googleapis.com"]: + module.project-factory.module.projects["app02/be"].google_project_service.project_services["compute.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: test-pf-prj-app-2 + project: test-pf-app02-be service: compute.googleapis.com timeouts: null - module.project-factory.module.projects["prj-app-2"].google_project_service.project_services["run.googleapis.com"]: + module.project-factory.module.projects["app02/be"].google_project_service.project_services["run.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: test-pf-prj-app-2 + project: test-pf-app02-be service: run.googleapis.com timeouts: null - module.project-factory.module.projects["prj-app-2"].google_project_service.project_services["stackdriver.googleapis.com"]: + module.project-factory.module.projects["app02/be"].google_project_service.project_services["stackdriver.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: test-pf-prj-app-2 + project: test-pf-app02-be service: stackdriver.googleapis.com timeouts: null - module.project-factory.module.projects["prj-app-2"].google_project_service.project_services["storage.googleapis.com"]: + module.project-factory.module.projects["app02/be"].google_project_service.project_services["storage.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: test-pf-prj-app-2 + project: test-pf-app02-be service: storage.googleapis.com timeouts: null - module.project-factory.module.projects["prj-app-3"].data.google_storage_project_service_account.gcs_sa[0]: - project: test-pf-prj-app-3 + module.project-factory.module.projects["app03/be"].data.google_storage_project_service_account.gcs_sa[0]: + project: test-pf-app03-be-0 user_project: null - module.project-factory.module.projects["prj-app-3"].google_essential_contacts_contact.contact["admin@example.com"]: + module.project-factory.module.projects["app03/be"].google_essential_contacts_contact.contact["admin@example.com"]: email: admin@example.com language_tag: en notification_category_subscriptions: - ALL - parent: projects/test-pf-prj-app-3 + parent: projects/test-pf-app03-be-0 timeouts: null - module.project-factory.module.projects["prj-app-3"].google_project.project[0]: + module.project-factory.module.projects["app03/be"].google_project.project[0]: auto_create_network: false billing_account: 012345-67890A-ABCDEF effective_labels: @@ -144,71 +144,114 @@ values: folder_id: '12345678' labels: environment: test - name: test-pf-prj-app-3 + name: test-pf-app03-be-0 org_id: null - project_id: test-pf-prj-app-3 + project_id: test-pf-app03-be-0 skip_delete: false terraform_labels: environment: test timeouts: null - module.project-factory.module.projects["prj-app-3"].google_project_service.project_services["run.googleapis.com"]: + module.project-factory.module.projects["app03/be"].google_project_service.project_services["run.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: test-pf-prj-app-3 + project: test-pf-app03-be-0 service: run.googleapis.com timeouts: null - module.project-factory.module.projects["prj-app-3"].google_project_service.project_services["stackdriver.googleapis.com"]: + module.project-factory.module.projects["app03/be"].google_project_service.project_services["stackdriver.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: test-pf-prj-app-3 + project: test-pf-app03-be-0 service: stackdriver.googleapis.com timeouts: null - module.project-factory.module.projects["prj-app-3"].google_project_service.project_services["storage.googleapis.com"]: + module.project-factory.module.projects["app03/be"].google_project_service.project_services["storage.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: test-pf-prj-app-3 + project: test-pf-app03-be-0 service: storage.googleapis.com timeouts: null - ? module.project-factory.module.service-accounts["prj-app-1-app-1-be"].google_project_iam_member.project-roles["test-pf-prj-app-1-roles/logging.logWriter"] + module.project-factory.module.projects["app03/fe"].data.google_storage_project_service_account.gcs_sa[0]: + project: test-pf-app03-fe-0 + user_project: null + module.project-factory.module.projects["app03/fe"].google_essential_contacts_contact.contact["admin@example.com"]: + email: admin@example.com + language_tag: en + notification_category_subscriptions: + - ALL + parent: projects/test-pf-app03-fe-0 + timeouts: null + module.project-factory.module.projects["app03/fe"].google_project.project[0]: + auto_create_network: false + billing_account: 012345-67890A-ABCDEF + effective_labels: + environment: test + folder_id: '12345678' + labels: + environment: test + name: test-pf-app03-fe-0 + org_id: null + project_id: test-pf-app03-fe-0 + skip_delete: false + terraform_labels: + environment: test + timeouts: null + module.project-factory.module.projects["app03/fe"].google_project_service.project_services["run.googleapis.com"]: + disable_dependent_services: false + disable_on_destroy: false + project: test-pf-app03-fe-0 + service: run.googleapis.com + timeouts: null + module.project-factory.module.projects["app03/fe"].google_project_service.project_services["stackdriver.googleapis.com"]: + disable_dependent_services: false + disable_on_destroy: false + project: test-pf-app03-fe-0 + service: stackdriver.googleapis.com + timeouts: null + module.project-factory.module.projects["app03/fe"].google_project_service.project_services["storage.googleapis.com"]: + disable_dependent_services: false + disable_on_destroy: false + project: test-pf-app03-fe-0 + service: storage.googleapis.com + timeouts: null + ? module.project-factory.module.service-accounts["app01-app-1-be"].google_project_iam_member.project-roles["test-pf-app01-roles/logging.logWriter"] : condition: [] - project: test-pf-prj-app-1 + project: test-pf-app01 role: roles/logging.logWriter - ? module.project-factory.module.service-accounts["prj-app-1-app-1-be"].google_project_iam_member.project-roles["test-pf-prj-app-1-roles/monitoring.metricWriter"] + ? module.project-factory.module.service-accounts["app01-app-1-be"].google_project_iam_member.project-roles["test-pf-app01-roles/monitoring.metricWriter"] : condition: [] - project: test-pf-prj-app-1 + project: test-pf-app01 role: roles/monitoring.metricWriter - module.project-factory.module.service-accounts["prj-app-1-app-1-be"].google_service_account.service_account[0]: + module.project-factory.module.service-accounts["app01-app-1-be"].google_service_account.service_account[0]: account_id: app-1-be description: null disabled: false display_name: null - project: test-pf-prj-app-1 + project: test-pf-app01 timeouts: null - module.project-factory.module.service-accounts["prj-app-1-app-1-fe"].google_service_account.service_account[0]: + module.project-factory.module.service-accounts["app01-app-1-fe"].google_service_account.service_account[0]: account_id: app-1-fe description: null disabled: false display_name: Test app 1 frontend. - project: test-pf-prj-app-1 + project: test-pf-app01 timeouts: null - module.project-factory.module.service-accounts["prj-app-2-app-2-be"].google_service_account.service_account[0]: + module.project-factory.module.service-accounts["app02/be-app-2-be"].google_service_account.service_account[0]: account_id: app-2-be description: null disabled: false display_name: null - project: test-pf-prj-app-2 + project: test-pf-app02-be timeouts: null counts: google_compute_shared_vpc_service_project: 1 - google_essential_contacts_contact: 3 + google_essential_contacts_contact: 4 google_kms_crypto_key_iam_member: 1 - google_project: 3 + google_project: 4 google_project_iam_member: 2 - google_project_service: 10 + google_project_service: 13 google_service_account: 3 - google_storage_project_service_account: 3 - modules: 7 - resources: 26 + google_storage_project_service_account: 4 + modules: 8 + resources: 32 outputs: {} From 82c74e4ab6947e0093f9945ae90ab0199cc9da6a Mon Sep 17 00:00:00 2001 From: Francesco Spinelli <90899331+Francesco-cloud24@users.noreply.github.com> Date: Thu, 9 Nov 2023 16:48:29 +0100 Subject: [PATCH 25/29] Dataproc module bug fix (#1848) * bug fix * bug fix * fix dinamic for_each --------- Co-authored-by: Francesco Spinelli --- .../factories/project-factory/README.md | 26 +-- .../factories/project-factory/factory.tf | 1 - blueprints/factories/project-factory/main.tf | 2 +- modules/dataproc/README.md | 2 +- modules/dataproc/main.tf | 10 +- modules/dataproc/variables.tf | 2 +- .../project_factory/examples/example.yaml | 169 +++++++----------- 7 files changed, 76 insertions(+), 136 deletions(-) diff --git a/blueprints/factories/project-factory/README.md b/blueprints/factories/project-factory/README.md index 3988a20607..2e67158277 100644 --- a/blueprints/factories/project-factory/README.md +++ b/blueprints/factories/project-factory/README.md @@ -29,10 +29,6 @@ In addition to the yaml files describing projects, the project factory accepts t Some examples on where to use each of the three sets are provided below. -## Overriding project id - -By default, the project id is derived from the file path relative to the data root. Path slashes are replaced with dashes to allow for multilevel data folders (e.g. `app01/fe.yaml`, `app02/fe.yaml`, etc.). The project id can be overridden by specifying a custom `name` attribute in the yaml file. Refer to the example below for details. - ## Example ```hcl @@ -61,7 +57,7 @@ module "project-factory" { # location where the yaml files are read from factory_data_path = "data" } -# tftest modules=8 resources=32 files=app01,app02-be,app03-be,app03-fe inventory=example.yaml +# tftest modules=7 resources=26 files=prj-app-1,prj-app-2,prj-app-3 inventory=example.yaml ``` ```yaml @@ -84,12 +80,12 @@ service_accounts: app-1-fe: display_name: "Test app 1 frontend." -# tftest-file id=app01 path=data/app01.yaml +# tftest-file id=prj-app-1 path=data/prj-app-1.yaml ``` ```yaml labels: - app: app02 + app: app-2 team: foo parent: folders/12345678 service_accounts: @@ -101,29 +97,17 @@ services: shared_vpc_service_config: host_project: foo-host -# tftest-file id=app02-be path=data/app02/be.yaml +# tftest-file id=prj-app-2 path=data/prj-app-2.yaml ``` ```yaml -name: app03-be-0 parent: folders/12345678 services: - run.googleapis.com - storage.googleapis.com -# tftest-file id=app03-be path=data/app03/be.yaml +# tftest-file id=prj-app-3 path=data/prj-app-3.yaml ``` - -```yaml -name: app03-fe-0 -parent: folders/12345678 -services: -- run.googleapis.com -- storage.googleapis.com - -# tftest-file id=app03-fe path=data/app03/fe.yaml -``` - ## Variables diff --git a/blueprints/factories/project-factory/factory.tf b/blueprints/factories/project-factory/factory.tf index 3a4295b33f..eabb551ad1 100644 --- a/blueprints/factories/project-factory/factory.tf +++ b/blueprints/factories/project-factory/factory.tf @@ -44,7 +44,6 @@ locals { try(v.metric_scopes, null), var.data_defaults.metric_scopes ) - name = try(v.name, replace(k, "/", "-")) org_policies = try(v.org_policies, {}) parent = coalesce( var.data_overrides.parent, diff --git a/blueprints/factories/project-factory/main.tf b/blueprints/factories/project-factory/main.tf index a23ee5ba76..81f1d31652 100644 --- a/blueprints/factories/project-factory/main.tf +++ b/blueprints/factories/project-factory/main.tf @@ -18,7 +18,7 @@ module "projects" { source = "../../../modules/project" for_each = local.projects billing_account = each.value.billing_account - name = each.value.name + name = each.key parent = try(each.value.parent, null) prefix = each.value.prefix auto_create_network = try(each.value.auto_create_network, false) diff --git a/modules/dataproc/README.md b/modules/dataproc/README.md index 5cd220cbaa..f00101345c 100644 --- a/modules/dataproc/README.md +++ b/modules/dataproc/README.md @@ -149,7 +149,7 @@ module "processing-dp-cluster" { | [name](variables.tf#L235) | Cluster name. | string | ✓ | | | [project_id](variables.tf#L250) | Project ID. | string | ✓ | | | [region](variables.tf#L255) | Dataproc region. | string | ✓ | | -| [dataproc_config](variables.tf#L17) | Dataproc cluster config. | object({…}) | | {} | +| [dataproc_config](variables.tf#L17) | Dataproc cluster config. | object({…}) | | {} | | [group_iam](variables.tf#L185) | Authoritative IAM binding for organization groups, in {GROUP_EMAIL => [ROLES]} format. Group emails need to be static. Can be used in combination with the `iam` variable. | map(list(string)) | | {} | | [iam](variables.tf#L192) | IAM bindings in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | | [iam_bindings](variables.tf#L199) | Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary. | map(object({…})) | | {} | diff --git a/modules/dataproc/main.tf b/modules/dataproc/main.tf index 55bef5c70e..f229d7c7ae 100644 --- a/modules/dataproc/main.tf +++ b/modules/dataproc/main.tf @@ -108,8 +108,8 @@ resource "google_dataproc_cluster" "cluster" { dynamic "accelerators" { for_each = var.dataproc_config.cluster_config.worker_config.accelerators == null ? [] : [""] content { - accelerator_type = var.dataproc_config.cluster_config.accelerators.accelerator_type - accelerator_count = var.dataproc_config.cluster_config.accelerators.accelerator_count + accelerator_type = var.dataproc_config.cluster_config.worker_config.accelerators.accelerator_type + accelerator_count = var.dataproc_config.cluster_config.worker_config.accelerators.accelerator_count } } } @@ -185,10 +185,10 @@ resource "google_dataproc_cluster" "cluster" { for_each = var.dataproc_config.cluster_config.dataproc_metric_config == null ? [] : [""] content { dynamic "metrics" { - for_each = var.dataproc_config.cluster_config.dataproc_metric_config.metrics == null ? [] : [""] + for_each = coalesce(var.dataproc_config.cluster_config.dataproc_metric_config.metrics, []) content { - metric_source = var.dataproc_config.cluster_config.dataproc_metric_config.metrics.metric_source - metric_overrides = var.dataproc_config.cluster_config.dataproc_metric_config.metrics.metric_overrides + metric_source = metrics.value.metric_source + metric_overrides = metrics.value.metric_overrides } } } diff --git a/modules/dataproc/variables.tf b/modules/dataproc/variables.tf index 8b77c5b96b..f4170a94f0 100644 --- a/modules/dataproc/variables.tf +++ b/modules/dataproc/variables.tf @@ -128,7 +128,7 @@ variable "dataproc_config" { dataproc_metric_config = optional(object({ metrics = list(object({ metric_source = string - metric_overrides = optional(string) + metric_overrides = optional(list(string)) })) })) metastore_config = optional(object({ diff --git a/tests/blueprints/factories/project_factory/examples/example.yaml b/tests/blueprints/factories/project_factory/examples/example.yaml index 9e4481b41d..71391a526a 100644 --- a/tests/blueprints/factories/project_factory/examples/example.yaml +++ b/tests/blueprints/factories/project_factory/examples/example.yaml @@ -13,21 +13,21 @@ # limitations under the License. values: - module.project-factory.module.projects["app01"].data.google_storage_project_service_account.gcs_sa[0]: - project: test-pf-app01 + module.project-factory.module.projects["prj-app-1"].data.google_storage_project_service_account.gcs_sa[0]: + project: test-pf-prj-app-1 user_project: null - module.project-factory.module.projects["app01"].google_essential_contacts_contact.contact["admin@example.com"]: + module.project-factory.module.projects["prj-app-1"].google_essential_contacts_contact.contact["admin@example.com"]: email: admin@example.com language_tag: en notification_category_subscriptions: - ALL - parent: projects/test-pf-app01 + parent: projects/test-pf-prj-app-1 timeouts: null - ? module.project-factory.module.projects["app01"].google_kms_crypto_key_iam_member.service_identity_cmek["compute.projects/kms-central-prj/locations/europe-west3/keyRings/my-keyring/cryptoKeys/europe3-gce"] + ? module.project-factory.module.projects["prj-app-1"].google_kms_crypto_key_iam_member.service_identity_cmek["compute.projects/kms-central-prj/locations/europe-west3/keyRings/my-keyring/cryptoKeys/europe3-gce"] : condition: [] crypto_key_id: projects/kms-central-prj/locations/europe-west3/keyRings/my-keyring/cryptoKeys/europe3-gce role: roles/cloudkms.cryptoKeyEncrypterDecrypter - module.project-factory.module.projects["app01"].google_project.project[0]: + module.project-factory.module.projects["prj-app-1"].google_project.project[0]: auto_create_network: false billing_account: 012345-67890A-BCDEF0 effective_labels: @@ -39,104 +39,104 @@ values: app: app-1 environment: test team: foo - name: test-pf-app01 + name: test-pf-prj-app-1 org_id: null - project_id: test-pf-app01 + project_id: test-pf-prj-app-1 skip_delete: false terraform_labels: app: app-1 environment: test team: foo timeouts: null - module.project-factory.module.projects["app01"].google_project_service.project_services["container.googleapis.com"]: + module.project-factory.module.projects["prj-app-1"].google_project_service.project_services["container.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: test-pf-app01 + project: test-pf-prj-app-1 service: container.googleapis.com timeouts: null - module.project-factory.module.projects["app01"].google_project_service.project_services["stackdriver.googleapis.com"]: + module.project-factory.module.projects["prj-app-1"].google_project_service.project_services["stackdriver.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: test-pf-app01 + project: test-pf-prj-app-1 service: stackdriver.googleapis.com timeouts: null - module.project-factory.module.projects["app01"].google_project_service.project_services["storage.googleapis.com"]: + module.project-factory.module.projects["prj-app-1"].google_project_service.project_services["storage.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: test-pf-app01 + project: test-pf-prj-app-1 service: storage.googleapis.com timeouts: null - module.project-factory.module.projects["app02/be"].data.google_storage_project_service_account.gcs_sa[0]: - project: test-pf-app02-be + module.project-factory.module.projects["prj-app-2"].data.google_storage_project_service_account.gcs_sa[0]: + project: test-pf-prj-app-2 user_project: null - module.project-factory.module.projects["app02/be"].google_compute_shared_vpc_service_project.shared_vpc_service[0]: + module.project-factory.module.projects["prj-app-2"].google_compute_shared_vpc_service_project.shared_vpc_service[0]: deletion_policy: null host_project: foo-host - service_project: test-pf-app02-be + service_project: test-pf-prj-app-2 timeouts: null - module.project-factory.module.projects["app02/be"].google_essential_contacts_contact.contact["admin@example.com"]: + module.project-factory.module.projects["prj-app-2"].google_essential_contacts_contact.contact["admin@example.com"]: email: admin@example.com language_tag: en notification_category_subscriptions: - ALL - parent: projects/test-pf-app02-be + parent: projects/test-pf-prj-app-2 timeouts: null - module.project-factory.module.projects["app02/be"].google_project.project[0]: + module.project-factory.module.projects["prj-app-2"].google_project.project[0]: auto_create_network: false billing_account: 012345-67890A-ABCDEF effective_labels: - app: app02 + app: app-2 environment: test team: foo folder_id: '12345678' labels: - app: app02 + app: app-2 environment: test team: foo - name: test-pf-app02-be + name: test-pf-prj-app-2 org_id: null - project_id: test-pf-app02-be + project_id: test-pf-prj-app-2 skip_delete: false terraform_labels: - app: app02 + app: app-2 environment: test team: foo timeouts: null - module.project-factory.module.projects["app02/be"].google_project_service.project_services["compute.googleapis.com"]: + module.project-factory.module.projects["prj-app-2"].google_project_service.project_services["compute.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: test-pf-app02-be + project: test-pf-prj-app-2 service: compute.googleapis.com timeouts: null - module.project-factory.module.projects["app02/be"].google_project_service.project_services["run.googleapis.com"]: + module.project-factory.module.projects["prj-app-2"].google_project_service.project_services["run.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: test-pf-app02-be + project: test-pf-prj-app-2 service: run.googleapis.com timeouts: null - module.project-factory.module.projects["app02/be"].google_project_service.project_services["stackdriver.googleapis.com"]: + module.project-factory.module.projects["prj-app-2"].google_project_service.project_services["stackdriver.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: test-pf-app02-be + project: test-pf-prj-app-2 service: stackdriver.googleapis.com timeouts: null - module.project-factory.module.projects["app02/be"].google_project_service.project_services["storage.googleapis.com"]: + module.project-factory.module.projects["prj-app-2"].google_project_service.project_services["storage.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: test-pf-app02-be + project: test-pf-prj-app-2 service: storage.googleapis.com timeouts: null - module.project-factory.module.projects["app03/be"].data.google_storage_project_service_account.gcs_sa[0]: - project: test-pf-app03-be-0 + module.project-factory.module.projects["prj-app-3"].data.google_storage_project_service_account.gcs_sa[0]: + project: test-pf-prj-app-3 user_project: null - module.project-factory.module.projects["app03/be"].google_essential_contacts_contact.contact["admin@example.com"]: + module.project-factory.module.projects["prj-app-3"].google_essential_contacts_contact.contact["admin@example.com"]: email: admin@example.com language_tag: en notification_category_subscriptions: - ALL - parent: projects/test-pf-app03-be-0 + parent: projects/test-pf-prj-app-3 timeouts: null - module.project-factory.module.projects["app03/be"].google_project.project[0]: + module.project-factory.module.projects["prj-app-3"].google_project.project[0]: auto_create_network: false billing_account: 012345-67890A-ABCDEF effective_labels: @@ -144,114 +144,71 @@ values: folder_id: '12345678' labels: environment: test - name: test-pf-app03-be-0 + name: test-pf-prj-app-3 org_id: null - project_id: test-pf-app03-be-0 + project_id: test-pf-prj-app-3 skip_delete: false terraform_labels: environment: test timeouts: null - module.project-factory.module.projects["app03/be"].google_project_service.project_services["run.googleapis.com"]: + module.project-factory.module.projects["prj-app-3"].google_project_service.project_services["run.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: test-pf-app03-be-0 + project: test-pf-prj-app-3 service: run.googleapis.com timeouts: null - module.project-factory.module.projects["app03/be"].google_project_service.project_services["stackdriver.googleapis.com"]: + module.project-factory.module.projects["prj-app-3"].google_project_service.project_services["stackdriver.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: test-pf-app03-be-0 + project: test-pf-prj-app-3 service: stackdriver.googleapis.com timeouts: null - module.project-factory.module.projects["app03/be"].google_project_service.project_services["storage.googleapis.com"]: + module.project-factory.module.projects["prj-app-3"].google_project_service.project_services["storage.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: test-pf-app03-be-0 + project: test-pf-prj-app-3 service: storage.googleapis.com timeouts: null - module.project-factory.module.projects["app03/fe"].data.google_storage_project_service_account.gcs_sa[0]: - project: test-pf-app03-fe-0 - user_project: null - module.project-factory.module.projects["app03/fe"].google_essential_contacts_contact.contact["admin@example.com"]: - email: admin@example.com - language_tag: en - notification_category_subscriptions: - - ALL - parent: projects/test-pf-app03-fe-0 - timeouts: null - module.project-factory.module.projects["app03/fe"].google_project.project[0]: - auto_create_network: false - billing_account: 012345-67890A-ABCDEF - effective_labels: - environment: test - folder_id: '12345678' - labels: - environment: test - name: test-pf-app03-fe-0 - org_id: null - project_id: test-pf-app03-fe-0 - skip_delete: false - terraform_labels: - environment: test - timeouts: null - module.project-factory.module.projects["app03/fe"].google_project_service.project_services["run.googleapis.com"]: - disable_dependent_services: false - disable_on_destroy: false - project: test-pf-app03-fe-0 - service: run.googleapis.com - timeouts: null - module.project-factory.module.projects["app03/fe"].google_project_service.project_services["stackdriver.googleapis.com"]: - disable_dependent_services: false - disable_on_destroy: false - project: test-pf-app03-fe-0 - service: stackdriver.googleapis.com - timeouts: null - module.project-factory.module.projects["app03/fe"].google_project_service.project_services["storage.googleapis.com"]: - disable_dependent_services: false - disable_on_destroy: false - project: test-pf-app03-fe-0 - service: storage.googleapis.com - timeouts: null - ? module.project-factory.module.service-accounts["app01-app-1-be"].google_project_iam_member.project-roles["test-pf-app01-roles/logging.logWriter"] + ? module.project-factory.module.service-accounts["prj-app-1-app-1-be"].google_project_iam_member.project-roles["test-pf-prj-app-1-roles/logging.logWriter"] : condition: [] - project: test-pf-app01 + project: test-pf-prj-app-1 role: roles/logging.logWriter - ? module.project-factory.module.service-accounts["app01-app-1-be"].google_project_iam_member.project-roles["test-pf-app01-roles/monitoring.metricWriter"] + ? module.project-factory.module.service-accounts["prj-app-1-app-1-be"].google_project_iam_member.project-roles["test-pf-prj-app-1-roles/monitoring.metricWriter"] : condition: [] - project: test-pf-app01 + project: test-pf-prj-app-1 role: roles/monitoring.metricWriter - module.project-factory.module.service-accounts["app01-app-1-be"].google_service_account.service_account[0]: + module.project-factory.module.service-accounts["prj-app-1-app-1-be"].google_service_account.service_account[0]: account_id: app-1-be description: null disabled: false display_name: null - project: test-pf-app01 + project: test-pf-prj-app-1 timeouts: null - module.project-factory.module.service-accounts["app01-app-1-fe"].google_service_account.service_account[0]: + module.project-factory.module.service-accounts["prj-app-1-app-1-fe"].google_service_account.service_account[0]: account_id: app-1-fe description: null disabled: false display_name: Test app 1 frontend. - project: test-pf-app01 + project: test-pf-prj-app-1 timeouts: null - module.project-factory.module.service-accounts["app02/be-app-2-be"].google_service_account.service_account[0]: + module.project-factory.module.service-accounts["prj-app-2-app-2-be"].google_service_account.service_account[0]: account_id: app-2-be description: null disabled: false display_name: null - project: test-pf-app02-be + project: test-pf-prj-app-2 timeouts: null counts: google_compute_shared_vpc_service_project: 1 - google_essential_contacts_contact: 4 + google_essential_contacts_contact: 3 google_kms_crypto_key_iam_member: 1 - google_project: 4 + google_project: 3 google_project_iam_member: 2 - google_project_service: 13 + google_project_service: 10 google_service_account: 3 - google_storage_project_service_account: 4 - modules: 8 - resources: 32 + google_storage_project_service_account: 3 + modules: 7 + resources: 26 outputs: {} From 0f446e89d49a9a801dc5ff932295c6ba476119b3 Mon Sep 17 00:00:00 2001 From: Tone Date: Fri, 10 Nov 2023 12:39:50 +0100 Subject: [PATCH 26/29] Extend `cluster_autoscaling` fields in gke-cluster-standard (#1845) * feat(gke-cluster-standard): Add feature to setup `cluster_autoscaling` * feat(gke-cluster-standard): Add GPUs setup feature for `cluster_autoscaling` * feat(gke-cluster-standard): Add validation for `autoscaling_profile` and `disk_type` to ensure only valid values are specified * feat(gke-cluster-standard): Fix validation condition for `cluster_autoscaling` --- modules/gke-cluster-standard/README.md | 42 +++++++++++------------ modules/gke-cluster-standard/main.tf | 32 ++++++++++++++++- modules/gke-cluster-standard/variables.tf | 24 +++++++++++++ 3 files changed, 76 insertions(+), 22 deletions(-) diff --git a/modules/gke-cluster-standard/README.md b/modules/gke-cluster-standard/README.md index 53b57e8f80..e895b4819c 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#L154) | Cluster zone or region. | string | ✓ | | -| [name](variables.tf#L265) | Cluster name. | string | ✓ | | -| [project_id](variables.tf#L291) | Cluster project id. | string | ✓ | | -| [vpc_config](variables.tf#L314) | VPC-level configuration. | object({…}) | ✓ | | +| [location](variables.tf#L178) | Cluster zone or region. | string | ✓ | | +| [name](variables.tf#L289) | Cluster name. | string | ✓ | | +| [project_id](variables.tf#L315) | Cluster project id. | string | ✓ | | +| [vpc_config](variables.tf#L338) | 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 | -| [deletion_protection](variables.tf#L59) | 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#L66) | Cluster description. | string | | null | -| [enable_addons](variables.tf#L72) | Addons enabled in the cluster (true means enabled). | object({…}) | | {…} | -| [enable_features](variables.tf#L96) | Enable cluster-level features. Certain features allow configuration. | object({…}) | | {…} | -| [issue_client_certificate](variables.tf#L142) | Enable issuing client certificate. | bool | | false | -| [labels](variables.tf#L148) | Cluster resource labels. | map(string) | | null | -| [logging_config](variables.tf#L159) | Logging configuration. | object({…}) | | {} | -| [maintenance_config](variables.tf#L180) | Maintenance window configuration. | object({…}) | | {…} | -| [max_pods_per_node](variables.tf#L203) | Maximum number of pods per node in this cluster. | number | | 110 | -| [min_master_version](variables.tf#L209) | Minimum version of the master, defaults to the version of the most recent official release. | string | | null | -| [monitoring_config](variables.tf#L215) | Monitoring configuration. Google Cloud Managed Service for Prometheus is enabled by default. | object({…}) | | {} | -| [node_locations](variables.tf#L270) | Zones in which the cluster's nodes are located. | list(string) | | [] | -| [private_cluster_config](variables.tf#L277) | Private cluster configuration. | object({…}) | | null | -| [release_channel](variables.tf#L296) | Release channel for GKE upgrades. | string | | null | -| [service_account](variables.tf#L302) | Service account used for the default node pool, only useful if the default GCE service account has been disabled. | string | | null | -| [tags](variables.tf#L308) | Network tags applied to nodes. | list(string) | | null | +| [cluster_autoscaling](variables.tf#L38) | Enable and configure limits for Node Auto-Provisioning with Cluster Autoscaler. | object({…}) | | null | +| [deletion_protection](variables.tf#L83) | 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#L90) | Cluster description. | string | | null | +| [enable_addons](variables.tf#L96) | Addons enabled in the cluster (true means enabled). | object({…}) | | {…} | +| [enable_features](variables.tf#L120) | Enable cluster-level features. Certain features allow configuration. | object({…}) | | {…} | +| [issue_client_certificate](variables.tf#L166) | Enable issuing client certificate. | bool | | false | +| [labels](variables.tf#L172) | Cluster resource labels. | map(string) | | null | +| [logging_config](variables.tf#L183) | Logging configuration. | object({…}) | | {} | +| [maintenance_config](variables.tf#L204) | Maintenance window configuration. | object({…}) | | {…} | +| [max_pods_per_node](variables.tf#L227) | Maximum number of pods per node in this cluster. | number | | 110 | +| [min_master_version](variables.tf#L233) | Minimum version of the master, defaults to the version of the most recent official release. | string | | null | +| [monitoring_config](variables.tf#L239) | Monitoring configuration. Google Cloud Managed Service for Prometheus is enabled by default. | object({…}) | | {} | +| [node_locations](variables.tf#L294) | Zones in which the cluster's nodes are located. | list(string) | | [] | +| [private_cluster_config](variables.tf#L301) | Private cluster configuration. | object({…}) | | null | +| [release_channel](variables.tf#L320) | Release channel for GKE upgrades. | string | | null | +| [service_account](variables.tf#L326) | Service account used for the default node pool, only useful if the default GCE service account has been disabled. | string | | null | +| [tags](variables.tf#L332) | Network tags applied to nodes. | list(string) | | null | ## Outputs diff --git a/modules/gke-cluster-standard/main.tf b/modules/gke-cluster-standard/main.tf index f5d8fe7511..42f115e26b 100644 --- a/modules/gke-cluster-standard/main.tf +++ b/modules/gke-cluster-standard/main.tf @@ -123,13 +123,31 @@ resource "google_container_cluster" "cluster" { content { enabled = true + autoscaling_profile = var.cluster_autoscaling.autoscaling_profile + dynamic "auto_provisioning_defaults" { for_each = var.cluster_autoscaling.auto_provisioning_defaults != null ? [""] : [] content { boot_disk_kms_key = var.cluster_autoscaling.auto_provisioning_defaults.boot_disk_kms_key + disk_size = var.cluster_autoscaling.auto_provisioning_defaults.disk_size + disk_type = var.cluster_autoscaling.auto_provisioning_defaults.disk_type image_type = var.cluster_autoscaling.auto_provisioning_defaults.image_type oauth_scopes = var.cluster_autoscaling.auto_provisioning_defaults.oauth_scopes service_account = var.cluster_autoscaling.auto_provisioning_defaults.service_account + dynamic "management" { + for_each = var.cluster_autoscaling.auto_provisioning_defaults.management != null ? [""] : [] + content { + auto_repair = var.cluster_autoscaling.auto_provisioning_defaults.management.auto_repair + auto_upgrade = var.cluster_autoscaling.auto_provisioning_defaults.management.auto_upgrade + } + } + dynamic "shielded_instance_config" { + for_each = var.cluster_autoscaling.auto_provisioning_defaults.shielded_instance_config != null ? [""] : [] + content { + enable_integrity_monitoring = var.cluster_autoscaling.auto_provisioning_defaults.shielded_instance_config.integrity_monitoring + enable_secure_boot = var.cluster_autoscaling.auto_provisioning_defaults.shielded_instance_config.secure_boot + } + } } } dynamic "resource_limits" { @@ -148,7 +166,19 @@ resource "google_container_cluster" "cluster" { maximum = var.cluster_autoscaling.mem_limits.max } } - // TODO: support GPUs too + dynamic "resource_limits" { + for_each = ( + try(var.cluster_autoscaling.gpu_resources, null) == null + ? [] + : var.cluster_autoscaling.gpu_resources + ) + iterator = gpu_resources + content { + resource_type = gpu_resources.value.resource_type + minimum = gpu_resources.value.min + maximum = gpu_resources.value.max + } + } } } diff --git a/modules/gke-cluster-standard/variables.tf b/modules/gke-cluster-standard/variables.tf index 221f6b8a55..eebd595a05 100644 --- a/modules/gke-cluster-standard/variables.tf +++ b/modules/gke-cluster-standard/variables.tf @@ -38,11 +38,22 @@ variable "backup_configs" { variable "cluster_autoscaling" { description = "Enable and configure limits for Node Auto-Provisioning with Cluster Autoscaler." type = object({ + autoscaling_profile = optional(string, "BALANCED") auto_provisioning_defaults = optional(object({ boot_disk_kms_key = optional(string) + disk_size = optional(number) + disk_type = optional(string, "pd-standard") image_type = optional(string) oauth_scopes = optional(list(string)) service_account = optional(string) + management = optional(object({ + auto_repair = optional(bool, true) + auto_upgrade = optional(bool, true) + })) + shielded_instance_config = object({ + integrity_monitoring = optional(bool, true) + secure_boot = optional(bool, false) + }) })) cpu_limits = optional(object({ min = number @@ -52,8 +63,21 @@ variable "cluster_autoscaling" { min = number max = number })) + gpu_resources = optional(list(object({ + resource_type = string + min = number + max = number + }))) }) default = null + validation { + condition = (var.cluster_autoscaling == null ? true : contains(["BALANCED", "OPTIMIZE_UTILIZATION"], var.cluster_autoscaling.autoscaling_profile)) + error_message = "Invalid autoscaling_profile." + } + validation { + condition = (var.cluster_autoscaling == null ? true : contains(["pd-standard", "pd-ssd", "pd-balanced"], var.cluster_autoscaling.auto_provisioning_defaults.disk_type)) + error_message = "Invalid disk_type." + } } variable "deletion_protection" { From d07f8fd33d0a5fc8eb9118a0258e3158949d95f9 Mon Sep 17 00:00:00 2001 From: luigi-bitonti <93377317+luigi-bitonti@users.noreply.github.com> Date: Fri, 10 Nov 2023 16:45:47 +0100 Subject: [PATCH 27/29] Added CMEK for Secret auto managed (#1739) Allow to specify custom KMS keys for Secret Manager secrets --- .../sqlserver-alwayson/secrets.tf | 4 +- .../data-solutions/vertex-mlops/ci-cd.tf | 10 ++-- modules/secret-manager/README.md | 53 +++++++++++-------- modules/secret-manager/main.tf | 23 ++++---- modules/secret-manager/variables.tf | 19 +++---- 5 files changed, 63 insertions(+), 46 deletions(-) diff --git a/blueprints/data-solutions/sqlserver-alwayson/secrets.tf b/blueprints/data-solutions/sqlserver-alwayson/secrets.tf index 2a0bba8d6c..f25871deb8 100644 --- a/blueprints/data-solutions/sqlserver-alwayson/secrets.tf +++ b/blueprints/data-solutions/sqlserver-alwayson/secrets.tf @@ -19,7 +19,9 @@ module "secret-manager" { source = "../../../modules/secret-manager" project_id = var.project_id secrets = { - (local.ad_user_password_secret) = null + (local.ad_user_password_secret) = { + locations = null + } } versions = { (local.ad_user_password_secret) = { diff --git a/blueprints/data-solutions/vertex-mlops/ci-cd.tf b/blueprints/data-solutions/vertex-mlops/ci-cd.tf index 3c7c863151..28fb320bc1 100644 --- a/blueprints/data-solutions/vertex-mlops/ci-cd.tf +++ b/blueprints/data-solutions/vertex-mlops/ci-cd.tf @@ -57,10 +57,12 @@ module "secret-manager" { project_id = module.project.project_id source = "../../../modules/secret-manager" secrets = { - github-key = [var.region] - } - encryption_key = { - "${var.region}" = var.service_encryption_keys.secretmanager + github-key = { + locations = [var.region] + keys = { + "${var.region}" = var.service_encryption_keys.secretmanager + } + } } iam = { github-key = { diff --git a/modules/secret-manager/README.md b/modules/secret-manager/README.md index dc0929832f..8d1d8b110b 100644 --- a/modules/secret-manager/README.md +++ b/modules/secret-manager/README.md @@ -17,8 +17,10 @@ module "secret-manager" { source = "./fabric/modules/secret-manager" project_id = "my-project" secrets = { - test-auto = null - test-manual = ["europe-west1", "europe-west4"] + test-auto = {} + test-manual = { + locations = ["europe-west1", "europe-west4"] + } } } # tftest modules=1 resources=2 @@ -33,8 +35,10 @@ module "secret-manager" { source = "./fabric/modules/secret-manager" project_id = "my-project" secrets = { - test-auto = null - test-manual = ["europe-west1", "europe-west4"] + test-auto = {} + test-manual = { + locations = ["europe-west1", "europe-west4"] + } } iam = { test-auto = { @@ -57,8 +61,10 @@ module "secret-manager" { source = "./fabric/modules/secret-manager" project_id = "my-project" secrets = { - test-auto = null - test-manual = ["europe-west1", "europe-west4"] + test-auto = {} + test-manual = { + locations = ["europe-west1", "europe-west4"] + } } versions = { test-auto = { @@ -75,34 +81,40 @@ module "secret-manager" { ### Secret with customer managed encryption key -Secrets will be used if an encryption key is set in the `encryption_key` variable for the secret region. +CMEK will be used if an encryption key is set in the `keys` field of `secrets` object for the secret region. For secrets with auto-replication, a global key must be specified. ```hcl module "secret-manager" { source = "./fabric/modules/secret-manager" project_id = "my-project" secrets = { - test-encryption = ["europe-west1", "europe-west4"] - } - encryption_key = { - europe-west1 = "projects/PROJECT_ID/locations/europe-west1/keyRings/KEYRING/cryptoKeys/KEY" - europe-west4 = "projects/PROJECT_ID/locations/europe-west4/keyRings/KEYRING/cryptoKeys/KEY" + test-auto = { + keys = { + global = "projects/PROJECT_ID/locations/global/keyRings/KEYRING/cryptoKeys/KEY" + } + } + test-auto-nokeys = {} + test-manual = { + locations = ["europe-west1", "europe-west4"] + keys = { + europe-west1 = "projects/PROJECT_ID/locations/europe-west1/keyRings/KEYRING/cryptoKeys/KEY" + europe-west4 = "projects/PROJECT_ID/locations/europe-west4/keyRings/KEYRING/cryptoKeys/KEY" + } + } } } -# tftest modules=1 resources=1 +# tftest modules=1 resources=3 ``` - ## Variables | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [project_id](variables.tf#L35) | Project id where the keyring will be created. | string | ✓ | | -| [encryption_key](variables.tf#L17) | Self link of the KMS keys in {LOCATION => KEY} format. A key must be provided for all replica locations. | map(string) | | null | -| [iam](variables.tf#L23) | IAM bindings in {SECRET => {ROLE => [MEMBERS]}} format. | map(map(list(string))) | | {} | -| [labels](variables.tf#L29) | Optional labels for each secret. | map(map(string)) | | {} | -| [secrets](variables.tf#L40) | Map of secrets to manage and their locations. If locations is null, automatic management will be set. | map(list(string)) | | {} | -| [versions](variables.tf#L46) | Optional versions to manage for each secret. Version names are only used internally to track individual versions. | map(map(object({…}))) | | {} | +| [project_id](variables.tf#L29) | Project id where the keyring will be created. | string | ✓ | | +| [iam](variables.tf#L17) | IAM bindings in {SECRET => {ROLE => [MEMBERS]}} format. | map(map(list(string))) | | {} | +| [labels](variables.tf#L23) | Optional labels for each secret. | map(map(string)) | | {} | +| [secrets](variables.tf#L34) | Map of secrets to manage, their locations and KMS keys in {LOCATION => KEY} format. {GLOBAL => KEY} format enables CMEK for automatic managed secrets. If locations is null, automatic management will be set. | map(object({…})) | | {} | +| [versions](variables.tf#L43) | Optional versions to manage for each secret. Version names are only used internally to track individual versions. | map(map(object({…}))) | | {} | ## Outputs @@ -112,7 +124,6 @@ module "secret-manager" { | [secrets](outputs.tf#L24) | Secret resources. | | | [version_ids](outputs.tf#L29) | Version ids keyed by secret name : version name. | | | [versions](outputs.tf#L36) | Secret versions. | ✓ | - ## Requirements diff --git a/modules/secret-manager/main.tf b/modules/secret-manager/main.tf index 1a17ac21cf..61f4d5efe2 100644 --- a/modules/secret-manager/main.tf +++ b/modules/secret-manager/main.tf @@ -42,27 +42,32 @@ resource "google_secret_manager_secret" "default" { labels = lookup(var.labels, each.key, null) dynamic "replication" { - for_each = each.value == null ? [""] : [] + for_each = each.value.locations == null ? [""] : [] content { - # TODO(jccb): support custom keys inside auto - auto {} + auto { + dynamic "customer_managed_encryption" { + for_each = try(lookup(each.value.keys, "global", null) == null ? [] : [""], []) + content { + kms_key_name = each.value.keys["global"] + } + } + } } } dynamic "replication" { - for_each = each.value == null ? [] : [each.value] - iterator = locations + for_each = each.value.locations == null ? [] : [""] content { user_managed { dynamic "replicas" { - for_each = locations.value + for_each = each.value.locations iterator = location content { location = location.value dynamic "customer_managed_encryption" { - for_each = try(var.encryption_key[location.value] != null ? [""] : [], []) + for_each = try(lookup(each.value.keys, location.value, null) == null ? [] : [""], []) content { - kms_key_name = var.encryption_key[location.value] + kms_key_name = each.value.keys[location.value] } } } @@ -88,4 +93,4 @@ resource "google_secret_manager_secret_iam_binding" "default" { role = each.value.role secret_id = google_secret_manager_secret.default[each.value.secret].id members = each.value.members -} +} \ No newline at end of file diff --git a/modules/secret-manager/variables.tf b/modules/secret-manager/variables.tf index 7d7b528484..089f2a69b2 100644 --- a/modules/secret-manager/variables.tf +++ b/modules/secret-manager/variables.tf @@ -1,5 +1,5 @@ /** - * Copyright 2022 Google LLC + * Copyright 2023 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,12 +14,6 @@ * limitations under the License. */ -variable "encryption_key" { - description = "Self link of the KMS keys in {LOCATION => KEY} format. A key must be provided for all replica locations." - type = map(string) - default = null -} - variable "iam" { description = "IAM bindings in {SECRET => {ROLE => [MEMBERS]}} format." type = map(map(list(string))) @@ -38,9 +32,12 @@ variable "project_id" { } variable "secrets" { - description = "Map of secrets to manage and their locations. If locations is null, automatic management will be set." - type = map(list(string)) - default = {} + description = "Map of secrets to manage, their locations and KMS keys in {LOCATION => KEY} format. {GLOBAL => KEY} format enables CMEK for automatic managed secrets. If locations is null, automatic management will be set." + type = map(object({ + locations = optional(list(string), null) + keys = optional(map(string), null) + })) + default = {} } variable "versions" { @@ -50,4 +47,4 @@ variable "versions" { data = string }))) default = {} -} +} \ No newline at end of file From c79af78c48ef77041ebfb5fee509cc1a33522bcf Mon Sep 17 00:00:00 2001 From: apichick Date: Sun, 12 Nov 2023 20:21:06 +0100 Subject: [PATCH 28/29] Removed options that are not applicable to this load balancer --- modules/net-lb-app-int/README.md | 24 +++++++++++++------ modules/net-lb-app-int/backend-service.tf | 22 ----------------- .../variables-backend-service.tf | 11 --------- 3 files changed, 17 insertions(+), 40 deletions(-) diff --git a/modules/net-lb-app-int/README.md b/modules/net-lb-app-int/README.md index dfc4f5eccb..3616494a7d 100644 --- a/modules/net-lb-app-int/README.md +++ b/modules/net-lb-app-int/README.md @@ -223,7 +223,9 @@ module "ilb-l7" { backends = [{ balancing_mode = "RATE" group = "projects/myprj/zones/europe-west1-a/networkEndpointGroups/my-neg" - max_rate = { per_endpoint = 1 } + max_rate = { + per_endpoint = 1 + } }] } } @@ -259,7 +261,9 @@ module "ilb-l7" { backends = [{ balancing_mode = "RATE" group = "my-neg" - max_rate = { per_endpoint = 1 } + max_rate = { + per_endpoint = 1 + } }] } } @@ -296,7 +300,13 @@ module "ilb-l7" { region = "europe-west1" backend_service_configs = { default = { - backends = [{ group = "my-neg" }] + backends = [{ + balancing_mode = "RATE" + group = "my-neg" + max_rate = { + per_endpoint = 1 + } + }] } } neg_configs = { @@ -518,7 +528,9 @@ module "ilb-l7" { backends = [{ balancing_mode = "RATE" group = "neg-nginx-ew8-c" - max_rate = { per_endpoint = 1 } + max_rate = { + per_endpoint = 1 + } }] } home = { @@ -625,7 +637,6 @@ module "ilb-l7" { - ## Files | name | description | resources | @@ -651,7 +662,7 @@ module "ilb-l7" { | [region](variables.tf#L156) | The region where to allocate the ILB resources. | string | ✓ | | | [vpc_config](variables.tf#L183) | VPC-level configuration. | object({…}) | ✓ | | | [address](variables.tf#L17) | Optional IP address used for the forwarding rule. | string | | null | -| [backend_service_configs](variables-backend-service.tf#L19) | Backend service level configuration. | map(object({…})) | | {} | +| [backend_service_configs](variables-backend-service.tf#L19) | Backend service level configuration. | map(object({…})) | | {} | | [description](variables.tf#L23) | Optional description used for resources. | string | | "Terraform managed." | | [global_access](variables.tf#L30) | Allow client access from all regions. | bool | | null | | [group_configs](variables.tf#L36) | Optional unmanaged groups to create. Can be referenced in backends via key or outputs. | map(object({…})) | | {} | @@ -677,5 +688,4 @@ module "ilb-l7" { | [health_check_ids](outputs.tf#L48) | Autogenerated health check ids. | | | [id](outputs.tf#L55) | Fully qualified forwarding rule id. | | | [neg_ids](outputs.tf#L60) | Autogenerated network endpoint group ids. | | - diff --git a/modules/net-lb-app-int/backend-service.tf b/modules/net-lb-app-int/backend-service.tf index 669a291aff..0dcfa46a99 100644 --- a/modules/net-lb-app-int/backend-service.tf +++ b/modules/net-lb-app-int/backend-service.tf @@ -114,28 +114,6 @@ resource "google_compute_region_backend_service" "default" { } } - dynamic "connection_tracking_policy" { - for_each = ( - each.value.connection_tracking == null - ? [] - : [each.value.connection_tracking] - ) - iterator = cb - content { - connection_persistence_on_unhealthy_backends = ( - cb.value.persist_conn_on_unhealthy != null - ? cb.value.persist_conn_on_unhealthy - : null - ) - idle_timeout_sec = cb.value.idle_timeout_sec - tracking_mode = ( - cb.value.track_per_session != null - ? cb.value.track_per_session - : null - ) - } - } - dynamic "consistent_hash" { for_each = ( each.value.consistent_hash == null ? [] : [each.value.consistent_hash] diff --git a/modules/net-lb-app-int/variables-backend-service.tf b/modules/net-lb-app-int/variables-backend-service.tf index 5cfe9a5aca..728e21dbc3 100644 --- a/modules/net-lb-app-int/variables-backend-service.tf +++ b/modules/net-lb-app-int/variables-backend-service.tf @@ -35,11 +35,6 @@ variable "backend_service_configs" { capacity_scaler = optional(number, 1) description = optional(string, "Terraform managed.") failover = optional(bool, false) - max_connections = optional(object({ - per_endpoint = optional(number) - per_group = optional(number) - per_instance = optional(number) - })) max_rate = optional(object({ per_endpoint = optional(number) per_group = optional(number) @@ -58,11 +53,6 @@ variable "backend_service_configs" { nanos = optional(number) })) })) - connection_tracking = optional(object({ - idle_timeout_sec = optional(number) - persist_conn_on_unhealthy = optional(string) - track_per_session = optional(bool) - })) consistent_hash = optional(object({ http_header_name = optional(string) minimum_ring_size = optional(number) @@ -79,7 +69,6 @@ variable "backend_service_configs" { failover_config = optional(object({ disable_conn_drain = optional(bool) drop_traffic_if_unhealthy = optional(bool) - ratio = optional(number) })) iap_config = optional(object({ oauth2_client_id = string From 1c2f1c7b0d565db3b3f56bdcb2dfbfac80351975 Mon Sep 17 00:00:00 2001 From: Francesco Spinelli <90899331+Francesco-cloud24@users.noreply.github.com> Date: Mon, 13 Nov 2023 10:27:14 +0100 Subject: [PATCH 29/29] Sql user features (#1856) * added user type feature * fix readme * fix comment * fix blueprint cloudsql users value + minor fix * readme fix * variables fix * local var fix * fix for in local var * fix on readme * fix intentations var in readme * fix blueprint user quote --------- Co-authored-by: Francesco Spinelli --- .../cloudsql-multiregion/cloudsql.tf | 4 +- .../third-party-solutions/phpipam/cloudsql.tf | 4 +- .../wordpress/cloudrun/cloudsql.tf | 4 +- modules/cloudsql-instance/README.md | 10 +++-- modules/cloudsql-instance/main.tf | 39 ++++++++++--------- modules/cloudsql-instance/variables.tf | 9 +++-- 6 files changed, 43 insertions(+), 27 deletions(-) diff --git a/blueprints/data-solutions/cloudsql-multiregion/cloudsql.tf b/blueprints/data-solutions/cloudsql-multiregion/cloudsql.tf index e25812df5b..5dab5d6b60 100644 --- a/blueprints/data-solutions/cloudsql-multiregion/cloudsql.tf +++ b/blueprints/data-solutions/cloudsql-multiregion/cloudsql.tf @@ -34,7 +34,9 @@ module "db" { } databases = [var.postgres_database] users = { - postgres = var.postgres_user_password + postgres = { + password = var.postgres_user_password + } } } diff --git a/blueprints/third-party-solutions/phpipam/cloudsql.tf b/blueprints/third-party-solutions/phpipam/cloudsql.tf index 24a47b661c..f3b7a78665 100644 --- a/blueprints/third-party-solutions/phpipam/cloudsql.tf +++ b/blueprints/third-party-solutions/phpipam/cloudsql.tf @@ -27,6 +27,8 @@ module "cloudsql" { region = var.region tier = local.cloudsql_conf.tier users = { - "${local.cloudsql_conf.user}" = var.cloudsql_password + "${local.cloudsql_conf.user}" = { + password = var.cloudsql_password + } } } diff --git a/blueprints/third-party-solutions/wordpress/cloudrun/cloudsql.tf b/blueprints/third-party-solutions/wordpress/cloudrun/cloudsql.tf index 4ed2ed1992..2ebe9e1436 100644 --- a/blueprints/third-party-solutions/wordpress/cloudrun/cloudsql.tf +++ b/blueprints/third-party-solutions/wordpress/cloudrun/cloudsql.tf @@ -61,7 +61,9 @@ module "cloudsql" { tier = local.cloudsql_conf.tier databases = [local.cloudsql_conf.db] users = { - "${local.cloudsql_conf.user}" = var.cloudsql_password + "${local.cloudsql_conf.user}" = { + password = var.cloudsql_password + } } deletion_protection = false } diff --git a/modules/cloudsql-instance/README.md b/modules/cloudsql-instance/README.md index c0f72cae08..1a9347691d 100644 --- a/modules/cloudsql-instance/README.md +++ b/modules/cloudsql-instance/README.md @@ -86,9 +86,13 @@ module "db" { users = { # generatea password for user1 - user1 = null + user1 = { + password = null + } # assign a password to user2 - user2 = "mypassword" + user2 = { + password = "mypassword" + } } } # tftest modules=1 resources=6 inventory=custom.yaml @@ -212,7 +216,7 @@ module "db" { | [replicas](variables.tf#L179) | Map of NAME=> {REGION, KMS_KEY} for additional read replicas. Set to null to disable replica creation. | map(object({…})) | | {} | | [require_ssl](variables.tf#L188) | Enable SSL connections only. | bool | | null | | [root_password](variables.tf#L194) | Root password of the Cloud SQL instance. Required for MS SQL Server. | string | | null | -| [users](variables.tf#L205) | Map of users to create in the primary instance (and replicated to other replicas) in the format USER=>PASSWORD. For MySQL, anything afterr the first `@` (if persent) will be used as the user's host. Set PASSWORD to null if you want to get an autogenerated password. | map(string) | | null | +| [users](variables.tf#L205) | Map of users to create in the primary instance (and replicated to other replicas). For MySQL, anything afterr the first `@` (if persent) will be used as the user's host. Set PASSWORD to null if you want to get an autogenerated password. The user types available are: 'BUILT_IN', 'CLOUD_IAM_USER' or 'CLOUD_IAM_SERVICE_ACCOUNT'. | map(object({…})) | | null | ## Outputs diff --git a/modules/cloudsql-instance/main.tf b/modules/cloudsql-instance/main.tf index fd3d9abdbd..cc6e62af8f 100644 --- a/modules/cloudsql-instance/main.tf +++ b/modules/cloudsql-instance/main.tf @@ -1,4 +1,4 @@ -/** +/** TO MOD * Copyright 2022 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,6 +17,7 @@ locals { prefix = var.prefix == null ? "" : "${var.prefix}-" is_mysql = can(regex("^MYSQL", var.database_version)) + is_postgres = can(regex("^POSTGRES", var.database_version)) has_replicas = try(length(var.replicas) > 0, false) is_regional = var.availability_type == "REGIONAL" ? true : false @@ -25,20 +26,20 @@ locals { enable_backup = var.backup_configuration.enabled || (local.is_mysql && local.has_replicas) || (local.is_mysql && local.is_regional) users = { - for user, password in coalesce(var.users, {}) : - (user) => ( - local.is_mysql - ? { - name = split("@", user)[0] - host = try(split("@", user)[1], null) - password = try(random_password.passwords[user].result, password) - } - : { - name = user - host = null - password = try(random_password.passwords[user].result, password) - } - ) + for k, v in coalesce(var.users, {}) : + k => + local.is_mysql ? + { + name = try(v.type, "BUILT_IN") == "BUILT_IN" ? split("@", k)[0] : k + host = try(v.type, "BUILT_IN") == "BUILT_IN" ? try(split("@", k)[1], null) : null + password = try(v.type, "BUILT_IN") == "BUILT_IN" ? try(random_password.passwords[k].result, v.password) : null + type = try(v.type, "BUILT_IN") + } : { + name = local.is_postgres ? try(trimsuffix(k, ".gserviceaccount.com"), k) : k + host = null + password = try(v.type, "BUILT_IN") == "BUILT_IN" ? try(random_password.passwords[k].result, v.password) : null + type = try(v.type, "BUILT_IN") + } } } @@ -178,14 +179,15 @@ resource "google_sql_database" "databases" { resource "random_password" "passwords" { for_each = toset([ - for user, password in coalesce(var.users, {}) : - user - if password == null + for k, v in coalesce(var.users, {}) : + k + if v.password == null ]) length = 16 special = true } + resource "google_sql_user" "users" { for_each = local.users project = var.project_id @@ -193,6 +195,7 @@ resource "google_sql_user" "users" { name = each.value.name host = each.value.host password = each.value.password + type = each.value.type } resource "google_sql_ssl_cert" "postgres_client_certificates" { diff --git a/modules/cloudsql-instance/variables.tf b/modules/cloudsql-instance/variables.tf index d13889b0c4..7fda3e9b02 100644 --- a/modules/cloudsql-instance/variables.tf +++ b/modules/cloudsql-instance/variables.tf @@ -203,8 +203,11 @@ variable "tier" { } variable "users" { - description = "Map of users to create in the primary instance (and replicated to other replicas) in the format USER=>PASSWORD. For MySQL, anything afterr the first `@` (if persent) will be used as the user's host. Set PASSWORD to null if you want to get an autogenerated password." - type = map(string) - default = null + description = "Map of users to create in the primary instance (and replicated to other replicas). For MySQL, anything afterr the first `@` (if persent) will be used as the user's host. Set PASSWORD to null if you want to get an autogenerated password. The user types available are: 'BUILT_IN', 'CLOUD_IAM_USER' or 'CLOUD_IAM_SERVICE_ACCOUNT'." + type = map(object({ + password = optional(string) + type = optional(string) + })) + default = null }