Skip to content

IAM Overview

A flat list of every GCP service account this Terraform module creates, what roles each one holds, and which Kubernetes service account (if any) impersonates it via Workload Identity.

Code: infrastructure/gcp/gke_iam.tf, cloudbuild_iam.tf, image_updater_iam.tf, plus the SA blocks inside backup.tf and tempo.tf. The photon-indexer SA is not Terraform-managed — it lives outside Terraform alongside the Photon GCS bucket (see bootstrap doc) to keep the planet index safe from terraform destroy.

Workload Identity at a glance

Workload Identity is enabled on the cluster with the pool ${project_id}.svc.id.goog. Every binding follows the same shape:

serviceAccount:${project_id}.svc.id.goog[<namespace>/<ksa-name>]

The K8s SA on the left of the arrow can call gcloud auth print-identity-token and pretend to be the GCP SA on the right.

flowchart LR
    subgraph K8s["GKE"]
        KSA1[argocd/argocd-image-updater]
        KSA2[data/postgres-dev]
        KSA3[data/postgres-prod]
        KSA4[data/photon-indexer]
        KSA5[monitoring/tempo]
    end

    subgraph GCP["GCP service accounts"]
        SA1[argocd-image-updater-sa]
        SA2[cnpg-backup-sa]
        SA3[photon-indexer]
        SA4[cloudbuild-worker-sa]
        SA5[tempo]
    end

    KSA1 -. WI .-> SA1
    KSA2 -. WI .-> SA2
    KSA3 -. WI .-> SA2
    KSA4 -. WI .-> SA3
    KSA5 -. WI .-> SA5

    SA1 -->|artifactregistry.reader| AR[(Artifact Registry)]
    SA2 -->|objectAdmin on backup bucket| BK[(tomoda-db-backups-…)]
    SA3 -->|objectAdmin on index bucket| PI[(…-photon-index)]
    SA4 -->|writer + logger + container.developer| CB[Cloud Build]
    SA5 -->|objectAdmin on traces bucket| TR[(…-tomoda-traces)]

The full table

GCP SA Created in K8s SA via WI Roles What it lets the workload do
cloudbuild-worker-sa@… cloudbuild_iam.tf (none — used directly by Cloud Build) roles/logging.logWriter (project), roles/artifactregistry.writer (project), roles/container.developer (project) Cloud Build can write logs, push Docker images to both registries, and (future) deploy to GKE.
argocd-image-updater-sa@… image_updater_iam.tf argocd/argocd-image-updater roles/artifactregistry.reader (project) Argo CD Image Updater lists image tags in both Artifact Registry repos.
cnpg-backup-sa@… backup.tf data/postgres-dev and data/postgres-prod roles/storage.objectAdmin on tomoda-db-backups-${project_id} CNPG Barman writes WAL + base backups for both Postgres clusters into the backup bucket.
photon-indexer@… manual bootstrap (bootstrap doc) data/photon-indexer roles/storage.objectAdmin on ${project_id}-photon-index Photon indexer (CronJob, currently suspended; or scripts/photon-index-local.sh) uploads index tarballs. SA + bucket detached from Terraform so destroy can't touch the $500-per-rebuild planet index.
tempo@… tempo.tf monitoring/tempo roles/storage.objectAdmin on ${project_id}-tomoda-traces Grafana Tempo writes trace chunks to (and reads from) the traces bucket.
Default compute SA 287267207777-compute@developer.gserviceaccount.com gke_iam.tf (binding only) (implicitly used by GKE nodes) roles/artifactregistry.reader (project) Every GKE node can pull images from both Artifact Registry repos.

Cross-references

Where to read more Doc
Cloud Build SA + IAM in context Cloud Build
Image Updater flow end-to-end Artifact Registry
CNPG backup wiring Backup
Photon indexer wiring Photon Indexer
GKE node identity & cluster shape GKE

Things worth knowing

  • No SA keys. Every binding above uses Workload Identity or the platform's own impersonation chain. There are no JSON key files in this Terraform — and there should never be. If you see one being added, push back.
  • Project-level roles. roles/artifactregistry.writer and roles/artifactregistry.reader are granted at the project level, not per-repo. Adding a third Artifact Registry repo does not require new IAM.
  • Bucket-scoped roles. roles/storage.objectAdmin is always granted on a specific bucket via google_storage_bucket_iam_member, never at the project level. Adding a new bucket means adding a new binding.
  • The Cloud Build platform SA (287267207777@cloudbuild.gserviceaccount.com) is granted roles/iam.serviceAccountUser on cloudbuild-worker-sa (cloudbuild_iam.tf). That binding is what lets Cloud Build impersonate the worker SA when executing a build.
  • 287267207777 is the project number for development-485000 — it appears in multiple bindings (default compute SA, Cloud Build platform SA). If you ever migrate to a new project, every binding using that literal will need to be updated.