← worklog

2025-01-20

External Secrets Operator with GCP Secret Manager

External SecretsGCPWorkload IdentityKubernetes

Why not mounted volumes

Kubernetes native secret mounting works but has no rotation story. ESO pulls from Secret Manager on a configurable schedule and updates the k8s Secret object, which triggers pod restarts if you want them.

Setup

  • ClusterSecretStore using the gcpsm provider, authenticated via Workload Identity (GSA bound to the ESO controller KSA).
  • Tenant teams define ExternalSecret resources in their namespaces pointing to specific GCP Secret Manager paths.
  • Naming convention: projects/<project>/secrets/<team>-<env>-<name>.

Workload Identity binding

resource "google_service_account_iam_binding" "eso_wi" {
  service_account_id = google_service_account.eso.name
  role               = "roles/iam.workloadIdentityUser"
  members = [
    "serviceAccount:${var.project}.svc.id.goog[external-secrets/external-secrets]"
  ]
}

Gotcha

The GSA needs roles/secretmanager.secretAccessor on the secrets it reads — not the project. Broad project-level access defeats the purpose.