From 3ac6ceac1e879450f1dfef8012f5703c1167f451 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Niesiob=C4=99dzki?= Date: Tue, 30 May 2023 14:49:14 +0000 Subject: [PATCH] Add trigger SA for Cloud Run --- modules/cloud-run/README.md | 83 +++++++++++++++---- modules/cloud-run/main.tf | 33 +++++++- modules/cloud-run/variables.tf | 4 +- .../trigger-service-account-external.yaml | 22 +++++ .../examples/trigger-service-account.yaml | 35 ++++++++ 5 files changed, 159 insertions(+), 18 deletions(-) create mode 100644 tests/modules/cloud_run/examples/trigger-service-account-external.yaml create mode 100644 tests/modules/cloud_run/examples/trigger-service-account.yaml diff --git a/modules/cloud-run/README.md b/modules/cloud-run/README.md index cfd4d7928..cd655a5f6 100644 --- a/modules/cloud-run/README.md +++ b/modules/cloud-run/README.md @@ -218,6 +218,57 @@ module "cloud_run" { # tftest modules=1 resources=2 inventory=audit-logs.yaml ``` +#### 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 Account 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. + +Example using provided service account: +```hcl +module "cloud_run" { + source = "./fabric/modules/cloud-run" + project_id = "my-project" + name = "hello" + containers = { + hello = { + image = "us-docker.pkg.dev/cloudrun/container/hello" + } + } + eventarc_triggers = { + audit_log = { + setiampolicy = { + method = "SetIamPolicy" + service = "cloudresourcemanager.googleapis.com" + } + } + service_account_email = "cloud-run-trigger@my-project.iam.gserviceaccount.com" + } +} +# tftest modules=1 resources=2 inventory=trigger-service-account-external.yaml +``` + +Example using automatically created service account: +```hcl +module "cloud_run" { + source = "./fabric/modules/cloud-run" + project_id = "my-project" + name = "hello" + containers = { + hello = { + image = "us-docker.pkg.dev/cloudrun/container/hello" + } + } + eventarc_triggers = { + pubsub = { + topic-1 = "topic1" + topic-2 = "topic2" + } + service_account_create = true + } +} +# tftest modules=1 resources=5 inventory=trigger-service-account.yaml +``` + + ### Service account To use a custom service account managed by the module, set `service_account_create` to `true` and leave `service_account` set to `null` value (default). @@ -259,24 +310,24 @@ module "cloud_run" { | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [name](variables.tf#L121) | Name used for cloud run service. | string | ✓ | | -| [project_id](variables.tf#L136) | Project id used for all resources. | string | ✓ | | +| [name](variables.tf#L123) | Name used for cloud run service. | string | ✓ | | +| [project_id](variables.tf#L138) | Project id used for all resources. | string | ✓ | | | [container_concurrency](variables.tf#L18) | Maximum allowed in-flight (concurrent) requests per container of the revision. | string | | null | | [containers](variables.tf#L24) | Containers in arbitrary key => attributes format. | map(object({…})) | | {} | -| [eventarc_triggers](variables.tf#L91) | Event arc triggers for different sources. | object({…}) | | {} | -| [iam](variables.tf#L103) | IAM bindings for Cloud Run service in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | -| [ingress_settings](variables.tf#L109) | Ingress settings. | string | | null | -| [labels](variables.tf#L115) | Resource labels. | map(string) | | {} | -| [prefix](variables.tf#L126) | Optional prefix used for resource names. | string | | null | -| [region](variables.tf#L141) | Region used for all resources. | string | | "europe-west1" | -| [revision_annotations](variables.tf#L147) | Configure revision template annotations. | object({…}) | | {} | -| [revision_name](variables.tf#L162) | Revision name. | string | | null | -| [service_account](variables.tf#L168) | Service account email. Unused if service account is auto-created. | string | | null | -| [service_account_create](variables.tf#L174) | Auto-create service account. | bool | | false | -| [timeout_seconds](variables.tf#L180) | Maximum duration the instance is allowed for responding to a request. | number | | null | -| [traffic](variables.tf#L186) | Traffic steering configuration. If revision name is null the latest revision will be used. | map(object({…})) | | {} | -| [volumes](variables.tf#L197) | Named volumes in containers in name => attributes format. | map(object({…})) | | {} | -| [vpc_connector_create](variables.tf#L211) | Populate this to create a VPC connector. You can then refer to it in the template annotations. | object({…}) | | null | +| [eventarc_triggers](variables.tf#L91) | Event arc triggers for different sources. | object({…}) | | {} | +| [iam](variables.tf#L105) | IAM bindings for Cloud Run service in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | +| [ingress_settings](variables.tf#L111) | Ingress settings. | string | | null | +| [labels](variables.tf#L117) | Resource labels. | map(string) | | {} | +| [prefix](variables.tf#L128) | Optional prefix used for resource names. | string | | null | +| [region](variables.tf#L143) | Region used for all resources. | string | | "europe-west1" | +| [revision_annotations](variables.tf#L149) | Configure revision template annotations. | object({…}) | | {} | +| [revision_name](variables.tf#L164) | Revision name. | string | | null | +| [service_account](variables.tf#L170) | Service account email. Unused if service account is auto-created. | string | | null | +| [service_account_create](variables.tf#L176) | Auto-create service account. | bool | | false | +| [timeout_seconds](variables.tf#L182) | Maximum duration the instance is allowed for responding to a request. | number | | null | +| [traffic](variables.tf#L188) | Traffic steering configuration. If revision name is null the latest revision will be used. | map(object({…})) | | {} | +| [volumes](variables.tf#L199) | Named volumes in containers in name => attributes format. | map(object({…})) | | {} | +| [vpc_connector_create](variables.tf#L213) | Populate this to create a VPC connector. You can then refer to it in the template annotations. | object({…}) | | null | ## Outputs diff --git a/modules/cloud-run/main.tf b/modules/cloud-run/main.tf index f2d8e327f..f982081be 100644 --- a/modules/cloud-run/main.tf +++ b/modules/cloud-run/main.tf @@ -35,6 +35,17 @@ locals { "run.googleapis.com/ingress" = var.ingress_settings } ) + _iam_run_invoker_members = concat( + lookup(var.iam, "roles/run.invoker", []), + var.eventarc_triggers.service_account_create ? ["serviceAccount:${local.trigger_service_account_email}"] : [] + ) + iam = merge( + var.iam, + length(local._iam_run_invoker_members) == 0 ? {} : + { + "roles/run.invoker" : local._iam_run_invoker_members + }, + ) prefix = var.prefix == null ? "" : "${var.prefix}-" revision_annotations = merge( try(var.revision_annotations.autoscaling, null) == null ? {} : { @@ -73,6 +84,17 @@ locals { ) : var.service_account ) + trigger_service_account_email = ( + var.eventarc_triggers.service_account_create + ? ( + length(google_service_account.trigger_service_account) > 0 + ? google_service_account.trigger_service_account[0].email + # : google_service_account.trigger_service_account[0].email # : null + : null + ) + : var.eventarc_triggers.service_account_email + ) + vpc_connector_create = var.vpc_connector_create != null } @@ -288,7 +310,7 @@ resource "google_cloud_run_service" "service" { } resource "google_cloud_run_service_iam_binding" "binding" { - for_each = var.iam + for_each = local.iam project = google_cloud_run_service.service.project location = google_cloud_run_service.service.location service = google_cloud_run_service.service.name @@ -326,6 +348,7 @@ resource "google_eventarc_trigger" "audit_log_triggers" { region = google_cloud_run_service.service.location } } + service_account = local.trigger_service_account_email } resource "google_eventarc_trigger" "pubsub_triggers" { @@ -348,4 +371,12 @@ resource "google_eventarc_trigger" "pubsub_triggers" { region = google_cloud_run_service.service.location } } + service_account = local.trigger_service_account_email +} + +resource "google_service_account" "trigger_service_account" { + count = var.eventarc_triggers.service_account_create ? 1 : 0 # coalesce(try(var.eventarc_triggers.service_account_create, false), false) ? 1 : 0 + project = var.project_id + account_id = "tf-cr-trigger-${var.name}" + display_name = "Terraform trigger for Cloud Run ${var.name}." } diff --git a/modules/cloud-run/variables.tf b/modules/cloud-run/variables.tf index afeeb4dde..69499c182 100644 --- a/modules/cloud-run/variables.tf +++ b/modules/cloud-run/variables.tf @@ -95,7 +95,9 @@ variable "eventarc_triggers" { method = string service = string })), {}) - pubsub = optional(map(string), {}) + pubsub = optional(map(string), {}) + service_account_email = optional(string) + service_account_create = optional(bool, false) }) default = {} } diff --git a/tests/modules/cloud_run/examples/trigger-service-account-external.yaml b/tests/modules/cloud_run/examples/trigger-service-account-external.yaml new file mode 100644 index 000000000..def9c89a2 --- /dev/null +++ b/tests/modules/cloud_run/examples/trigger-service-account-external.yaml @@ -0,0 +1,22 @@ +# 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.cloud_run.google_cloud_run_service.service: {} + module.cloud_run.google_eventarc_trigger.audit_log_triggers["setiampolicy"]: + service_account: cloud-run-trigger@my-project.iam.gserviceaccount.com + +counts: + google_cloud_run_service: 1 + google_eventarc_trigger: 1 diff --git a/tests/modules/cloud_run/examples/trigger-service-account.yaml b/tests/modules/cloud_run/examples/trigger-service-account.yaml new file mode 100644 index 000000000..86b1e1afa --- /dev/null +++ b/tests/modules/cloud_run/examples/trigger-service-account.yaml @@ -0,0 +1,35 @@ +# 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.cloud_run.google_cloud_run_service.service: {} + module.cloud_run.google_cloud_run_service_iam_binding.binding["roles/run.invoker"]: + project: my-project + role: roles/run.invoker + service: hello + # members: ["known after apply"] + module.cloud_run.google_eventarc_trigger.pubsub_triggers["topic-1"]: {} + # service_account: known after apply + module.cloud_run.google_eventarc_trigger.pubsub_triggers["topic-2"]: {} + # service_account: known after apply + module.cloud_run.google_service_account.trigger_service_account[0]: + account_id: tf-cr-trigger-hello + display_name: Terraform trigger for Cloud Run hello. + project: my-project + +counts: + google_cloud_run_service: 1 + google_cloud_run_service_iam_binding: 1 + google_eventarc_trigger: 2 + google_service_account: 1