diff --git a/modules/cloud-run-v2/README.md b/modules/cloud-run-v2/README.md index 330fd02584..631fa3b185 100644 --- a/modules/cloud-run-v2/README.md +++ b/modules/cloud-run-v2/README.md @@ -20,6 +20,7 @@ Cloud Run Services and Jobs, with support for IAM roles and Eventarc trigger cre - [Creating Cloud Run Jobs](#creating-cloud-run-jobs) - [Tag bindings](#tag-bindings) - [IAP Configuration](#iap-configuration) +- [Binary Authorization](#binary-authorization) - [Adding GPUs](#adding-gpus) - [Variables](#variables) - [Outputs](#outputs) @@ -881,6 +882,49 @@ module "cloud_run" { # tftest inventory=iap.yaml e2e ``` +## Binary Authorization + +Binary Authorization can be enabled on services, jobs and worker pools. Setting `use_default = true` opts the resource into the [project default policy](https://cloud.google.com/binary-authorization/docs/run/enabling-binauthz-cloud-run); use `policy` instead to attach a custom Cloud Run Binary Authorization policy by its full resource path. `breakglass_justification` bypasses Binary Authorization checks for the current revision and emits a high-severity audit log entry — only set it for ad-hoc breakglass deploys. + +```hcl +module "cloud_run" { + source = "./fabric/modules/cloud-run-v2" + project_id = var.project_id + name = "example-binauthz" + region = var.region + containers = { + hello = { + image = "us-docker.pkg.dev/cloudrun/container/hello" + } + } + binary_authorization = { + use_default = true + } + deletion_protection = false +} +# tftest inventory=binary-authorization.yaml e2e +``` + +```hcl +module "job" { + source = "./fabric/modules/cloud-run-v2" + project_id = var.project_id + name = "example-binauthz-job" + region = var.region + type = "JOB" + containers = { + hello = { + image = "us-docker.pkg.dev/cloudrun/container/hello" + } + } + binary_authorization = { + policy = "projects/${var.project_id}/platforms/cloudRun/policies/example-policy" + } + deletion_protection = false +} +# tftest inventory=binary-authorization-job.yaml +``` + ## Adding GPUs GPU support is available for all types of Cloud Run resources: jobs, services and worker pools. @@ -981,26 +1025,27 @@ module "worker" { | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [name](variables.tf#L182) | Name used for Cloud Run service. | string | ✓ | | -| [project_id](variables.tf#L187) | Project id used for all resources. | string | ✓ | | -| [region](variables.tf#L192) | Region used for all resources. | string | ✓ | | -| [containers](variables.tf#L17) | Containers in name => attributes format. | map(object({…})) | | {} | -| [context](variables.tf#L97) | Context-specific interpolations. | object({…}) | | {} | -| [deletion_protection](variables.tf#L119) | Deletion protection setting for this Cloud Run service. | string | | null | -| [encryption_key](variables.tf#L125) | The full resource name of the Cloud KMS CryptoKey. | string | | null | -| [iam](variables.tf#L131) | IAM bindings for Cloud Run service in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | -| [job_config](variables.tf#L137) | Cloud Run Job specific configuration. | object({…}) | | {} | -| [labels](variables.tf#L152) | Resource labels. | map(string) | | {} | -| [launch_stage](variables.tf#L158) | The launch stage as defined by Google Cloud Platform Launch Stages. | string | | null | -| [managed_revision](variables.tf#L175) | Whether the Terraform module should control the deployment of revisions. | bool | | true | -| [revision](variables.tf#L197) | Revision template configurations. | object({…}) | | {} | +| [name](variables.tf#L214) | Name used for Cloud Run service. | string | ✓ | | +| [project_id](variables.tf#L219) | Project id used for all resources. | string | ✓ | | +| [region](variables.tf#L224) | Region used for all resources. | string | ✓ | | +| [binary_authorization](variables.tf#L17) | Binary Authorization configuration. Applies to services, jobs and worker pools. Set `use_default = true` to enforce the project default policy, or `policy` to a custom Cloud Run policy resource path. `breakglass_justification` bypasses Binary Authorization checks for the resource and emits a high-severity audit log entry. | object({…}) | | null | +| [containers](variables.tf#L49) | Containers in name => attributes format. | map(object({…})) | | {} | +| [context](variables.tf#L129) | Context-specific interpolations. | object({…}) | | {} | +| [deletion_protection](variables.tf#L151) | Deletion protection setting for this Cloud Run service. | string | | null | +| [encryption_key](variables.tf#L157) | The full resource name of the Cloud KMS CryptoKey. | string | | null | +| [iam](variables.tf#L163) | IAM bindings for Cloud Run service in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | +| [job_config](variables.tf#L169) | Cloud Run Job specific configuration. | object({…}) | | {} | +| [labels](variables.tf#L184) | Resource labels. | map(string) | | {} | +| [launch_stage](variables.tf#L190) | The launch stage as defined by Google Cloud Platform Launch Stages. | string | | null | +| [managed_revision](variables.tf#L207) | Whether the Terraform module should control the deployment of revisions. | bool | | true | +| [revision](variables.tf#L229) | Revision template configurations. | object({…}) | | {} | | [service_account_config](variables-serviceaccount.tf#L17) | Service account configurations. | object({…}) | | {} | -| [service_config](variables.tf#L264) | Cloud Run service specific configuration options. | object({…}) | | {} | -| [tag_bindings](variables.tf#L327) | Tag bindings for this service, in key => tag value id format. | map(string) | | {} | -| [type](variables.tf#L334) | Type of Cloud Run resource to deploy: JOB, SERVICE or WORKERPOOL. | string | | "SERVICE" | -| [volumes](variables.tf#L344) | Named volumes in containers in name => attributes format. | map(object({…})) | | {} | +| [service_config](variables.tf#L296) | Cloud Run service specific configuration options. | object({…}) | | {} | +| [tag_bindings](variables.tf#L359) | Tag bindings for this service, in key => tag value id format. | map(string) | | {} | +| [type](variables.tf#L366) | Type of Cloud Run resource to deploy: JOB, SERVICE or WORKERPOOL. | string | | "SERVICE" | +| [volumes](variables.tf#L376) | Named volumes in containers in name => attributes format. | map(object({…})) | | {} | | [vpc_connector_create](variables-vpcconnector.tf#L17) | VPC connector network configuration. Must be provided if new VPC connector is being created. | object({…}) | | null | -| [workerpool_config](variables.tf#L378) | Cloud Run Worker Pool specific configuration. | object({…}) | | {} | +| [workerpool_config](variables.tf#L410) | Cloud Run Worker Pool specific configuration. | object({…}) | | {} | ## Outputs diff --git a/modules/cloud-run-v2/job-managed.tf b/modules/cloud-run-v2/job-managed.tf index c65578712e..30612573b5 100644 --- a/modules/cloud-run-v2/job-managed.tf +++ b/modules/cloud-run-v2/job-managed.tf @@ -23,6 +23,16 @@ resource "google_cloud_run_v2_job" "job" { labels = var.labels launch_stage = var.launch_stage deletion_protection = var.deletion_protection + + dynamic "binary_authorization" { + for_each = var.binary_authorization == null ? [] : [""] + content { + breakglass_justification = var.binary_authorization.breakglass_justification + policy = var.binary_authorization.policy + use_default = var.binary_authorization.use_default + } + } + template { labels = var.revision.labels task_count = var.job_config.task_count diff --git a/modules/cloud-run-v2/job-unmanaged.tf b/modules/cloud-run-v2/job-unmanaged.tf index 1961acad63..2ec65941ad 100644 --- a/modules/cloud-run-v2/job-unmanaged.tf +++ b/modules/cloud-run-v2/job-unmanaged.tf @@ -23,6 +23,16 @@ resource "google_cloud_run_v2_job" "job_unmanaged" { labels = var.labels launch_stage = var.launch_stage deletion_protection = var.deletion_protection + + dynamic "binary_authorization" { + for_each = var.binary_authorization == null ? [] : [""] + content { + breakglass_justification = var.binary_authorization.breakglass_justification + policy = var.binary_authorization.policy + use_default = var.binary_authorization.use_default + } + } + template { labels = var.revision.labels task_count = var.job_config.task_count diff --git a/modules/cloud-run-v2/service-managed.tf b/modules/cloud-run-v2/service-managed.tf index a6078c13d2..44c1812735 100644 --- a/modules/cloud-run-v2/service-managed.tf +++ b/modules/cloud-run-v2/service-managed.tf @@ -28,6 +28,15 @@ resource "google_cloud_run_v2_service" "service" { deletion_protection = var.deletion_protection iap_enabled = var.service_config.iap_config != null + dynamic "binary_authorization" { + for_each = var.binary_authorization == null ? [] : [""] + content { + breakglass_justification = var.binary_authorization.breakglass_justification + policy = var.binary_authorization.policy + use_default = var.binary_authorization.use_default + } + } + template { labels = var.revision.labels encryption_key = var.encryption_key diff --git a/modules/cloud-run-v2/service-unmanaged.tf b/modules/cloud-run-v2/service-unmanaged.tf index 033004330f..4782314536 100644 --- a/modules/cloud-run-v2/service-unmanaged.tf +++ b/modules/cloud-run-v2/service-unmanaged.tf @@ -28,6 +28,15 @@ resource "google_cloud_run_v2_service" "service_unmanaged" { deletion_protection = var.deletion_protection iap_enabled = var.service_config.iap_config != null + dynamic "binary_authorization" { + for_each = var.binary_authorization == null ? [] : [""] + content { + breakglass_justification = var.binary_authorization.breakglass_justification + policy = var.binary_authorization.policy + use_default = var.binary_authorization.use_default + } + } + template { labels = var.revision.labels encryption_key = var.encryption_key diff --git a/modules/cloud-run-v2/variables.tf b/modules/cloud-run-v2/variables.tf index 5d74fc09fc..f0043b7f0a 100644 --- a/modules/cloud-run-v2/variables.tf +++ b/modules/cloud-run-v2/variables.tf @@ -14,6 +14,38 @@ * limitations under the License. */ +variable "binary_authorization" { + description = "Binary Authorization configuration. Applies to services, jobs and worker pools. Set `use_default = true` to enforce the project default policy, or `policy` to a custom Cloud Run policy resource path. `breakglass_justification` bypasses Binary Authorization checks for the resource and emits a high-severity audit log entry." + type = object({ + breakglass_justification = optional(string) + policy = optional(string) + use_default = optional(bool, false) + }) + default = null + validation { + condition = ( + var.binary_authorization == null + ? true + : ( + var.binary_authorization.use_default + || var.binary_authorization.policy != null + ) + ) + error_message = "Either binary_authorization.use_default must be true or binary_authorization.policy must be set." + } + validation { + condition = ( + var.binary_authorization == null + ? true + : !( + var.binary_authorization.use_default + && var.binary_authorization.policy != null + ) + ) + error_message = "binary_authorization.use_default and binary_authorization.policy are mutually exclusive." + } +} + variable "containers" { description = "Containers in name => attributes format." type = map(object({ diff --git a/modules/cloud-run-v2/workerpool-managed.tf b/modules/cloud-run-v2/workerpool-managed.tf index 19bacb034d..535caf575f 100644 --- a/modules/cloud-run-v2/workerpool-managed.tf +++ b/modules/cloud-run-v2/workerpool-managed.tf @@ -24,6 +24,15 @@ resource "google_cloud_run_v2_worker_pool" "default_managed" { launch_stage = var.launch_stage deletion_protection = var.deletion_protection + dynamic "binary_authorization" { + for_each = var.binary_authorization == null ? [] : [""] + content { + breakglass_justification = var.binary_authorization.breakglass_justification + policy = var.binary_authorization.policy + use_default = var.binary_authorization.use_default + } + } + dynamic "scaling" { for_each = var.workerpool_config.scaling == null ? [] : [""] content { diff --git a/modules/cloud-run-v2/workerpool-unmanaged.tf b/modules/cloud-run-v2/workerpool-unmanaged.tf index 5f05eca58c..4e5f10ea27 100644 --- a/modules/cloud-run-v2/workerpool-unmanaged.tf +++ b/modules/cloud-run-v2/workerpool-unmanaged.tf @@ -24,6 +24,15 @@ resource "google_cloud_run_v2_worker_pool" "default_unmanaged" { launch_stage = var.launch_stage deletion_protection = var.deletion_protection + dynamic "binary_authorization" { + for_each = var.binary_authorization == null ? [] : [""] + content { + breakglass_justification = var.binary_authorization.breakglass_justification + policy = var.binary_authorization.policy + use_default = var.binary_authorization.use_default + } + } + dynamic "scaling" { for_each = var.workerpool_config.scaling == null ? [] : [""] content { diff --git a/tests/modules/cloud_run_v2/examples/binary-authorization-job.yaml b/tests/modules/cloud_run_v2/examples/binary-authorization-job.yaml new file mode 100644 index 0000000000..e084b18eba --- /dev/null +++ b/tests/modules/cloud_run_v2/examples/binary-authorization-job.yaml @@ -0,0 +1,87 @@ +# Copyright 2026 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. + +values: + module.job.google_cloud_run_v2_job.job[0]: + annotations: null + binary_authorization: + - breakglass_justification: null + policy: projects/project-id/platforms/cloudRun/policies/example-policy + use_default: false + client: null + client_version: null + deletion_policy: DELETE + deletion_protection: false + effective_labels: + goog-terraform-provisioned: 'true' + labels: null + location: europe-west8 + name: example-binauthz-job + project: project-id + run_execution_token: null + start_execution_token: null + template: + - annotations: null + labels: null + template: + - containers: + - args: null + command: null + depends_on: null + env: [] + image: us-docker.pkg.dev/cloudrun/container/hello + name: hello + ports: [] + volume_mounts: [] + working_dir: null + encryption_key: null + gpu_zonal_redundancy_disabled: null + max_retries: 3 + node_selector: [] + service_account: example-binauthz-job@project-id.iam.gserviceaccount.com + volumes: [] + vpc_access: [] + terraform_labels: + goog-terraform-provisioned: 'true' + timeouts: null + module.job.google_project_iam_member.default["roles/logging.logWriter"]: + condition: [] + member: serviceAccount:example-binauthz-job@project-id.iam.gserviceaccount.com + project: project-id + role: roles/logging.logWriter + module.job.google_project_iam_member.default["roles/monitoring.metricWriter"]: + condition: [] + member: serviceAccount:example-binauthz-job@project-id.iam.gserviceaccount.com + project: project-id + role: roles/monitoring.metricWriter + module.job.google_service_account.service_account[0]: + account_id: example-binauthz-job + create_ignore_already_exists: null + deletion_policy: DELETE + description: null + disabled: false + display_name: example-binauthz-job + email: example-binauthz-job@project-id.iam.gserviceaccount.com + member: serviceAccount:example-binauthz-job@project-id.iam.gserviceaccount.com + project: project-id + timeouts: null + +counts: + google_cloud_run_v2_job: 1 + google_project_iam_member: 2 + google_service_account: 1 + modules: 1 + resources: 4 + +outputs: {} diff --git a/tests/modules/cloud_run_v2/examples/binary-authorization.yaml b/tests/modules/cloud_run_v2/examples/binary-authorization.yaml new file mode 100644 index 0000000000..5f4d716119 --- /dev/null +++ b/tests/modules/cloud_run_v2/examples/binary-authorization.yaml @@ -0,0 +1,98 @@ +# Copyright 2026 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. + +values: + module.cloud_run.google_cloud_run_v2_service.service[0]: + annotations: null + binary_authorization: + - breakglass_justification: null + policy: null + use_default: true + build_config: [] + client: null + client_version: null + custom_audiences: null + default_uri_disabled: null + deletion_policy: DELETE + deletion_protection: false + description: null + effective_labels: + goog-terraform-provisioned: 'true' + iap_enabled: false + invoker_iam_disabled: false + labels: null + location: europe-west8 + multi_region_settings: [] + name: example-binauthz + project: project-id + template: + - annotations: null + containers: + - args: null + base_image_uri: null + command: null + depends_on: null + env: [] + image: us-docker.pkg.dev/cloudrun/container/hello + liveness_probe: [] + name: hello + readiness_probe: [] + source_code: [] + volume_mounts: [] + working_dir: null + encryption_key: null + execution_environment: EXECUTION_ENVIRONMENT_GEN1 + gpu_zonal_redundancy_disabled: null + health_check_disabled: null + labels: null + node_selector: [] + revision: null + service_account: example-binauthz@project-id.iam.gserviceaccount.com + service_mesh: [] + session_affinity: null + volumes: [] + vpc_access: [] + terraform_labels: + goog-terraform-provisioned: 'true' + timeouts: null + module.cloud_run.google_project_iam_member.default["roles/logging.logWriter"]: + condition: [] + member: serviceAccount:example-binauthz@project-id.iam.gserviceaccount.com + project: project-id + role: roles/logging.logWriter + module.cloud_run.google_project_iam_member.default["roles/monitoring.metricWriter"]: + condition: [] + member: serviceAccount:example-binauthz@project-id.iam.gserviceaccount.com + project: project-id + role: roles/monitoring.metricWriter + module.cloud_run.google_service_account.service_account[0]: + account_id: example-binauthz + create_ignore_already_exists: null + deletion_policy: DELETE + description: null + disabled: false + display_name: example-binauthz + email: example-binauthz@project-id.iam.gserviceaccount.com + member: serviceAccount:example-binauthz@project-id.iam.gserviceaccount.com + project: project-id + timeouts: null + +counts: + google_cloud_run_v2_service: 1 + google_project_iam_member: 2 + google_service_account: 1 + modules: 1 + resources: 4 + +outputs: {}