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.
K8s SA workload pod identity
Workload Identity
GCP SA holds IAM roles
IAM
GCS / AR / etc.
One pattern for every workload-to-GCP-resource binding. The table below enumerates each instance.
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) | platform/photon-indexer |
roles/storage.objectAdmin on ${project_id}-photon-index-usc1 |
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. |
cost-exporter@… |
cost_exporter_iam.tf |
monitoring/cost-exporter |
roles/bigquery.jobUser (project), roles/bigquery.dataViewer on the billing_export dataset |
Cost-exporter queries the BigQuery billing export for GCP month-to-date spend. |
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.writerandroles/artifactregistry.readerare granted at the project level, not per-repo. Adding a third Artifact Registry repo does not require new IAM. - Bucket-scoped roles.
roles/storage.objectAdminis always granted on a specific bucket viagoogle_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 grantedroles/iam.serviceAccountUseroncloudbuild-worker-sa(cloudbuild_iam.tf). That binding is what lets Cloud Build impersonate the worker SA when executing a build. 287267207777is the project number fordevelopment-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.