Cardinal Agent Builder
Release Agent
CloudRun Terraform Config

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.tfvars

Main 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 TypeNameDescription
google_project_serviceMultipleEnables 6 required GCP APIs
google_service_accountcloudrun-deployment-trackerService account for Cloud Function
google_project_iam_memberMultipleIAM bindings for permissions
google_project_iam_audit_configCloud Run audit logsEnables audit logging
google_storage_bucket{project-id}-cloudrun-tracker-sourceStores function source code
google_storage_bucket_objectFunction ZIPUploaded function code
google_cloudfunctions2_functioncloudrun-deployment-trackerCloud Function (2nd gen)
google_eventarc_triggercloudrun-deployment-tracker-triggerTrigger for service updates
google_eventarc_triggercloudrun-creation-tracker-triggerTrigger for service creations

APIs Enabled

  • cloudfunctions.googleapis.com - Cloud Functions
  • cloudbuild.googleapis.com - Cloud Build (for function deployment)
  • eventarc.googleapis.com - Eventarc
  • run.googleapis.com - Cloud Run
  • logging.googleapis.com - Cloud Logging
  • artifactregistry.googleapis.com - Artifact Registry

IAM Permissions

The service account is granted:

  • roles/run.viewer - Read Cloud Run resources
  • roles/eventarc.eventReceiver - Receive events from Eventarc
  • roles/run.invoker - Invoke the Cloud Function

Usage

  1. Create directory structure:

    mkdir -p gcp-cloudrun-tracker/terraform
    cd gcp-cloudrun-tracker
  2. Save all files:

    • main.py - See CloudRun function code
    • requirements.txt
    • terraform/main.tf (above)
    • terraform/variables.tf (above)
    • terraform/outputs.tf (above)
    • terraform/terraform.tfvars (above, with your values)
  3. Deploy:

    cd terraform
    terraform init
    terraform plan
    terraform apply

Cleanup

To remove all resources:

terraform destroy

Related Pages