CloudRun Terraform Configuration Reference
This is the complete Terraform configuration for deploying the Cloud Run deployment tracker Cloud Function.
File Structure
gcp-cloudrun-tracker/
├── main.py
├── requirements.txt
└── terraform/
├── main.tf
├── variables.tf
├── outputs.tf
└── terraform.tfvarsMain Configuration
terraform/main.tf:
terraform {
required_version = ">= 1.0"
required_providers {
google = {
source = "hashicorp/google"
version = "~> 5.0"
}
archive = {
source = "hashicorp/archive"
version = "~> 2.4"
}
}
}
provider "google" {
project = var.project_id
region = var.region
}
# Enable required APIs
resource "google_project_service" "required_apis" {
for_each = toset([
"cloudfunctions.googleapis.com",
"cloudbuild.googleapis.com",
"eventarc.googleapis.com",
"run.googleapis.com",
"logging.googleapis.com",
"artifactregistry.googleapis.com",
])
service = each.value
disable_on_destroy = false
}
# Get project number for service account construction
data "google_project" "project" {
project_id = var.project_id
}
# Create a dedicated service account for the Cloud Function
resource "google_service_account" "cloudrun_tracker" {
account_id = "cloudrun-deployment-tracker"
display_name = "Cloud Run Deployment Tracker Function"
description = "Service account for Cloud Run deployment tracking function"
}
# Grant the Cloud Function service account permission to read Cloud Run resources
resource "google_project_iam_member" "cloudrun_tracker_run_viewer" {
project = var.project_id
role = "roles/run.viewer"
member = "serviceAccount:${google_service_account.cloudrun_tracker.email}"
}
# Grant the Eventarc service agent permission to invoke the Cloud Function
resource "google_project_iam_member" "eventarc_service_agent" {
project = var.project_id
role = "roles/eventarc.serviceAgent"
member = "serviceAccount:service-${data.google_project.project.number}@gcp-sa-eventarc.iam.gserviceaccount.com"
depends_on = [google_project_service.required_apis]
}
# Grant the default compute service account eventReceiver role
resource "google_project_iam_member" "compute_event_receiver" {
project = var.project_id
role = "roles/eventarc.eventReceiver"
member = "serviceAccount:${data.google_project.project.number}-compute@developer.gserviceaccount.com"
depends_on = [google_project_service.required_apis]
}
# Grant the Cloud Function service account permission to receive events
resource "google_project_iam_member" "cloudrun_tracker_event_receiver" {
project = var.project_id
role = "roles/eventarc.eventReceiver"
member = "serviceAccount:${google_service_account.cloudrun_tracker.email}"
}
# Grant the Cloud Function service account permission to be invoked by Eventarc
resource "google_cloud_run_service_iam_member" "cloudrun_tracker_invoker" {
project = var.project_id
location = var.region
service = google_cloudfunctions2_function.cloudrun_tracker.name
role = "roles/run.invoker"
member = "serviceAccount:${data.google_project.project.number}-compute@developer.gserviceaccount.com"
}
# Enable audit logging for Cloud Run
resource "google_project_iam_audit_config" "cloudrun_audit_logs" {
project = var.project_id
service = "run.googleapis.com"
audit_log_config {
log_type = "ADMIN_READ"
}
audit_log_config {
log_type = "DATA_WRITE"
}
depends_on = [google_project_service.required_apis]
}
# Create a GCS bucket for Cloud Function source code
resource "google_storage_bucket" "function_source" {
name = "${var.project_id}-cloudrun-tracker-source"
location = var.region
uniform_bucket_level_access = true
force_destroy = true
depends_on = [google_project_service.required_apis]
}
# Create a ZIP archive of the Cloud Function source code
data "archive_file" "function_source" {
type = "zip"
output_path = "${path.module}/../function-source.zip"
source {
content = file("${path.module}/../main.py")
filename = "main.py"
}
source {
content = file("${path.module}/../requirements.txt")
filename = "requirements.txt"
}
}
# Upload the function source to GCS
resource "google_storage_bucket_object" "function_source" {
name = "cloudrun-tracker-${data.archive_file.function_source.output_md5}.zip"
bucket = google_storage_bucket.function_source.name
source = data.archive_file.function_source.output_path
}
# Deploy the Cloud Function (2nd gen)
resource "google_cloudfunctions2_function" "cloudrun_tracker" {
name = "cloudrun-deployment-tracker"
location = var.region
description = "Tracks Cloud Run deployments and extracts image SHA256 digests"
build_config {
runtime = "python311"
entry_point = "cloudrun_deployment_tracker"
source {
storage_source {
bucket = google_storage_bucket.function_source.name
object = google_storage_bucket_object.function_source.name
}
}
}
service_config {
max_instance_count = 10
min_instance_count = 0
available_memory = "256M"
timeout_seconds = 60
service_account_email = google_service_account.cloudrun_tracker.email
environment_variables = {
DEPLOYMENT_ENDPOINT_URL = var.deployment_endpoint_url
API_KEY = var.api_key
}
}
depends_on = [
google_project_service.required_apis,
google_project_iam_member.cloudrun_tracker_run_viewer,
]
}
# Create Eventarc trigger for Cloud Run deployments
resource "google_eventarc_trigger" "cloudrun_deployments" {
name = "cloudrun-deployment-tracker-trigger"
location = var.region
# Match Cloud Run service updates
matching_criteria {
attribute = "type"
value = "google.cloud.audit.log.v1.written"
}
matching_criteria {
attribute = "serviceName"
value = "run.googleapis.com"
}
matching_criteria {
attribute = "methodName"
value = "google.cloud.run.v1.Services.ReplaceService"
}
destination {
cloud_run_service {
service = google_cloudfunctions2_function.cloudrun_tracker.name
region = var.region
}
}
service_account = "${data.google_project.project.number}-compute@developer.gserviceaccount.com"
depends_on = [
google_project_service.required_apis,
google_project_iam_audit_config.cloudrun_audit_logs,
google_project_iam_member.eventarc_service_agent,
google_project_iam_member.compute_event_receiver,
google_cloud_run_service_iam_member.cloudrun_tracker_invoker,
]
}
# Create a second trigger for service creations
resource "google_eventarc_trigger" "cloudrun_creations" {
name = "cloudrun-creation-tracker-trigger"
location = var.region
matching_criteria {
attribute = "type"
value = "google.cloud.audit.log.v1.written"
}
matching_criteria {
attribute = "serviceName"
value = "run.googleapis.com"
}
matching_criteria {
attribute = "methodName"
value = "google.cloud.run.v1.Services.CreateService"
}
destination {
cloud_run_service {
service = google_cloudfunctions2_function.cloudrun_tracker.name
region = var.region
}
}
service_account = "${data.google_project.project.number}-compute@developer.gserviceaccount.com"
depends_on = [
google_project_service.required_apis,
google_project_iam_audit_config.cloudrun_audit_logs,
google_project_iam_member.eventarc_service_agent,
google_project_iam_member.compute_event_receiver,
google_cloud_run_service_iam_member.cloudrun_tracker_invoker,
]
}Variables
terraform/variables.tf:
variable "project_id" {
description = "The GCP project ID where resources will be created"
type = string
}
variable "region" {
description = "The GCP region where the Cloud Function and Eventarc trigger will be deployed"
type = string
default = "us-central1"
}
variable "deployment_endpoint_url" {
description = "The HTTPS endpoint URL where deployment notifications will be sent"
type = string
sensitive = true
}
variable "api_key" {
description = "API key for authenticating with the deployment endpoint (sent as Bearer token)"
type = string
sensitive = true
}Outputs
terraform/outputs.tf:
output "cloud_function_name" {
description = "The name of the deployed Cloud Function"
value = google_cloudfunctions2_function.cloudrun_tracker.name
}
output "cloud_function_url" {
description = "The URL of the deployed Cloud Function"
value = google_cloudfunctions2_function.cloudrun_tracker.service_config[0].uri
}
output "eventarc_trigger_names" {
description = "The names of the Eventarc triggers"
value = [
google_eventarc_trigger.cloudrun_deployments.name,
google_eventarc_trigger.cloudrun_creations.name,
]
}
output "service_account_email" {
description = "The email of the service account used by the Cloud Function"
value = google_service_account.cloudrun_tracker.email
}
output "function_source_bucket" {
description = "The GCS bucket containing the Cloud Function source code"
value = google_storage_bucket.function_source.name
}Configuration File
terraform/terraform.tfvars:
project_id = "your-gcp-project-id"
region = "us-central1"
deployment_endpoint_url = "https://app.cardinalhq.io/_/chip/workloads"
api_key = "your-cardinal-api-key"Resources Created
| Resource Type | Name | Description |
|---|---|---|
google_project_service | Multiple | Enables 6 required GCP APIs |
google_service_account | cloudrun-deployment-tracker | Service account for Cloud Function |
google_project_iam_member | Multiple | IAM bindings for permissions |
google_project_iam_audit_config | Cloud Run audit logs | Enables audit logging |
google_storage_bucket | {project-id}-cloudrun-tracker-source | Stores function source code |
google_storage_bucket_object | Function ZIP | Uploaded function code |
google_cloudfunctions2_function | cloudrun-deployment-tracker | Cloud Function (2nd gen) |
google_eventarc_trigger | cloudrun-deployment-tracker-trigger | Trigger for service updates |
google_eventarc_trigger | cloudrun-creation-tracker-trigger | Trigger for service creations |
APIs Enabled
cloudfunctions.googleapis.com- Cloud Functionscloudbuild.googleapis.com- Cloud Build (for function deployment)eventarc.googleapis.com- Eventarcrun.googleapis.com- Cloud Runlogging.googleapis.com- Cloud Loggingartifactregistry.googleapis.com- Artifact Registry
IAM Permissions
The service account is granted:
roles/run.viewer- Read Cloud Run resourcesroles/eventarc.eventReceiver- Receive events from Eventarcroles/run.invoker- Invoke the Cloud Function
Usage
-
Create directory structure:
mkdir -p gcp-cloudrun-tracker/terraform cd gcp-cloudrun-tracker -
Save all files:
main.py- See CloudRun function coderequirements.txtterraform/main.tf(above)terraform/variables.tf(above)terraform/outputs.tf(above)terraform/terraform.tfvars(above, with your values)
-
Deploy:
cd terraform terraform init terraform plan terraform apply
Cleanup
To remove all resources:
terraform destroyRelated Pages
- CloudRun Deployment Tracking Guide - Complete setup guide
- CloudRun Function Code - Python function implementation
- Release Agent Overview - Learn about the Release Agent