From fdbe2f34bdd81fc56a86aa1dfd0b32c589e3cb49 Mon Sep 17 00:00:00 2001 From: Liam Nesteroff <35284740+lnesteroff@users.noreply.github.com> Date: Fri, 1 Aug 2025 16:48:04 +1000 Subject: [PATCH 1/3] fixed schema patter for iam_bindings_additive roles (#3258) * fixed schema to allow iam_bindings_additive roles with "." (roles/compute.admin) --- fast/stages/2-project-factory/schemas/project.schema.md | 2 +- modules/project-factory/schemas/project.schema.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fast/stages/2-project-factory/schemas/project.schema.md b/fast/stages/2-project-factory/schemas/project.schema.md index 0be198251..bffc4bb97 100644 --- a/fast/stages/2-project-factory/schemas/project.schema.md +++ b/fast/stages/2-project-factory/schemas/project.schema.md @@ -173,7 +173,7 @@ - **member**: *string*
*pattern: ^(?:domain:|group:|serviceAccount:|user:|principal:|principalSet:|[a-z])* - **role**: *string* -
*pattern: ^[a-zA-Z0-9_/]+$* +
*pattern: ^[a-zA-Z0-9_/.]+$* - **condition**: *object*
*additional properties: false* - ⁺**expression**: *string* diff --git a/modules/project-factory/schemas/project.schema.json b/modules/project-factory/schemas/project.schema.json index e2c765ed0..11b4eb05e 100644 --- a/modules/project-factory/schemas/project.schema.json +++ b/modules/project-factory/schemas/project.schema.json @@ -249,7 +249,7 @@ } } } - }, + }, "parent": { "type": "string" }, @@ -616,7 +616,7 @@ }, "role": { "type": "string", - "pattern": "^[a-zA-Z0-9_/]+$" + "pattern": "^[a-zA-Z0-9_/.]+$" }, "condition": { "type": "object", From 9bd43632692aeeaea9251038717ddf4026d19469 Mon Sep 17 00:00:00 2001 From: Muhammad Elsaeed Date: Fri, 1 Aug 2025 19:41:49 +0300 Subject: [PATCH 2/3] feat: add GCS bucket trigger support for Cloud Run services (#3257) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add GCS bucket trigger support for Cloud Run services 🌟 * feat: add examples for Cloud Run service with Eventarc storage triggers * fix: update bucket name in Eventarc storage trigger example and clean up service account configuration --------- Co-authored-by: Ludovico Magnocavallo --- modules/cloud-run-v2/README.md | 91 +++++++++++++++---- modules/cloud-run-v2/main.tf | 23 +++++ modules/cloud-run-v2/variables.tf | 6 +- .../service-eventarc-storage-sa-create.yaml | 73 +++++++++++++++ .../examples/service-eventarc-storage.yaml | 58 ++++++++++++ 5 files changed, 233 insertions(+), 18 deletions(-) create mode 100644 tests/modules/cloud_run_v2/examples/service-eventarc-storage-sa-create.yaml create mode 100644 tests/modules/cloud_run_v2/examples/service-eventarc-storage.yaml diff --git a/modules/cloud-run-v2/README.md b/modules/cloud-run-v2/README.md index 5c577f528..86c4f1a68 100644 --- a/modules/cloud-run-v2/README.md +++ b/modules/cloud-run-v2/README.md @@ -14,6 +14,7 @@ Cloud Run Services and Jobs, with support for IAM roles and Eventarc trigger cre - [Eventarc triggers](#eventarc-triggers) - [PubSub](#pubsub) - [Audit logs](#audit-logs) + - [GCS bucket](#gcs-bucket) - [Using custom service accounts for triggers](#using-custom-service-accounts-for-triggers) - [Cloud Run Invoker IAM Disable](#cloud-run-invoker-iam-disable) - [Cloud Run Service Account](#cloud-run-service-account) @@ -612,6 +613,34 @@ module "cloud_run" { # tftest modules=1 resources=4 inventory=service-eventarc-auditlogs-sa-create.yaml ``` +### GCS bucket + +This deploys a Cloud Run service that will be triggered when files are uploaded to a GCS bucket. + +```hcl +module "cloud_run" { + source = "./fabric/modules/cloud-run-v2" + project_id = var.project_id + region = var.region + name = "hello" + containers = { + hello = { + image = "us-docker.pkg.dev/cloudrun/container/hello" + } + } + eventarc_triggers = { + storage = { + bucket-upload = { + bucket = module.gcs.name + path = "/webhook" # optional: URL path for the Cloud Run service + } + } + } + deletion_protection = false +} +# tftest modules=2 resources=4 fixtures=fixtures/gcs.tf inventory=service-eventarc-storage.yaml e2e +``` + ### Using custom service accounts for triggers By default `Compute default service account` is used to trigger Cloud Run. If you want to use custom Service Accounts you can either provide your own in `eventarc_triggers.service_account_email` or set `eventarc_triggers.service_account_create` to true and service account named `tf-cr-trigger-${var.name}` will be created with `roles/run.invoker` granted on this Cloud Run service. @@ -666,6 +695,33 @@ module "cloud_run" { # tftest modules=2 resources=6 fixtures=fixtures/pubsub.tf inventory=service-eventarc-pubsub-sa-create.yaml e2e ``` +Example using automatically created service account for storage triggers: + +```hcl +module "cloud_run" { + source = "./fabric/modules/cloud-run-v2" + project_id = var.project_id + region = var.region + name = "hello" + containers = { + hello = { + image = "us-docker.pkg.dev/cloudrun/container/hello" + } + } + eventarc_triggers = { + storage = { + bucket-upload = { + bucket = module.gcs.name + path = "/webhook" # optional: URL path for the Cloud Run service + } + } + service_account_create = true + } + deletion_protection = false +} +# tftest modules=2 resources=6 fixtures=fixtures/gcs.tf inventory=service-eventarc-storage-sa-create.yaml e2e +``` + ## Cloud Run Invoker IAM Disable To disables IAM permission check for `run.routes.invoke` for callers of this service set the `invoker_iam_disabled` variable of the module to `true` (default `false`). There should be no requirement to pass the `roles/run.invoker` to the IAM block to enable public access. This allows for the org policy `domain restricted sharing` org policy remain enabled. @@ -842,28 +898,28 @@ module "cloud_run" { | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [name](variables.tf#L206) | Name used for Cloud Run service. | string | ✓ | | -| [project_id](variables.tf#L221) | Project id used for all resources. | string | ✓ | | -| [region](variables.tf#L226) | Region used for all resources. | string | ✓ | | +| [name](variables.tf#L210) | Name used for Cloud Run service. | string | ✓ | | +| [project_id](variables.tf#L225) | Project id used for all resources. | string | ✓ | | +| [region](variables.tf#L230) | Region used for all resources. | string | ✓ | | | [containers](variables.tf#L17) | Containers in name => attributes format. | map(object({…})) | | {} | | [create_job](variables.tf#L80) | Create Cloud Run Job instead of Service. | bool | | false | | [custom_audiences](variables.tf#L86) | Custom audiences for service. | list(string) | | null | | [deletion_protection](variables.tf#L92) | Deletion protection setting for this Cloud Run service. | string | | null | | [encryption_key](variables.tf#L98) | The full resource name of the Cloud KMS CryptoKey. | string | | null | -| [eventarc_triggers](variables.tf#L104) | Event arc triggers for different sources. | object({…}) | | {} | -| [iam](variables.tf#L122) | IAM bindings for Cloud Run service in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | -| [iap_config](variables.tf#L128) | If present, turns on Identity-Aware Proxy (IAP) for the Cloud Run service. | object({…}) | | null | -| [ingress](variables.tf#L153) | Ingress settings. | string | | null | -| [invoker_iam_disabled](variables.tf#L170) | Disables IAM permission check for run.routes.invoke for callers of this service. | bool | | false | -| [labels](variables.tf#L176) | Resource labels. | map(string) | | {} | -| [launch_stage](variables.tf#L182) | The launch stage as defined by Google Cloud Platform Launch Stages. | string | | null | -| [managed_revision](variables.tf#L199) | Whether the Terraform module should control the deployment of revisions. | bool | | true | -| [prefix](variables.tf#L211) | Optional prefix used for resource names. | string | | null | -| [revision](variables.tf#L231) | Revision template configurations. | object({…}) | | {} | -| [service_account](variables.tf#L270) | Service account email. Unused if service account is auto-created. | string | | null | -| [service_account_create](variables.tf#L276) | Auto-create service account. | bool | | false | -| [tag_bindings](variables.tf#L282) | Tag bindings for this service, in key => tag value id format. | map(string) | | {} | -| [volumes](variables.tf#L289) | Named volumes in containers in name => attributes format. | map(object({…})) | | {} | +| [eventarc_triggers](variables.tf#L104) | Event arc triggers for different sources. | object({…}) | | {} | +| [iam](variables.tf#L126) | IAM bindings for Cloud Run service in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | +| [iap_config](variables.tf#L132) | If present, turns on Identity-Aware Proxy (IAP) for the Cloud Run service. | object({…}) | | null | +| [ingress](variables.tf#L157) | Ingress settings. | string | | null | +| [invoker_iam_disabled](variables.tf#L174) | Disables IAM permission check for run.routes.invoke for callers of this service. | bool | | false | +| [labels](variables.tf#L180) | Resource labels. | map(string) | | {} | +| [launch_stage](variables.tf#L186) | The launch stage as defined by Google Cloud Platform Launch Stages. | string | | null | +| [managed_revision](variables.tf#L203) | Whether the Terraform module should control the deployment of revisions. | bool | | true | +| [prefix](variables.tf#L215) | Optional prefix used for resource names. | string | | null | +| [revision](variables.tf#L235) | Revision template configurations. | object({…}) | | {} | +| [service_account](variables.tf#L274) | Service account email. Unused if service account is auto-created. | string | | null | +| [service_account_create](variables.tf#L280) | Auto-create service account. | bool | | false | +| [tag_bindings](variables.tf#L286) | Tag bindings for this service, in key => tag value id format. | map(string) | | {} | +| [volumes](variables.tf#L293) | Named volumes in containers in name => attributes format. | map(object({…})) | | {} | | [vpc_connector_create](variables-vpcconnector.tf#L17) | Populate this to create a Serverless VPC Access connector. | object({…}) | | null | ## Outputs @@ -884,6 +940,7 @@ module "cloud_run" { ## Fixtures - [cloudsql-instance.tf](../../tests/fixtures/cloudsql-instance.tf) +- [gcs.tf](../../tests/fixtures/gcs.tf) - [iam-service-account.tf](../../tests/fixtures/iam-service-account.tf) - [pubsub.tf](../../tests/fixtures/pubsub.tf) - [secret-credentials.tf](../../tests/fixtures/secret-credentials.tf) diff --git a/modules/cloud-run-v2/main.tf b/modules/cloud-run-v2/main.tf index 84212ba07..d92a1697b 100644 --- a/modules/cloud-run-v2/main.tf +++ b/modules/cloud-run-v2/main.tf @@ -128,6 +128,29 @@ resource "google_eventarc_trigger" "pubsub_triggers" { service_account = local.trigger_sa_email } +resource "google_eventarc_trigger" "storage_triggers" { + for_each = coalesce(var.eventarc_triggers.storage, tomap({})) + name = "${local.prefix}storage-${each.key}" + location = google_cloud_run_v2_service.service[0].location + project = google_cloud_run_v2_service.service[0].project + matching_criteria { + attribute = "type" + value = "google.cloud.storage.object.v1.finalized" + } + matching_criteria { + attribute = "bucket" + value = each.value.bucket + } + destination { + cloud_run_service { + service = google_cloud_run_v2_service.service[0].name + region = google_cloud_run_v2_service.service[0].location + path = try(each.value.path, null) + } + } + service_account = local.trigger_sa_email +} + resource "google_service_account" "trigger_service_account" { count = local.trigger_sa_create ? 1 : 0 project = var.project_id diff --git a/modules/cloud-run-v2/variables.tf b/modules/cloud-run-v2/variables.tf index 1de08de08..d270a6799 100644 --- a/modules/cloud-run-v2/variables.tf +++ b/modules/cloud-run-v2/variables.tf @@ -108,7 +108,11 @@ variable "eventarc_triggers" { method = string service = string }))) - pubsub = optional(map(string)) + pubsub = optional(map(string)) + storage = optional(map(object({ + bucket = string + path = optional(string) + }))) service_account_email = optional(string) service_account_create = optional(bool, false) }) diff --git a/tests/modules/cloud_run_v2/examples/service-eventarc-storage-sa-create.yaml b/tests/modules/cloud_run_v2/examples/service-eventarc-storage-sa-create.yaml new file mode 100644 index 000000000..6b532fa56 --- /dev/null +++ b/tests/modules/cloud_run_v2/examples/service-eventarc-storage-sa-create.yaml @@ -0,0 +1,73 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +values: + module.cloud_run.google_cloud_run_v2_service.service[0]: + location: europe-west8 + name: hello + project: project-id + template: + - containers: + - args: null + command: null + depends_on: null + env: [] + image: us-docker.pkg.dev/cloudrun/container/hello + name: hello + volume_mounts: [] + working_dir: null + execution_environment: EXECUTION_ENVIRONMENT_GEN1 + volumes: [] + vpc_access: [] + + module.cloud_run.google_eventarc_trigger.storage_triggers["bucket-upload"]: + destination: + - cloud_run_service: + - path: /webhook + region: europe-west8 + service: hello + location: europe-west8 + matching_criteria: + - attribute: bucket + operator: '' + value: test-my-bucket + - attribute: type + operator: '' + value: google.cloud.storage.object.v1.finalized + name: storage-bucket-upload + project: project-id + + module.cloud_run.google_service_account.trigger_service_account[0]: + account_id: tf-cr-trigger-hello + description: null + disabled: false + display_name: Terraform trigger for Cloud Run hello. + project: project-id + timeouts: null + + module.cloud_run.google_cloud_run_v2_service_iam_member.default[0]: + condition: [] + member: serviceAccount:tf-cr-trigger-hello@project-id.iam.gserviceaccount.com + project: project-id + role: roles/run.invoker + +counts: + google_cloud_run_v2_service: 1 + google_cloud_run_v2_service_iam_member: 1 + google_eventarc_trigger: 1 + google_service_account: 1 + modules: 2 + resources: 6 + +outputs: {} diff --git a/tests/modules/cloud_run_v2/examples/service-eventarc-storage.yaml b/tests/modules/cloud_run_v2/examples/service-eventarc-storage.yaml new file mode 100644 index 000000000..e3da8d02d --- /dev/null +++ b/tests/modules/cloud_run_v2/examples/service-eventarc-storage.yaml @@ -0,0 +1,58 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +values: + module.cloud_run.google_cloud_run_v2_service.service[0]: + location: europe-west8 + name: hello + project: project-id + template: + - containers: + - args: null + command: null + depends_on: null + env: [] + image: us-docker.pkg.dev/cloudrun/container/hello + name: hello + volume_mounts: [] + working_dir: null + execution_environment: EXECUTION_ENVIRONMENT_GEN1 + volumes: [] + vpc_access: [] + + module.cloud_run.google_eventarc_trigger.storage_triggers["bucket-upload"]: + destination: + - cloud_run_service: + - path: /webhook + region: europe-west8 + service: hello + location: europe-west8 + matching_criteria: + - attribute: bucket + operator: '' + value: test-my-bucket + - attribute: type + operator: '' + value: google.cloud.storage.object.v1.finalized + name: storage-bucket-upload + project: project-id + service_account: null + +counts: + google_cloud_run_v2_service: 1 + google_eventarc_trigger: 1 + modules: 2 + resources: 4 + +outputs: {} From 1c46d3bcb572fe322fccdbc1213f3a66972297c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Niesiob=C4=99dzki?= Date: Tue, 29 Jul 2025 15:00:06 +0000 Subject: [PATCH 3/3] Disable E2E for dataproc on GKE --- modules/dataproc/README.md | 2 +- tests/fixtures/gke-cluster-standard.tf | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/dataproc/README.md b/modules/dataproc/README.md index 15bc157b6..17d124c05 100644 --- a/modules/dataproc/README.md +++ b/modules/dataproc/README.md @@ -242,7 +242,7 @@ module "processing-dp-cluster" { } } } -# tftest modules=5 resources=9 fixtures=fixtures/gke-cluster-standard.tf e2e +# tftest modules=5 resources=9 fixtures=fixtures/gke-cluster-standard.tf ``` ## IAM diff --git a/tests/fixtures/gke-cluster-standard.tf b/tests/fixtures/gke-cluster-standard.tf index 9de8a05a8..3b0425ca5 100644 --- a/tests/fixtures/gke-cluster-standard.tf +++ b/tests/fixtures/gke-cluster-standard.tf @@ -41,7 +41,8 @@ module "gke-cluster-standard" { kubelet_readonly_port_enabled = false } node_pool_auto_config = { - network_tags = ["foo"] # to avoid perma-diff + network_tags = ["foo"] # to avoid perma-diff + kubelet_readonly_port_enabled = false } }