diff --git a/modules/job-exec/metadata.yaml b/modules/job-exec/metadata.yaml index 4df1fe92..ebe4468c 100644 --- a/modules/job-exec/metadata.yaml +++ b/modules/job-exec/metadata.yaml @@ -317,13 +317,13 @@ spec: roles: - level: Project roles: - - roles/run.admin - - roles/iam.serviceAccountAdmin - roles/artifactregistry.admin - roles/iam.serviceAccountUser - roles/serviceusage.serviceUsageViewer - roles/cloudkms.admin - roles/resourcemanager.projectIamAdmin + - roles/run.admin + - roles/iam.serviceAccountAdmin services: - accesscontextmanager.googleapis.com - cloudbilling.googleapis.com diff --git a/modules/secure-cloud-run-core/README.md b/modules/secure-cloud-run-core/README.md index 7f0db181..58a468af 100644 --- a/modules/secure-cloud-run-core/README.md +++ b/modules/secure-cloud-run-core/README.md @@ -37,43 +37,53 @@ module "cloud_run_core" { | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| argument | Arguments passed to the ENTRYPOINT command, include these only if image entrypoint needs arguments. | `list(string)` | `[]` | no | +| argument | Arguments passed to the ENTRYPOINT command. | `list(string)` | `[]` | no | | certificate\_mode | The mode of the certificate (NONE or AUTOMATIC). | `string` | `"NONE"` | no | -| cloud\_armor\_policies\_name | Cloud Armor policy name already created in the project. If `create_cloud_armor_policies` is `false`, this variable must be provided, If `create_cloud_armor_policies` is `true`, this variable will be ignored. | `string` | `null` | no | +| cloud\_armor\_policies\_name | Existing Cloud Armor policy name if create\_cloud\_armor\_policies is false. | `string` | `null` | no | +| cloud\_run\_deletion\_protection | This field prevents Terraform from destroying or recreating the Cloud Run v2 Jobs and Services | `bool` | `false` | no | | cloud\_run\_sa | Service account to be used on Cloud Run. | `string` | n/a | yes | -| container\_command | Leave blank to use the ENTRYPOINT command defined in the container image, include these only if image entrypoint should be overwritten. | `list(string)` | `[]` | no | +| container\_command | Container entrypoint command. | `list(string)` | `[]` | no | | container\_concurrency | Concurrent request limits to the service. | `number` | `null` | no | -| create\_cloud\_armor\_policies | When `true`, the terraform will create the Cloud Armor policies. When `false`, the user must provide their own Cloud Armor name in `cloud_armor_policies_name`. | `bool` | `true` | no | +| create\_cloud\_armor\_policies | When true, create Cloud Armor policies. When false, provide existing name. | `bool` | `true` | no | | default\_rules | Default rule for Cloud Armor. |
map(object({
action = string
priority = string
versioned_expr = string
src_ip_ranges = list(string)
description = string
})) | {
"default_rule": {
"action": "allow",
"description": "Default allow all rule",
"priority": "2147483647",
"src_ip_ranges": [
"*"
],
"versioned_expr": "SRC_IPS_V1"
}
} | no |
| domain\_map\_annotations | Annotations to the domain map. | `map(string)` | `{}` | no |
-| domain\_map\_labels | A set of key/value label pairs to assign to the Domain mapping. | `map(string)` | `{}` | no |
-| encryption\_key | CMEK encryption key self-link expected in the format projects/PROJECT/locations/LOCATION/keyRings/KEY-RING/cryptoKeys/CRYPTO-KEY. | `string` | n/a | yes |
+| domain\_map\_labels | Labels to assign to the Domain mapping. | `map(string)` | `{}` | no |
+| enable\_prometheus\_sidecar | Enable Prometheus sidecar in Cloud Run instance. | `bool` | `false` | no |
+| encryption\_key | CMEK encryption key self-link. | `string` | `null` | no |
| env\_vars | Environment variables. | list(object({
value = string
name = string
})) | `[]` | no |
+| execution\_environment | The execution environment (e.g., EXECUTION\_ENVIRONMENT\_GEN2, EXECUTION\_ENVIRONMENT\_GEN1). | `string` | `"EXECUTION_ENVIRONMENT_GEN2"` | no |
| force\_override | Option to force override existing mapping. | `bool` | `false` | no |
| generate\_revision\_name | Option to enable revision name generation. | `bool` | `true` | no |
+| gpu\_zonal\_redundancy\_disabled | True if GPU zonal redundancy is disabled on this revision. | `bool` | `false` | no |
+| iap\_members | Users/SAs to be given IAP access (if IAP is enabled). | `list(string)` | `[]` | no |
| image | GAR hosted image URL to deploy. | `string` | n/a | yes |
+| ingress | Ingress traffic sources allowed to call the service. | `string` | `"INGRESS_TRAFFIC_INTERNAL_LOAD_BALANCER"` | no |
+| launch\_stage | The launch stage as defined by Google Cloud Platform Launch Stages. Cloud Run supports ALPHA, BETA, and GA. If no value is specified, GA is assumed. | `string` | `"GA"` | no |
| lb\_name | Name for load balancer and associated resources. | `string` | `"tf-cr-lb"` | no |
-| limits | Resource limits to the container. | `map(string)` | `null` | no |
+| limits | Resource limits (memory, cpu, nvidia.com/gpu). | `map(string)` | `null` | no |
+| liveness\_probe | Configuration for the liveness probe. | object({
failure_threshold = optional(number)
initial_delay_seconds = optional(number)
timeout_seconds = optional(number)
period_seconds = optional(number)
http_get = optional(object({
path = optional(string)
port = optional(number)
http_headers = optional(list(object({
name = string
value = string
})))
}))
tcp_socket = optional(object({
port = number
}))
grpc = optional(object({
port = optional(number)
service = optional(string)
}))
}) | `null` | no |
| location | The location where resources are going to be deployed. | `string` | n/a | yes |
-| max\_scale\_instances | Sets the maximum number of container instances needed to handle all incoming requests or events from each revison from Cloud Run. For more information, access this [documentation](https://cloud.google.com/run/docs/about-instance-autoscaling). | `number` | `2` | no |
-| members | Users/SAs to be given invoker access to the service with the prefix `serviceAccount:' for SAs and `user:` for users.` | `list(string)` | `[]` | no |
-| min\_scale\_instances | Sets the minimum number of container instances needed to handle all incoming requests or events from each revison from Cloud Run. For more information, access this [documentation](https://cloud.google.com/run/docs/about-instance-autoscaling). | `number` | `1` | no |
-| owasp\_rules | These are additional Cloud Armor rules for SQLi, XSS, LFI, RCE, RFI, Scannerdetection, Protocolattack and Sessionfixation (requires Cloud Armor default\_rule). | map(object({
action = string
priority = string
expression = string
})) | {
"rule_canary": {
"action": "deny(403)",
"expression": "evaluatePreconfiguredExpr('rce-v33-stable')",
"priority": "1003"
},
"rule_lfi": {
"action": "deny(403)",
"expression": "evaluatePreconfiguredExpr('lfi-v33-stable')",
"priority": "1002"
},
"rule_protocolattack": {
"action": "deny(403)",
"expression": "evaluatePreconfiguredExpr('protocolattack-v33-stable')",
"priority": "1006"
},
"rule_rfi": {
"action": "deny(403)",
"expression": "evaluatePreconfiguredExpr('rfi-v33-stable')",
"priority": "1004"
},
"rule_scannerdetection": {
"action": "deny(403)",
"expression": "evaluatePreconfiguredExpr('scannerdetection-v33-stable')",
"priority": "1005"
},
"rule_sessionfixation": {
"action": "deny(403)",
"expression": "evaluatePreconfiguredExpr('sessionfixation-v33-stable')",
"priority": "1007"
},
"rule_sqli": {
"action": "deny(403)",
"expression": "evaluatePreconfiguredExpr('sqli-v33-stable')",
"priority": "1000"
},
"rule_xss": {
"action": "deny(403)",
"expression": "evaluatePreconfiguredExpr('xss-v33-stable')",
"priority": "1001"
}
} | no |
-| ports | Port which the container listens to (http1 or h2c). | object({
name = string
port = number
}) | {
"name": "http1",
"port": 8080
} | no |
+| max\_scale\_instances | Maximum number of container instances. | `number` | `100` | no |
+| members | Users/SAs to be given invoker access. | `list(string)` | `[]` | no |
+| min\_scale\_instances | Minimum number of container instances. | `number` | `0` | no |
+| node\_selector | Node Selector describes the hardware requirements of the GPU resource. [More info](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/cloud_run_v2_service#nested_template_node_selector). | object({
accelerator = string
}) | `null` | no |
+| owasp\_rules | Additional Cloud Armor rules (SQLi, XSS, etc). | map(object({
action = string
priority = string
expression = string
})) | {
"rule_canary": {
"action": "deny(403)",
"expression": "evaluatePreconfiguredExpr('rce-v33-stable')",
"priority": "1003"
},
"rule_lfi": {
"action": "deny(403)",
"expression": "evaluatePreconfiguredExpr('lfi-v33-stable')",
"priority": "1002"
},
"rule_protocolattack": {
"action": "deny(403)",
"expression": "evaluatePreconfiguredExpr('protocolattack-v33-stable')",
"priority": "1006"
},
"rule_rfi": {
"action": "deny(403)",
"expression": "evaluatePreconfiguredExpr('rfi-v33-stable')",
"priority": "1004"
},
"rule_scannerdetection": {
"action": "deny(403)",
"expression": "evaluatePreconfiguredExpr('scannerdetection-v33-stable')",
"priority": "1005"
},
"rule_sessionfixation": {
"action": "deny(403)",
"expression": "evaluatePreconfiguredExpr('sessionfixation-v33-stable')",
"priority": "1007"
},
"rule_sqli": {
"action": "deny(403)",
"expression": "evaluatePreconfiguredExpr('sqli-v33-stable')",
"priority": "1000"
},
"rule_xss": {
"action": "deny(403)",
"expression": "evaluatePreconfiguredExpr('xss-v33-stable')",
"priority": "1001"
}
} | no |
+| ports | Port which the container listens to. | object({
name = string
port = number
}) | {
"name": "http1",
"port": 8080
} | no |
| project\_id | The project where cloud run is going to be deployed. | `string` | n/a | yes |
-| region | Location for load balancer and Cloud Run resources. | `string` | n/a | yes |
-| requests | Resource requests to the container. | `map(string)` | `{}` | no |
-| service\_labels | A set of key/value label pairs to assign to the service. | `map(string)` | `{}` | no |
+| region | Location for load balancer and Cloud Run resources (usually same as location). | `string` | n/a | yes |
+| service\_labels | Labels to assign to the service. | `map(string)` | `{}` | no |
| service\_name | The name of the Cloud Run service to create. | `string` | n/a | yes |
-| ssl\_certificates | A object with a list of domains to auto-generate SSL certificates or a list of SSL Certificates self-links in the pattern `projects/object({
ssl_certificates_self_links = list(string)
generate_certificates_for_domains = list(string)
}) | n/a | yes |
-| template\_labels | A set of key/value label pairs to assign to the container metadata. | `map(string)` | `{}` | no |
-| timeout\_seconds | Timeout for each request. | `number` | `120` | no |
-| traffic\_split | Managing traffic routing to the service. | list(object({
latest_revision = bool
percent = number
revision_name = string
tag = string
})) | [| no | -| verified\_domain\_name | List of custom Domain Name. | `list(string)` | n/a | yes | -| volume\_mounts | [Beta] Volume Mounts to be attached to the container (when using secret). |
{
"latest_revision": true,
"percent": 100,
"revision_name": "v1-0-0",
"tag": null
}
]
list(object({
mount_path = string
name = string
})) | `[]` | no |
+| ssl\_certificates | A object with a list of domains to auto-generate SSL certificates or a list of SSL Certificates self-links. | object({
ssl_certificates_self_links = list(string)
generate_certificates_for_domains = list(string)
}) | n/a | yes |
+| startup\_probe | Configuration for the startup probe. | object({
failure_threshold = optional(number)
initial_delay_seconds = optional(number)
timeout_seconds = optional(number)
period_seconds = optional(number)
http_get = optional(object({
path = optional(string)
port = optional(number)
http_headers = optional(list(object({
name = string
value = string
})))
}))
tcp_socket = optional(object({
port = number
}))
grpc = optional(object({
port = optional(number)
service = optional(string)
}))
}) | `null` | no |
+| template\_labels | Labels to assign to the container metadata. | `map(string)` | `{}` | no |
+| timeout\_seconds | Timeout for each request in seconds. | `number` | `120` | no |
+| traffic\_split | Managing traffic routing to the service. | list(object({
latest_revision = optional(bool)
percent = number
revision_name = optional(string)
tag = optional(string)
})) | [| no | +| verified\_domain\_name | List of custom Domain Name. | `list(string)` | `[]` | no | +| volume\_mounts | Volume Mounts to be attached to the container. |
{
"latest_revision": true,
"percent": 100
}
]
list(object({
mount_path = string
name = string
})) | `[]` | no |
| volumes | [Beta] Volumes needed for environment variables (when using secret). | list(object({
name = string
secret = set(object({
secret_name = string
items = map(string)
}))
})) | `[]` | no |
-| vpc\_connector\_id | VPC Connector id in the format projects/PROJECT/locations/LOCATION/connectors/NAME. | `string` | n/a | yes |
-| vpc\_egress\_value | Sets VPC Egress firewall rule. Supported values are all-traffic, all (deprecated), and private-ranges-only. all-traffic and all provide the same functionality. all is deprecated but will continue to be supported. Prefer all-traffic. | `string` | `"private-ranges-only"` | no |
+| vpc\_connector\_id | VPC Connector id. If provided, Direct VPC Egress settings are ignored. | `string` | `null` | no |
+| vpc\_egress\_value | Sets VPC Egress firewall rule (e.g. PRIVATE\_RANGES\_ONLY, ALL\_TRAFFIC). | `string` | `"PRIVATE_RANGES_ONLY"` | no |
+| vpc\_network\_interface | List of network interfaces for Direct VPC Egress (Cloud Run v2). | object({
network = optional(string)
subnetwork = optional(string)
tags = optional(list(string))
}) | `null` | no |
## Outputs
diff --git a/modules/secure-cloud-run-core/main.tf b/modules/secure-cloud-run-core/main.tf
index 84127be9..e2d67eba 100644
--- a/modules/secure-cloud-run-core/main.tf
+++ b/modules/secure-cloud-run-core/main.tf
@@ -1,5 +1,5 @@
/**
- * Copyright 2022 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,74 +15,156 @@
*/
locals {
- annotations_for_template = {
- "autoscaling.knative.dev/maxScale" = var.max_scale_instances,
- "autoscaling.knative.dev/minScale" = var.min_scale_instances,
- "run.googleapis.com/vpc-access-connector" = var.vpc_connector_id,
- "run.googleapis.com/vpc-access-egress" = var.vpc_egress_value
- }
+ env_vars_map = { for item in var.env_vars : item.name => item.value }
+
+ main_container = {
+ container_name = var.service_name
+ container_image = var.image
+ container_command = var.container_command
+ container_args = var.argument
+ working_dir = null
+
+ ports = {
+ name = var.ports.name
+ container_port = var.ports.port
+ }
+
+ resources = {
+ limits = var.limits
+ cpu_idle = true
+ startup_cpu_boost = false
+ }
+
+ env_vars = local.env_vars_map
+ env_secret_vars = {}
+
+ startup_probe = var.startup_probe
+ liveness_probe = var.liveness_probe
- conditional_annotations = {
- secret = length(local.secrets_alias) == 0 ? {} : { "run.googleapis.com/secrets" = join(", ", toset(local.secrets_alias)) }
+ depends_on_container = []
+ volume_mounts = var.volume_mounts
}
- secrets = distinct(flatten([
- for secret in var.volumes : [
- for secret_name in secret.secret : [
- {
- "name" : secret.name,
- "secret_name" : secret_name.secret_name,
- "path" : secret_name.items.path
+ traffic_config = [
+ for t in var.traffic_split : {
+ percent = t.percent
+ type = null
+ revision = lookup(t, "latest_revision", true) ? null : lookup(t, "revision_name", null)
+ tag = lookup(t, "tag", null)
+ }
+ ]
+
+ volumes_config = [
+ for v in var.volumes : {
+ name = v.name
+
+ secret = length(v.secret) > 0 ? {
+ secret = v.secret[0].secret
+ default_mode = try(tostring(v.secret[0].default_mode), null)
+ items = length(try(v.secret[0].items, [])) > 0 ? {
+ path = v.secret[0].items[0].path
+ version = v.secret[0].items[0].version
+ mode = try(tostring(v.secret[0].items[0].mode), null)
+ } : null
+ } : null
+
+ cloud_sql_instance = length(v.cloud_sql_instance) > 0 ? {
+ instances = v.cloud_sql_instance[0].instances
+ } : null
+
+ gcs = length(v.gcs) > 0 ? {
+ bucket = v.gcs[0].bucket
+ read_only = try(tostring(v.gcs[0].read_only), null)
+ } : null
+
+ nfs = length(v.nfs) > 0 ? {
+ server = v.nfs[0].server
+ path = v.nfs[0].path
+ read_only = try(tostring(v.nfs[0].read_only), null)
+ } : null
+
+ empty_dir = length(v.empty_dir) > 0 ? {
+ medium = v.empty_dir[0].medium
+ size_limit = v.empty_dir[0].size_limit
+ } : null
+ }
+ ]
+
+ secrets_list = distinct(flatten([
+ for v in var.volumes : [
+ for s in v.secret : [
+ for item in(s.items != null ? s.items : []) : {
+ name = v.name
+ secret_name = s.secret
+ path = item.path
}
]
]
]))
- secrets_alias = [
- for secret in local.secrets :
- "${secret.name}:${secret.path}${secret.secret_name}"
- ]
+ vpc_config = var.vpc_connector_id != null ? {
+ connector = var.vpc_connector_id
+ egress = var.vpc_egress_value
+ network_interfaces = null
+ } : (var.vpc_network_interface != null ? {
+ connector = null
+ egress = var.vpc_egress_value
+ network_interfaces = var.vpc_network_interface
+ } : null)
}
module "cloud_run" {
- source = "../.."
-
- service_name = var.service_name
- project_id = var.project_id
- location = var.location
- image = var.image
- service_account_email = var.cloud_run_sa
- encryption_key = var.encryption_key
- members = var.members
- env_vars = var.env_vars
- generate_revision_name = var.generate_revision_name
- traffic_split = var.traffic_split
- service_labels = var.service_labels
- template_labels = var.template_labels
- container_concurrency = var.container_concurrency
- timeout_seconds = var.timeout_seconds
- volumes = var.volumes
- limits = var.limits
- requests = var.requests
- ports = var.ports
- argument = var.argument
- container_command = var.container_command
- volume_mounts = var.volume_mounts
+ source = "../v2"
+
+ project_id = var.project_id
+ service_name = var.service_name
+ location = var.location
+ description = "Managed by Terraform"
+
+ service_account = var.cloud_run_sa
+ create_service_account = false
+
+ containers = [local.main_container]
+
+ revision = var.generate_revision_name ? null : "${var.service_name}-rev"
+
+ template_scaling = {
+ min_instance_count = var.min_scale_instances
+ max_instance_count = var.max_scale_instances
+ }
+
+ vpc_access = local.vpc_config
+
+ ingress = var.ingress
+ execution_environment = var.execution_environment
+
+ volumes = local.volumes_config
+ encryption_key = var.encryption_key
+
+ service_labels = var.service_labels
+ template_labels = var.template_labels
+ service_annotations = {}
+ template_annotations = {}
+
+ timeout = "${var.timeout_seconds}s"
+ max_instance_request_concurrency = var.container_concurrency != null ? tostring(var.container_concurrency) : null
+
+ traffic = local.traffic_config
+
+ members = var.members
+ iap_members = var.iap_members
+ launch_stage = var.launch_stage
+ node_selector = var.node_selector
+ gpu_zonal_redundancy_disabled = var.gpu_zonal_redundancy_disabled
+ enable_prometheus_sidecar = var.enable_prometheus_sidecar
+ cloud_run_deletion_protection = var.cloud_run_deletion_protection
+
force_override = var.force_override
certificate_mode = var.certificate_mode
domain_map_labels = var.domain_map_labels
domain_map_annotations = var.domain_map_annotations
verified_domain_name = var.verified_domain_name
- service_annotations = {
- "run.googleapis.com/ingress" = "internal-and-cloud-load-balancing"
- }
-
- template_annotations = merge(
- local.annotations_for_template,
- local.conditional_annotations["secret"]
- )
-
depends_on = [
time_sleep.wait_30_seconds
]
@@ -103,8 +185,34 @@ resource "time_sleep" "wait_30_seconds" {
}
resource "google_secret_manager_secret_iam_member" "member" {
- for_each = { for secret in local.secrets : secret.name => secret }
- secret_id = "${each.value.path}${each.value.secret_name}"
+ for_each = { for s in local.secrets_list : "${s.name}-${s.path}" => s }
+ secret_id = each.value.secret_name
role = "roles/secretmanager.secretAccessor"
member = "serviceAccount:${var.cloud_run_sa}"
}
+
+resource "google_cloud_run_domain_mapping" "domain_map" {
+ for_each = toset(var.verified_domain_name)
+ provider = google-beta
+ location = var.location
+ name = each.value
+ project = var.project_id
+
+ metadata {
+ labels = var.domain_map_labels
+ annotations = var.domain_map_annotations
+ namespace = var.project_id
+ }
+
+ spec {
+ route_name = module.cloud_run.service_name
+ force_override = var.force_override
+ certificate_mode = var.certificate_mode
+ }
+
+ lifecycle {
+ ignore_changes = [
+ metadata[0].annotations["run.googleapis.com/operation-id"],
+ ]
+ }
+}
diff --git a/modules/secure-cloud-run-core/metadata.yaml b/modules/secure-cloud-run-core/metadata.yaml
index c66d7052..96434daa 100644
--- a/modules/secure-cloud-run-core/metadata.yaml
+++ b/modules/secure-cloud-run-core/metadata.yaml
@@ -56,12 +56,16 @@ spec:
location: examples/v2_with_iap
interfaces:
variables:
+ - name: project_id
+ description: The project where cloud run is going to be deployed.
+ varType: string
+ required: true
- name: location
description: The location where resources are going to be deployed.
varType: string
required: true
- - name: project_id
- description: The project where cloud run is going to be deployed.
+ - name: region
+ description: Location for load balancer and Cloud Run resources (usually same as location).
varType: string
required: true
- name: service_name
@@ -76,18 +80,127 @@ spec:
description: Service account to be used on Cloud Run.
varType: string
required: true
+ - name: execution_environment
+ description: The execution environment (e.g., EXECUTION_ENVIRONMENT_GEN2, EXECUTION_ENVIRONMENT_GEN1).
+ varType: string
+ defaultValue: EXECUTION_ENVIRONMENT_GEN2
+ - name: env_vars
+ description: Environment variables.
+ varType: |-
+ list(object({
+ value = string
+ name = string
+ }))
+ defaultValue: []
+ - name: ports
+ description: Port which the container listens to.
+ varType: |-
+ object({
+ name = string
+ port = number
+ })
+ defaultValue:
+ name: http1
+ port: 8080
+ - name: argument
+ description: Arguments passed to the ENTRYPOINT command.
+ varType: list(string)
+ defaultValue: []
+ - name: container_command
+ description: Container entrypoint command.
+ varType: list(string)
+ defaultValue: []
+ - name: limits
+ description: Resource limits (memory, cpu, nvidia.com/gpu).
+ varType: map(string)
+ - name: container_concurrency
+ description: Concurrent request limits to the service.
+ varType: number
+ - name: timeout_seconds
+ description: Timeout for each request in seconds.
+ varType: number
+ defaultValue: 120
+ - name: startup_probe
+ description: Configuration for the startup probe.
+ varType: |-
+ object({
+ failure_threshold = optional(number)
+ initial_delay_seconds = optional(number)
+ timeout_seconds = optional(number)
+ period_seconds = optional(number)
+ http_get = optional(object({
+ path = optional(string)
+ port = optional(number)
+ http_headers = optional(list(object({
+ name = string
+ value = string
+ })))
+ }))
+ tcp_socket = optional(object({
+ port = number
+ }))
+ grpc = optional(object({
+ port = optional(number)
+ service = optional(string)
+ }))
+ })
+ - name: liveness_probe
+ description: Configuration for the liveness probe.
+ varType: |-
+ object({
+ failure_threshold = optional(number)
+ initial_delay_seconds = optional(number)
+ timeout_seconds = optional(number)
+ period_seconds = optional(number)
+ http_get = optional(object({
+ path = optional(string)
+ port = optional(number)
+ http_headers = optional(list(object({
+ name = string
+ value = string
+ })))
+ }))
+ tcp_socket = optional(object({
+ port = number
+ }))
+ grpc = optional(object({
+ port = optional(number)
+ service = optional(string)
+ }))
+ })
+ - name: ingress
+ description: Ingress traffic sources allowed to call the service.
+ varType: string
+ defaultValue: INGRESS_TRAFFIC_INTERNAL_LOAD_BALANCER
- name: vpc_connector_id
- description: VPC Connector id in the format projects/PROJECT/locations/LOCATION/connectors/NAME.
+ description: VPC Connector id. If provided, Direct VPC Egress settings are ignored.
varType: string
- required: true
+ - name: vpc_egress_value
+ description: Sets VPC Egress firewall rule (e.g. PRIVATE_RANGES_ONLY, ALL_TRAFFIC).
+ varType: string
+ defaultValue: PRIVATE_RANGES_ONLY
+ - name: vpc_network_interface
+ description: List of network interfaces for Direct VPC Egress (Cloud Run v2).
+ varType: |-
+ object({
+ network = optional(string)
+ subnetwork = optional(string)
+ tags = optional(list(string))
+ })
- name: encryption_key
- description: CMEK encryption key self-link expected in the format projects/PROJECT/locations/LOCATION/keyRings/KEY-RING/cryptoKeys/CRYPTO-KEY.
+ description: CMEK encryption key self-link.
varType: string
- required: true
- - name: region
- description: Location for load balancer and Cloud Run resources.
+ - name: lb_name
+ description: Name for load balancer and associated resources.
+ varType: string
+ defaultValue: tf-cr-lb
+ - name: create_cloud_armor_policies
+ description: When true, create Cloud Armor policies. When false, provide existing name.
+ varType: bool
+ defaultValue: true
+ - name: cloud_armor_policies_name
+ description: Existing Cloud Armor policy name if create_cloud_armor_policies is false.
varType: string
- required: true
- name: default_rules
description: Default rule for Cloud Armor.
varType: |-
@@ -107,7 +220,7 @@ spec:
- "*"
versioned_expr: SRC_IPS_V1
- name: owasp_rules
- description: These are additional Cloud Armor rules for SQLi, XSS, LFI, RCE, RFI, Scannerdetection, Protocolattack and Sessionfixation (requires Cloud Armor default_rule).
+ description: Additional Cloud Armor rules (SQLi, XSS, etc).
varType: |-
map(object({
action = string
@@ -147,103 +260,77 @@ spec:
action: deny(403)
expression: evaluatePreconfiguredExpr('xss-v33-stable')
priority: "1001"
- - name: lb_name
- description: Name for load balancer and associated resources.
- varType: string
- defaultValue: tf-cr-lb
- - name: env_vars
- description: Environment variables.
+ - name: ssl_certificates
+ description: A object with a list of domains to auto-generate SSL certificates or a list of SSL Certificates self-links.
+ varType: |-
+ object({
+ ssl_certificates_self_links = list(string)
+ generate_certificates_for_domains = list(string)
+ })
+ required: true
+ - name: volume_mounts
+ description: Volume Mounts to be attached to the container.
varType: |-
list(object({
- value = string
- name = string
+ mount_path = string
+ name = string
}))
defaultValue: []
- - name: members
- description: Users/SAs to be given invoker access to the service with the prefix `serviceAccount:' for SAs and `user:` for users.
- varType: list(string)
+ - name: volumes
+ description: "[Beta] Volumes needed for environment variables (when using secret)."
+ varType: |-
+ list(object({
+ name = string
+ secret = set(object({
+ secret_name = string
+ items = map(string)
+ }))
+ }))
defaultValue: []
- name: generate_revision_name
description: Option to enable revision name generation.
varType: bool
defaultValue: true
+ - name: min_scale_instances
+ description: Minimum number of container instances.
+ varType: number
+ defaultValue: 0
+ - name: max_scale_instances
+ description: Maximum number of container instances.
+ varType: number
+ defaultValue: 100
- name: traffic_split
description: Managing traffic routing to the service.
varType: |-
list(object({
- latest_revision = bool
+ latest_revision = optional(bool)
percent = number
- revision_name = string
- tag = string
+ revision_name = optional(string)
+ tag = optional(string)
}))
defaultValue:
- latest_revision: true
percent: 100
- revision_name: v1-0-0
- tag: null
+ - name: members
+ description: Users/SAs to be given invoker access.
+ varType: list(string)
+ defaultValue: []
+ - name: iap_members
+ description: Users/SAs to be given IAP access (if IAP is enabled).
+ varType: list(string)
+ defaultValue: []
- name: service_labels
- description: A set of key/value label pairs to assign to the service.
+ description: Labels to assign to the service.
varType: map(string)
defaultValue: {}
- name: template_labels
- description: A set of key/value label pairs to assign to the container metadata.
+ description: Labels to assign to the container metadata.
varType: map(string)
defaultValue: {}
- - name: container_concurrency
- description: Concurrent request limits to the service.
- varType: number
- - name: timeout_seconds
- description: Timeout for each request.
- varType: number
- defaultValue: 120
- - name: volumes
- description: "[Beta] Volumes needed for environment variables (when using secret)."
- varType: |-
- list(object({
- name = string
- secret = set(object({
- secret_name = string
- items = map(string)
- }))
- }))
- defaultValue: []
- - name: limits
- description: Resource limits to the container.
- varType: map(string)
- - name: requests
- description: Resource requests to the container.
- varType: map(string)
- defaultValue: {}
- - name: ports
- description: Port which the container listens to (http1 or h2c).
- varType: |-
- object({
- name = string
- port = number
- })
- defaultValue:
- name: http1
- port: 8080
- - name: argument
- description: Arguments passed to the ENTRYPOINT command, include these only if image entrypoint needs arguments.
- varType: list(string)
- defaultValue: []
- - name: container_command
- description: Leave blank to use the ENTRYPOINT command defined in the container image, include these only if image entrypoint should be overwritten.
- varType: list(string)
- defaultValue: []
- - name: volume_mounts
- description: "[Beta] Volume Mounts to be attached to the container (when using secret)."
- varType: |-
- list(object({
- mount_path = string
- name = string
- }))
- defaultValue: []
- name: verified_domain_name
description: List of custom Domain Name.
varType: list(string)
- required: true
+ defaultValue: []
- name: force_override
description: Option to force override existing mapping.
varType: bool
@@ -253,40 +340,35 @@ spec:
varType: string
defaultValue: NONE
- name: domain_map_labels
- description: A set of key/value label pairs to assign to the Domain mapping.
+ description: Labels to assign to the Domain mapping.
varType: map(string)
defaultValue: {}
- name: domain_map_annotations
description: Annotations to the domain map.
varType: map(string)
defaultValue: {}
- - name: create_cloud_armor_policies
- description: When `true`, the terraform will create the Cloud Armor policies. When `false`, the user must provide their own Cloud Armor name in `cloud_armor_policies_name`.
+ - name: cloud_run_deletion_protection
+ description: This field prevents Terraform from destroying or recreating the Cloud Run v2 Jobs and Services
varType: bool
- defaultValue: true
- - name: cloud_armor_policies_name
- description: Cloud Armor policy name already created in the project. If `create_cloud_armor_policies` is `false`, this variable must be provided, If `create_cloud_armor_policies` is `true`, this variable will be ignored.
- varType: string
- - name: max_scale_instances
- description: Sets the maximum number of container instances needed to handle all incoming requests or events from each revison from Cloud Run. For more information, access this [documentation](https://cloud.google.com/run/docs/about-instance-autoscaling).
- varType: number
- defaultValue: 2
- - name: min_scale_instances
- description: Sets the minimum number of container instances needed to handle all incoming requests or events from each revison from Cloud Run. For more information, access this [documentation](https://cloud.google.com/run/docs/about-instance-autoscaling).
- varType: number
- defaultValue: 1
- - name: vpc_egress_value
- description: Sets VPC Egress firewall rule. Supported values are all-traffic, all (deprecated), and private-ranges-only. all-traffic and all provide the same functionality. all is deprecated but will continue to be supported. Prefer all-traffic.
- varType: string
- defaultValue: private-ranges-only
- - name: ssl_certificates
- description: A object with a list of domains to auto-generate SSL certificates or a list of SSL Certificates self-links in the pattern `projects/list(object({
value = string
name = string
})) | `[]` | no |
| folder\_id | The folder ID to apply the policy to. | `string` | `""` | no |
+| gpu\_zonal\_redundancy\_disabled | True if GPU zonal redundancy is disabled on this revision. | `bool` | `false` | no |
| grant\_artifact\_register\_reader | When true it will grant permission to read an image from your artifact registry. When true, you must provide `artifact_registry_repository_project_id`, `artifact_registry_repository_location` and `artifact_registry_repository_name`. | `bool` | `false` | no |
| groups | Groups which will have roles assigned.object({
group_serverless_administrator = optional(string, null)
group_serverless_security_administrator = optional(string, null)
group_cloud_run_developer = optional(string, null)
group_cloud_run_user = optional(string, null)
}) | `{}` | no |
+| iap\_members | Valid only when launch stage is set to 'BETA'. IAP is enabled automatically when users or service accounts (SAs) are provided. Use allUsers for public access, allAuthenticatedUsers for any Google-authenticated user, or specify individual users/SAs. [More info](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/iap_web_cloud_run_service_iam#member/members-2) | `list(string)` | `[]` | no |
| image | Image url to be deployed on Cloud Run. | `string` | n/a | yes |
| ip\_cidr\_range | The range of internal addresses that are owned by the subnetwork and which is going to be used by VPC Connector. For example, 10.0.0.0/28 or 192.168.0.0/28. Ranges must be unique and non-overlapping within a network. Only IPv4 is supported. | `string` | n/a | yes |
| key\_name | The name of KMS Key to be created and used in Cloud Run. | `string` | `"cloud-run-kms-key"` | no |
@@ -97,12 +102,15 @@ module "secure_cloud_run" {
| key\_rotation\_period | Period of key rotation in seconds. | `string` | `"2592000s"` | no |
| keyring\_name | Keyring name. | `string` | `"cloud-run-kms-keyring"` | no |
| kms\_project\_id | The project where KMS will be created. | `string` | n/a | yes |
+| launch\_stage | The launch stage as defined by Google Cloud Platform Launch Stages. Cloud Run supports ALPHA, BETA, and GA. If no value is specified, GA is assumed. | `string` | `"GA"` | no |
| location | The location where resources are going to be deployed. | `string` | n/a | yes |
| max\_scale\_instances | Sets the maximum number of container instances needed to handle all incoming requests or events from each revison from Cloud Run. For more information, access this [documentation](https://cloud.google.com/run/docs/about-instance-autoscaling). | `number` | `2` | no |
| members | Users/SAs to be given invoker access to the service with the prefix `serviceAccount:' for SAs and `user:` for users.` | `list(string)` | `[]` | no |
| min\_scale\_instances | Sets the minimum number of container instances needed to handle all incoming requests or events from each revison from Cloud Run. For more information, access this [documentation](https://cloud.google.com/run/docs/about-instance-autoscaling). | `number` | `1` | no |
+| node\_selector | Node Selector describes the hardware requirements of the GPU resource. [More info](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/cloud_run_v2_service#nested_template_node_selector). | object({
accelerator = string
}) | `null` | no |
| organization\_id | The organization ID to apply the policy to. | `string` | `""` | no |
| policy\_for | Policy Root: set one of the following values to determine where the policy is applied. Possible values: ["project", "folder", "organization"]. | `string` | `"project"` | no |
+| ports | Port which the container listens to. | object({
name = string
port = number
}) | {
"name": "http1",
"port": 8080
} | no |
| prevent\_destroy | Set the `prevent_destroy` lifecycle attribute on the Cloud KMS key. | `bool` | `true` | no |
| region | Location for load balancer and Cloud Run resources. | `string` | n/a | yes |
| resource\_names\_suffix | A suffix to concat in the end of the network resources names being created. | `string` | `null` | no |
@@ -113,7 +121,8 @@ module "secure_cloud_run" {
| subnet\_name | Subnet name to be re-used to create Serverless Connector. | `string` | `null` | no |
| verified\_domain\_name | List of Custom Domain Name | `list(string)` | `[]` | no |
| volumes | [Beta] Volumes needed for environment variables (when using secret). | list(object({
name = string
secret = set(object({
secret_name = string
items = map(string)
}))
})) | `[]` | no |
-| vpc\_egress\_value | Sets VPC Egress firewall rule. Supported values are all-traffic, all (deprecated), and private-ranges-only. all-traffic and all provide the same functionality. all is deprecated but will continue to be supported. Prefer all-traffic. | `string` | `"private-ranges-only"` | no |
+| vpc\_egress\_value | Sets VPC Egress firewall rule. Supported values are ALL\_TRAFFIC, ALL (deprecated), and PRIVATE\_RANGES\_ONLY. all-traffic and all provide the same functionality. all is deprecated but will continue to be supported. Prefer all-traffic. | `string` | `"PRIVATE_RANGES_ONLY"` | no |
+| vpc\_network\_interface | List of network interfaces for Direct VPC Egress (Cloud Run v2). | object({
network = optional(string)
subnetwork = optional(string)
tags = optional(list(string))
}) | `null` | no |
| vpc\_project\_id | The host project for the shared vpc. | `string` | n/a | yes |
## Outputs
diff --git a/modules/secure-cloud-run/main.tf b/modules/secure-cloud-run/main.tf
index 9d3a75e3..ad90756e 100644
--- a/modules/secure-cloud-run/main.tf
+++ b/modules/secure-cloud-run/main.tf
@@ -127,24 +127,34 @@ resource "google_project_iam_member" "serverless_service_agent" {
module "cloud_run_core" {
source = "../secure-cloud-run-core"
- service_name = var.service_name
- location = var.location
- project_id = var.serverless_project_id
- image = var.image
- cloud_run_sa = var.cloud_run_sa
- vpc_connector_id = module.cloud_run_network.connector_id
- encryption_key = module.cloud_run_security.key_self_link
- env_vars = var.env_vars
- members = var.members
- region = var.region
- verified_domain_name = var.verified_domain_name
- create_cloud_armor_policies = var.create_cloud_armor_policies
- cloud_armor_policies_name = var.cloud_armor_policies_name
- vpc_egress_value = var.vpc_egress_value
- min_scale_instances = var.min_scale_instances
- max_scale_instances = var.max_scale_instances
- volumes = var.volumes
- ssl_certificates = var.ssl_certificates
+ service_name = var.service_name
+ location = var.location
+ project_id = var.serverless_project_id
+ image = var.image
+ cloud_run_sa = var.cloud_run_sa
+ vpc_connector_id = module.cloud_run_network.connector_id
+ encryption_key = module.cloud_run_security.key_self_link
+ env_vars = var.env_vars
+ members = var.members
+ region = var.region
+ verified_domain_name = var.verified_domain_name
+ create_cloud_armor_policies = var.create_cloud_armor_policies
+ cloud_armor_policies_name = var.cloud_armor_policies_name
+ vpc_egress_value = var.vpc_egress_value
+ min_scale_instances = var.min_scale_instances
+ max_scale_instances = var.max_scale_instances
+ volumes = var.volumes
+ ssl_certificates = var.ssl_certificates
+ vpc_network_interface = var.vpc_network_interface
+ iap_members = var.iap_members
+ launch_stage = var.launch_stage
+ node_selector = var.node_selector
+ gpu_zonal_redundancy_disabled = var.gpu_zonal_redundancy_disabled
+ enable_prometheus_sidecar = var.enable_prometheus_sidecar
+ cloud_run_deletion_protection = var.cloud_run_deletion_protection
+ argument = var.argument
+ ports = var.ports
+
depends_on = [
module.serverless_project_apis,
diff --git a/modules/secure-cloud-run/metadata.yaml b/modules/secure-cloud-run/metadata.yaml
index f648489e..22ff11e8 100644
--- a/modules/secure-cloud-run/metadata.yaml
+++ b/modules/secure-cloud-run/metadata.yaml
@@ -176,9 +176,9 @@ spec:
varType: number
defaultValue: 1
- name: vpc_egress_value
- description: Sets VPC Egress firewall rule. Supported values are all-traffic, all (deprecated), and private-ranges-only. all-traffic and all provide the same functionality. all is deprecated but will continue to be supported. Prefer all-traffic.
+ description: Sets VPC Egress firewall rule. Supported values are ALL_TRAFFIC, ALL (deprecated), and PRIVATE_RANGES_ONLY. all-traffic and all provide the same functionality. all is deprecated but will continue to be supported. Prefer all-traffic.
varType: string
- defaultValue: private-ranges-only
+ defaultValue: PRIVATE_RANGES_ONLY
- name: create_cloud_armor_policies
description: When `true`, the terraform will create the Cloud Armor policies. When `false`, the user must provide their own Cloud Armor name in `cloud_armor_policies_name`.
varType: bool
@@ -219,6 +219,54 @@ spec:
generate_certificates_for_domains = list(string)
})
required: true
+ - name: vpc_network_interface
+ description: List of network interfaces for Direct VPC Egress (Cloud Run v2).
+ varType: |-
+ object({
+ network = optional(string)
+ subnetwork = optional(string)
+ tags = optional(list(string))
+ })
+ - name: cloud_run_deletion_protection
+ description: This field prevents Terraform from destroying or recreating the Cloud Run v2 Jobs and Services
+ varType: bool
+ defaultValue: false
+ - name: enable_prometheus_sidecar
+ description: Enable Prometheus sidecar in Cloud Run instance.
+ varType: bool
+ defaultValue: false
+ - name: gpu_zonal_redundancy_disabled
+ description: True if GPU zonal redundancy is disabled on this revision.
+ varType: bool
+ defaultValue: false
+ - name: node_selector
+ description: Node Selector describes the hardware requirements of the GPU resource. [More info](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/cloud_run_v2_service#nested_template_node_selector).
+ varType: |-
+ object({
+ accelerator = string
+ })
+ - name: launch_stage
+ description: The launch stage as defined by Google Cloud Platform Launch Stages. Cloud Run supports ALPHA, BETA, and GA. If no value is specified, GA is assumed.
+ varType: string
+ defaultValue: GA
+ - name: iap_members
+ description: Valid only when launch stage is set to 'BETA'. IAP is enabled automatically when users or service accounts (SAs) are provided. Use allUsers for public access, allAuthenticatedUsers for any Google-authenticated user, or specify individual users/SAs. [More info](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/iap_web_cloud_run_service_iam#member\/members-2)
+ varType: list(string)
+ defaultValue: []
+ - name: argument
+ description: Arguments passed to the ENTRYPOINT command, include these only if image entrypoint needs arguments.
+ varType: list(string)
+ defaultValue: []
+ - name: ports
+ description: Port which the container listens to.
+ varType: |-
+ object({
+ name = string
+ port = number
+ })
+ defaultValue:
+ name: http1
+ port: 8080
outputs:
- name: cloud_services_sa
description: Service Account for Cloud Run Service.
@@ -250,13 +298,13 @@ spec:
roles:
- level: Project
roles:
+ - roles/run.admin
- roles/iam.serviceAccountAdmin
- roles/artifactregistry.admin
- roles/iam.serviceAccountUser
- roles/serviceusage.serviceUsageViewer
- roles/cloudkms.admin
- roles/resourcemanager.projectIamAdmin
- - roles/run.admin
services:
- accesscontextmanager.googleapis.com
- cloudbilling.googleapis.com
diff --git a/modules/secure-cloud-run/variables.tf b/modules/secure-cloud-run/variables.tf
index 406fe31e..8ad5151c 100644
--- a/modules/secure-cloud-run/variables.tf
+++ b/modules/secure-cloud-run/variables.tf
@@ -188,9 +188,9 @@ variable "min_scale_instances" {
}
variable "vpc_egress_value" {
- description = "Sets VPC Egress firewall rule. Supported values are all-traffic, all (deprecated), and private-ranges-only. all-traffic and all provide the same functionality. all is deprecated but will continue to be supported. Prefer all-traffic."
+ description = "Sets VPC Egress firewall rule. Supported values are ALL_TRAFFIC, ALL (deprecated), and PRIVATE_RANGES_ONLY. all-traffic and all provide the same functionality. all is deprecated but will continue to be supported. Prefer all-traffic."
type = string
- default = "private-ranges-only"
+ default = "PRIVATE_RANGES_ONLY"
}
variable "create_cloud_armor_policies" {
@@ -254,3 +254,75 @@ variable "ssl_certificates" {
}
description = "A object with a list of domains to auto-generate SSL certificates or a list of SSL Certificates self-links in the pattern `projects/object({
breakglass_justification = optional(bool) # If present, indicates to use Breakglass using this justification. If useDefault is False, then it must be empty. For more information on breakglass, [see](https://cloud.google.com/binary-authorization/docs/using-breakglass)
use_default = optional(bool) #If True, indicates to use the default project's binary authorization policy. If False, binary authorization will be disabled.
}) | `null` | no |
+| certificate\_mode | The mode of the certificate (NONE or AUTOMATIC). | `string` | `"NONE"` | no |
| client | Arbitrary identifier for the API client and version identifier | object({
name = optional(string, null)
version = optional(string, null)
}) | `{}` | no |
| cloud\_run\_deletion\_protection | This field prevents Terraform from destroying or recreating the Cloud Run jobs and services | `bool` | `true` | no |
| containers | Container images for the service | list(object({
container_name = optional(string, null)
container_image = string
working_dir = optional(string, null)
depends_on_container = optional(list(string), null)
container_args = optional(list(string), null)
container_command = optional(list(string), null)
env_vars = optional(map(string), {})
env_secret_vars = optional(map(object({
secret = string
version = string
})), {})
volume_mounts = optional(list(object({
name = string
mount_path = string
})), [])
ports = optional(object({
name = optional(string, "http1")
container_port = optional(number, 8080)
}), {})
resources = optional(object({
limits = optional(object({
cpu = optional(string)
memory = optional(string)
nvidia_gpu = optional(string)
}))
cpu_idle = optional(bool, true)
startup_cpu_boost = optional(bool, false)
}), {})
startup_probe = optional(object({
failure_threshold = optional(number, null)
initial_delay_seconds = optional(number, null)
timeout_seconds = optional(number, null)
period_seconds = optional(number, null)
http_get = optional(object({
path = optional(string)
port = optional(string)
http_headers = optional(list(object({
name = string
value = string
})), [])
}), null)
tcp_socket = optional(object({
port = optional(number)
}), null)
grpc = optional(object({
port = optional(number)
service = optional(string)
}), null)
}), null)
liveness_probe = optional(object({
failure_threshold = optional(number, null)
initial_delay_seconds = optional(number, null)
timeout_seconds = optional(number, null)
period_seconds = optional(number, null)
http_get = optional(object({
path = optional(string)
port = optional(string)
http_headers = optional(list(object({
name = string
value = string
})), [])
}), null)
tcp_socket = optional(object({
port = optional(number)
}), null)
grpc = optional(object({
port = optional(number)
service = optional(string)
}), null)
}), null)
})) | n/a | yes |
| create\_service\_account | Create a new service account for cloud run service | `bool` | `true` | no |
| custom\_audiences | One or more custom audiences that you want this service to support. Specify each custom audience as the full URL in a string. [Refer](https://cloud.google.com/run/docs/configuring/custom-audiences) | `list(string)` | `null` | no |
| description | Cloud Run service description. This field currently has a 512-character limit. | `string` | `null` | no |
+| domain\_map\_annotations | Annotations to the domain map. | `map(string)` | `{}` | no |
+| domain\_map\_labels | A set of key/value label pairs to assign to the Domain mapping. | `map(string)` | `{}` | no |
| enable\_prometheus\_sidecar | Enable Prometheus sidecar in Cloud Run instance. | `bool` | `false` | no |
| encryption\_key | A reference to a customer managed encryption key (CMEK) to use to encrypt this container image. This is optional. | `string` | `null` | no |
| execution\_environment | The sandbox environment to host this Revision. | `string` | `"EXECUTION_ENVIRONMENT_GEN2"` | no |
+| force\_override | Option to force override existing mapping. | `bool` | `false` | no |
| gpu\_zonal\_redundancy\_disabled | True if GPU zonal redundancy is disabled on this revision. | `bool` | `false` | no |
| iap\_members | Valid only when launch stage is set to 'BETA'. IAP is enabled automatically when users or service accounts (SAs) are provided. Use allUsers for public access, allAuthenticatedUsers for any Google-authenticated user, or specify individual users/SAs. [More info](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/iap_web_cloud_run_service_iam#member/members-2) | `list(string)` | `[]` | no |
| ingress | Restricts network access to your Cloud Run service | `string` | `"INGRESS_TRAFFIC_ALL"` | no |
@@ -82,6 +86,7 @@ Functional examples are included in the
| template\_scaling | Maximum and minimum number of instances for this Revision | object({
min_instance_count = optional(number)
max_instance_count = optional(number)
}) | `null` | no |
| timeout | Max allowed time for an instance to respond to a request. A duration in seconds with up to nine fractional digits, ending with 's' | `string` | `null` | no |
| traffic | Specifies how to distribute traffic over a collection of Revisions belonging to the Service. If traffic is empty or not provided, defaults to 100% traffic to the latest Ready Revision. | list(object({
type = optional(string, "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST")
percent = optional(number, 100)
revision = optional(string, null)
tag = optional(string, null)
})) | `[]` | no |
+| verified\_domain\_name | List of custom Domain Name. | `list(string)` | `[]` | no |
| volumes | Volumes needed for environment variables (when using secret) | list(object({
name = string
secret = optional(object({
secret = string
default_mode = optional(string)
items = optional(object({
path = string
version = optional(string)
mode = optional(string)
}))
}))
cloud_sql_instance = optional(object({
instances = optional(list(string))
}))
empty_dir = optional(object({
medium = optional(string)
size_limit = optional(string)
}))
gcs = optional(object({
bucket = string
read_only = optional(string)
}))
nfs = optional(object({
server = string
path = string
read_only = optional(string)
}))
})) | `[]` | no |
| vpc\_access | Configure this to enable your service to send traffic to a Virtual Private Cloud. Set egress to ALL\_TRAFFIC or PRIVATE\_RANGES\_ONLY. Choose a connector or network\_interfaces (for direct VPC egress). [More info](https://cloud.google.com/run/docs/configuring/connecting-vpc) | object({
connector = optional(string)
egress = optional(string)
network_interfaces = optional(object({
network = optional(string)
subnetwork = optional(string)
tags = optional(list(string))
}))
}) | `null` | no |
@@ -91,6 +96,8 @@ Functional examples are included in the
|------|-------------|
| apphub\_service\_uri | Service URI in CAIS style to be used by Apphub. |
| creator | Email address of the authenticated creator. |
+| domain\_map\_id | Unique Identifier for the created domain map |
+| domain\_map\_status | Status of Domain mapping |
| effective\_annotations | All of annotations (key/value pairs) present on the resource in GCP, including the annotations configured through Terraform, other clients and services. |
| last\_modifier | Email address of the last authenticated modifier. |
| latest\_created\_revision | Name of the last created revision. See comments in reconciling for additional information on reconciliation process in Cloud Run. |
@@ -98,10 +105,13 @@ Functional examples are included in the
| location | Location in which the Cloud Run service was created |
| observed\_generation | The generation of this Service currently serving traffic. |
| project\_id | Google Cloud project in which the service was created |
+| revision | Deployed revision for the service (Full Resource Name) |
| service\_account\_id | Service account id and email |
-| service\_id | Unique Identifier for the created service with format projects/{{project}}/locations/{{location}}/services/{{name}} |
+| service\_id | Unique Identifier for the created service |
| service\_name | Name of the created service |
+| service\_status | Status of the created service |
| service\_uri | The main URI in which this Service is serving traffic. |
+| service\_url | The URL on which the deployed service is available |
| traffic\_statuses | Detailed status information for corresponding traffic targets. |
diff --git a/modules/v2/main.tf b/modules/v2/main.tf
index 83a27d5e..4aea3c31 100644
--- a/modules/v2/main.tf
+++ b/modules/v2/main.tf
@@ -15,7 +15,7 @@
*/
data "google_compute_default_service_account" "default" {
- count = local.create_service_account == false && var.service_account == null ? 1 : 0
+ count = var.create_service_account ? 0 : 1
project = var.project_id
}
@@ -24,9 +24,9 @@ locals {
var.service_account != null
? var.service_account
: (
- var.create_service_account
+ local.create_service_account
? google_service_account.sa[0].email
- : null
+ : data.google_compute_default_service_account.default[0].email
)
)
create_service_account = var.create_service_account ? var.service_account == null : false
@@ -407,3 +407,29 @@ resource "google_cloud_run_v2_service_iam_member" "authorize_iap_p4sa" {
role = "roles/run.invoker"
member = google_project_service_identity.iap_p4sa[count.index].member
}
+
+resource "google_cloud_run_domain_mapping" "domain_map" {
+ for_each = toset(var.verified_domain_name)
+ provider = google-beta
+ location = google_cloud_run_v2_service.main.location
+ name = each.value
+ project = google_cloud_run_v2_service.main.project
+
+ metadata {
+ labels = var.domain_map_labels
+ annotations = var.domain_map_annotations
+ namespace = var.project_id
+ }
+
+ spec {
+ route_name = google_cloud_run_v2_service.main.name
+ force_override = var.force_override
+ certificate_mode = var.certificate_mode
+ }
+
+ lifecycle {
+ ignore_changes = [
+ metadata[0].annotations["run.googleapis.com/operation-id"],
+ ]
+ }
+}
diff --git a/modules/v2/metadata.yaml b/modules/v2/metadata.yaml
index 408f64d7..74c3c515 100644
--- a/modules/v2/metadata.yaml
+++ b/modules/v2/metadata.yaml
@@ -640,6 +640,26 @@ spec:
description: The sandbox environment to host this Revision.
varType: string
defaultValue: EXECUTION_ENVIRONMENT_GEN2
+ - name: verified_domain_name
+ description: List of custom Domain Name.
+ varType: list(string)
+ defaultValue: []
+ - name: certificate_mode
+ description: The mode of the certificate (NONE or AUTOMATIC).
+ varType: string
+ defaultValue: NONE
+ - name: force_override
+ description: Option to force override existing mapping.
+ varType: bool
+ defaultValue: false
+ - name: domain_map_labels
+ description: A set of key/value label pairs to assign to the Domain mapping.
+ varType: map(string)
+ defaultValue: {}
+ - name: domain_map_annotations
+ description: Annotations to the domain map.
+ varType: map(string)
+ defaultValue: {}
outputs:
- name: apphub_service_uri
description: Service URI in CAIS style to be used by Apphub.
@@ -651,6 +671,10 @@ spec:
- name: creator
description: Email address of the authenticated creator.
type: string
+ - name: domain_map_id
+ description: Unique Identifier for the created domain map
+ - name: domain_map_status
+ description: Status of Domain mapping
- name: effective_annotations
description: All of annotations (key/value pairs) present on the resource in GCP, including the annotations configured through Terraform, other clients and services.
type:
@@ -674,6 +698,8 @@ spec:
- name: project_id
description: Google Cloud project in which the service was created
type: string
+ - name: revision
+ description: Deployed revision for the service (Full Resource Name)
- name: service_account_id
description: Service account id and email
type:
@@ -682,14 +708,18 @@ spec:
id: string
member: string
- name: service_id
- description: Unique Identifier for the created service with format projects/{{project}}/locations/{{location}}/services/{{name}}
+ description: Unique Identifier for the created service
type: string
- name: service_name
description: Name of the created service
type: string
+ - name: service_status
+ description: Status of the created service
- name: service_uri
description: The main URI in which this Service is serving traffic.
type: string
+ - name: service_url
+ description: The URL on which the deployed service is available
- name: traffic_statuses
description: Detailed status information for corresponding traffic targets.
type:
@@ -704,14 +734,14 @@ spec:
roles:
- level: Project
roles:
+ - roles/iam.serviceAccountUser
+ - roles/serviceusage.serviceUsageViewer
+ - roles/resourcemanager.projectIamAdmin
- roles/compute.viewer
- roles/iap.admin
- roles/artifactregistry.reader
- roles/run.admin
- roles/iam.serviceAccountAdmin
- - roles/iam.serviceAccountUser
- - roles/serviceusage.serviceUsageViewer
- - roles/resourcemanager.projectIamAdmin
services:
- cloudresourcemanager.googleapis.com
- compute.googleapis.com
diff --git a/modules/v2/outputs.tf b/modules/v2/outputs.tf
index 4e76d00f..797b53bd 100644
--- a/modules/v2/outputs.tf
+++ b/modules/v2/outputs.tf
@@ -14,31 +14,11 @@
* limitations under the License.
*/
-output "project_id" {
- value = google_cloud_run_v2_service.main.project
- description = "Google Cloud project in which the service was created"
-}
-
output "service_uri" {
value = google_cloud_run_v2_service.main.uri
description = "The main URI in which this Service is serving traffic."
}
-output "service_id" {
- value = google_cloud_run_v2_service.main.id
- description = "Unique Identifier for the created service with format projects/{{project}}/locations/{{location}}/services/{{name}}"
-}
-
-output "service_name" {
- value = google_cloud_run_v2_service.main.name
- description = "Name of the created service"
-}
-
-output "location" {
- value = google_cloud_run_v2_service.main.location
- description = "Location in which the Cloud Run service was created"
-}
-
output "creator" {
value = google_cloud_run_v2_service.main.creator
description = "Email address of the authenticated creator."
@@ -79,11 +59,55 @@ output "service_account_id" {
value = local.service_account_output
}
+output "service_name" {
+ value = google_cloud_run_v2_service.main.name
+ description = "Name of the created service"
+}
+
+output "revision" {
+ value = google_cloud_run_v2_service.main.latest_ready_revision
+ description = "Deployed revision for the service (Full Resource Name)"
+}
+
+output "service_url" {
+ value = google_cloud_run_v2_service.main.uri
+ description = "The URL on which the deployed service is available"
+}
+
+output "project_id" {
+ value = google_cloud_run_v2_service.main.project
+ description = "Google Cloud project in which the service was created"
+}
+
+output "location" {
+ value = google_cloud_run_v2_service.main.location
+ description = "Location in which the Cloud Run service was created"
+}
+
+output "service_id" {
+ value = google_cloud_run_v2_service.main.id
+ description = "Unique Identifier for the created service"
+}
+
+output "service_status" {
+ value = try(google_cloud_run_v2_service.main.terminal_condition[0].type, null)
+ description = "Status of the created service"
+}
+
output "apphub_service_uri" {
value = {
service_uri = "//run.googleapis.com/${google_cloud_run_v2_service.main.id}"
service_id = substr("${var.service_name}-${md5("google-cloud-run-v2-${var.location}-${var.project_id}")}", 0, 63)
- location = var.location
}
description = "Service URI in CAIS style to be used by Apphub."
}
+
+output "domain_map_id" {
+ value = values(google_cloud_run_domain_mapping.domain_map)[*].id
+ description = "Unique Identifier for the created domain map"
+}
+
+output "domain_map_status" {
+ value = values(google_cloud_run_domain_mapping.domain_map)[*].status
+ description = "Status of Domain mapping"
+}
diff --git a/modules/v2/variables.tf b/modules/v2/variables.tf
index c62537e7..ffec1059 100644
--- a/modules/v2/variables.tf
+++ b/modules/v2/variables.tf
@@ -357,3 +357,32 @@ variable "execution_environment" {
}
}
+variable "verified_domain_name" {
+ description = "List of custom Domain Name."
+ type = list(string)
+ default = []
+}
+
+variable "certificate_mode" {
+ description = "The mode of the certificate (NONE or AUTOMATIC)."
+ type = string
+ default = "NONE"
+}
+
+variable "force_override" {
+ description = "Option to force override existing mapping."
+ type = bool
+ default = false
+}
+
+variable "domain_map_labels" {
+ description = "A set of key/value label pairs to assign to the Domain mapping."
+ type = map(string)
+ default = {}
+}
+
+variable "domain_map_annotations" {
+ description = "Annotations to the domain map."
+ type = map(string)
+ default = {}
+}