Skip to content

Terraform

All GCP infrastructure is defined in terraform/main.tf. The Terraform Cloud workspace handles remote state.

First-time setup

1. Enable APIs

gcloud services enable \
  run.googleapis.com \
  artifactregistry.googleapis.com \
  secretmanager.googleapis.com \
  aiplatform.googleapis.com \
  storage.googleapis.com \
  --project=the-curator-496412

2. Create a Terraform Cloud workspace

Create a workspace in app.terraform.io and set the TF_API_TOKEN GitHub secret.

3. Create an Artifact Registry repository

gcloud artifacts repositories create the-curator \
  --repository-format=docker \
  --location=us-central1 \
  --project=the-curator-496412

4. Configure GitHub secrets

Secret Description
GCP_SA_KEY Service account key JSON with roles/run.admin, roles/storage.admin, roles/secretmanager.admin, roles/artifactregistry.writer, roles/iam.serviceAccountAdmin, roles/resourcemanager.projectIamAdmin
GCP_PROJECT_ID the-curator-496412
TF_API_TOKEN Terraform Cloud API token
GOOGLE_CLIENT_ID Google OAuth client ID
GOOGLE_CLIENT_SECRET Google OAuth client secret
ALLOWED_EMAIL Authorized Google account email
SERVER_URL Cloud Run service URL (after first deploy)

5. Push to main

The Deploy workflow runs terraform apply automatically. The first apply creates all resources. Subsequent deploys update the Cloud Run image.

Manual apply

cd terraform
terraform init
terraform apply \
  -var="podcast_service_image_uri=us-central1-docker.pkg.dev/the-curator-496412/the-curator/the-curator-bot:latest" \
  -var="google_client_id=..." \
  -var="google_client_secret=..." \
  -var="allowed_email=you@example.com" \
  -var="server_url=https://your-cloud-run-url"

Resources reference

Cloud Run service

resource "google_cloud_run_v2_service" "podcast_service" {
  name     = "podcast-service"
  location = "us-central1"
  ingress  = "INGRESS_TRAFFIC_ALL"
  ...
}

The service is public (allUsers can invoke it) so that mcp-remote and MCP clients can reach the OAuth discovery endpoints without authentication. The MCP tools themselves require a valid OAuth token.

GCS buckets

Bucket Access Purpose
the-curator-podcast-data Public read Episode audio
the-curator-oauth-state Private (SA only) OAuth state JSON

Secret Manager

Secrets google-client-id, google-client-secret, and allowed-email are created by Terraform and populated from var.*. They are injected into the Cloud Run container as environment variables via secretKeyRef.