Workload Identity — Identidad para Cargas de Trabajo en GKE
Workload Identity es el mecanismo que permite que tus aplicaciones corriendo en GKE se autentiquen ante los servicios de Google Cloud —Cloud SQL, Secret Manager, Cloud Storage, Pub/Sub— sin ninguna clave JSON, sin contraseñas y sin secretos que rotar. Es el estándar de identidad canónico para cargas de trabajo en HERA.
¿Qué problema resuelve?
Sección titulada «¿Qué problema resuelve?»Cuando una aplicación en GKE necesita acceder a Cloud SQL o Secret Manager, la pregunta es: ¿cómo se identifica ante GCP?
La respuesta incorrecta —y la causa de la mayoría de brechas de seguridad en nube— es generar una clave JSON para una Service Account y distribuirla como secreto en el clúster o en variables de entorno. Este enfoque tiene tres problemas graves:
- La clave es un credencial de larga duración. Si se filtra, el atacante tiene acceso hasta que alguien la rote manualmente.
- La clave debe distribuirse, almacenarse y mantenerse en sync entre ambientes. Esto crea superficie de ataque en cada eslabón de la cadena.
- La rotación requiere coordinación entre múltiples equipos y es propensa a errores humanos.
Workload Identity elimina este problema por diseño. El Pod adquiere automáticamente la identidad de una Service Account de GCP, con tokens de corta duración, sin que ningún humano ni ningún sistema de CI/CD tenga que distribuir o rotar credenciales.
Conceptos clave
Sección titulada «Conceptos clave»Kubernetes Service Account (KSA)
Sección titulada «Kubernetes Service Account (KSA)»Una KSA es una identidad dentro del clúster de Kubernetes, scoped al namespace donde vive. Es el recurso que el Pod declara como su identidad dentro de GKE.
# KSA en el namespace del microservicioapiVersion: v1kind: ServiceAccountmetadata: name: mi-app-ksa namespace: mi-app annotations: # Esta anotación es el puente hacia GCP iam.gke.io/gcp-service-account: mi-app-gsa@mi-proyecto.iam.gserviceaccount.comGoogle Service Account (GSA)
Sección titulada «Google Service Account (GSA)»Una GSA es una identidad dentro de Google Cloud IAM. A ella se le asignan los roles de GCP que la aplicación necesita. La GSA nunca genera claves JSON en este patrón — su identidad se delega a través del mecanismo de Workload Identity.
# Crear la GSA con nombre descriptivo según el estándar de naming HERAgcloud iam service-accounts create mi-app-gsa \ --display-name="Service Account para mi-app (GKE)" \ --project=mi-proyectoIAM Policy Binding (el enlace)
Sección titulada «IAM Policy Binding (el enlace)»El IAM Binding es la declaración explícita que autoriza a la KSA a impersonar a la GSA. Sin este binding, la anotación no tiene efecto.
# Binding: autoriza a mi-app-ksa en namespace mi-app a ser mi-app-gsagcloud iam service-accounts add-iam-policy-binding \ mi-app-gsa@mi-proyecto.iam.gserviceaccount.com \ --role=roles/iam.workloadIdentityUser \ --member="serviceAccount:mi-proyecto.svc.id.goog[mi-app/mi-app-ksa]"El member sigue el formato canónico: serviceAccount:<PROJECT_ID>.svc.id.goog[<NAMESPACE>/<KSA_NAME>].
Diagrama: enlace KSA ↔ GSA
Sección titulada «Diagrama: enlace KSA ↔ GSA»mi-appmi-app-ksaiam.gke.io/gcp-service-account: mi-app-gsa@proyecto.iam.gserviceaccount.com mi-app-*mi-app-ksaroles/iam.workloadIdentityUser serviceAccount:proyecto.svc.id.goog[mi-app/mi-app-ksa] mi-app-gsa@proyecto.iam.gserviceaccount.comCadena de confianza (token flow)
Sección titulada «Cadena de confianza (token flow)»Una vez configurado el binding, el flujo de autenticación es completamente transparente para el código de la aplicación. El desarrollador usa Application Default Credentials (ADC) de forma estándar y el SDK se encarga de todo.
El GKE Metadata Server es el componente que hace posible este flujo. Corre como un DaemonSet en cada nodo del clúster e intercepta las llamadas al endpoint de metadatos (metadata.google.internal). Cuando el Pod solicita un token, el MDS verifica la KSA del Pod, consulta el IAM Binding y retorna un token OAuth de corta duración (TTL de 1 hora) asociado a la GSA vinculada.
Configuración canónica paso a paso
Sección titulada «Configuración canónica paso a paso»Los siguientes pasos aplican a cualquier microservicio que necesite acceder a servicios de GCP desde GKE.
Paso 1 — Habilitar Workload Identity en el clúster (operación de plataforma, ya realizada en todos los clústeres HERA):
# Verificar que WI esté habilitado — debe mostrar el workload poolgcloud container clusters describe gke-hera-prod-01 \ --format="value(workloadIdentityConfig.workloadPool)"# Salida esperada: mi-proyecto.svc.id.googPaso 2 — Crear la GSA con permisos mínimos:
# GSA con solo los permisos que la aplicación necesitagcloud iam service-accounts create pedidos-api-gsa \ --display-name="Service Account pedidos-api" \ --project=mi-proyecto
# Otorgar solo los roles necesarios (principio de privilegio mínimo)gcloud projects add-iam-policy-binding mi-proyecto \ --role=roles/cloudsql.client \ --member="serviceAccount:pedidos-api-gsa@mi-proyecto.iam.gserviceaccount.com"
gcloud projects add-iam-policy-binding mi-proyecto \ --role=roles/secretmanager.secretAccessor \ --member="serviceAccount:pedidos-api-gsa@mi-proyecto.iam.gserviceaccount.com"Paso 3 — Crear la KSA con la anotación de enlace:
kubectl create serviceaccount pedidos-api-ksa \ --namespace=pedidos
kubectl annotate serviceaccount pedidos-api-ksa \ --namespace=pedidos \ iam.gke.io/gcp-service-account=pedidos-api-gsa@mi-proyecto.iam.gserviceaccount.comPaso 4 — Crear el IAM Binding:
gcloud iam service-accounts add-iam-policy-binding \ pedidos-api-gsa@mi-proyecto.iam.gserviceaccount.com \ --role=roles/iam.workloadIdentityUser \ --member="serviceAccount:mi-proyecto.svc.id.goog[pedidos/pedidos-api-ksa]"Paso 5 — Referenciar la KSA en el Deployment:
apiVersion: apps/v1kind: Deploymentmetadata: name: pedidos-api namespace: pedidosspec: template: spec: serviceAccountName: pedidos-api-ksa # ← referencia explícita containers: - name: pedidos-api image: registry.hera.grupoherdez.com/pedidos/api:v1.2.0 # Sin env vars de credenciales — ADC las obtiene automáticamentePatrones de uso con servicios GCP
Sección titulada «Patrones de uso con servicios GCP»Conexión a Cloud SQL sin contraseñas
Sección titulada «Conexión a Cloud SQL sin contraseñas»Con Workload Identity configurado, el Cloud SQL Auth Proxy usa automáticamente ADC para autenticarse. No se configura ninguna contraseña de base de datos en el Deployment.
# El Auth Proxy como sidecar — ADC funciona automáticamente con Workload Identitycontainers: - name: cloud-sql-proxy image: gcr.io/cloud-sql-connectors/cloud-sql-proxy:2 args: - "--structured-logs" - "--port=5432" - "--auto-iam-authn" # ← habilita IAM DB Auth (sin passwords) - "mi-proyecto:us-central1:pedidos-db" securityContext: runAsNonRoot: trueLa GSA también necesita roles/cloudsql.instanceUser para IAM DB Auth, y el usuario de base de datos debe crearse como usuario IAM:
-- En Cloud SQL (PostgreSQL): crear usuario IAM-- El nombre es el email de la GSA sin el dominio .gserviceaccount.comCREATE USER "pedidos-api-gsa@mi-proyecto.iam" WITH LOGIN;GRANT CONNECT ON DATABASE pedidos TO "pedidos-api-gsa@mi-proyecto.iam";GRANT SELECT, INSERT, UPDATE ON ALL TABLES IN SCHEMA public TO "pedidos-api-gsa@mi-proyecto.iam";Acceso a Secret Manager
Sección titulada «Acceso a Secret Manager»from google.cloud import secretmanager
# ADC resuelve la identidad automáticamente — no hay credencial explícitaclient = secretmanager.SecretManagerServiceClient()
response = client.access_secret_version( request={"name": "projects/mi-proyecto/secrets/db-password/versions/latest"})secret_value = response.payload.data.decode("utf-8")Acceso a Cloud Storage
Sección titulada «Acceso a Cloud Storage»from google.cloud import storage
# Sin ninguna credencial hardcodeadaclient = storage.Client()bucket = client.bucket("ghdz-pedidos-assets")blob = bucket.blob("exports/reporte-diario.csv")blob.download_to_filename("/tmp/reporte.csv")Anti-patrones — qué no hacer
Sección titulada «Anti-patrones — qué no hacer»| Anti-patrón | Riesgo | Alternativa canónica |
|---|---|---|
| Claves JSON en variables de entorno | Credencial de larga duración filtrable en logs | Workload Identity + ADC |
| Claves JSON en Kubernetes Secrets | El Secret es legible por cualquier pod del namespace con los permisos correctos | Workload Identity + ADC |
| Claves JSON en el repositorio | Exposición permanente aunque se eliminen después | Workload Identity + ADC |
default compute SA del nodo | Todos los Pods del nodo comparten la misma identidad — imposible auditar qué pod hizo qué | KSA dedicada por microservicio |
| KSA sin anotación correcta | El Pod no adquiere la identidad de la GSA — falla silenciosamente hasta que se lee el log del MDS | Anotación iam.gke.io/gcp-service-account obligatoria |
GSA con roles/editor o roles/owner | Blast radius total si el Pod es comprometido | Roles granulares: roles/cloudsql.client, roles/secretmanager.secretAccessor, etc. |
Checklist de verificación
Sección titulada «Checklist de verificación»Antes de desplegar un microservicio que acceda a servicios GCP, verifica:
- El clúster GKE tiene Workload Identity habilitado (
workloadPoolconfigurado) - La GSA existe con nombre descriptivo que sigue el estándar de naming HERA
- La GSA tiene solo los roles mínimos necesarios (no
roles/editor, noroles/owner) - La KSA existe en el namespace correcto del microservicio
- La KSA tiene la anotación
iam.gke.io/gcp-service-accountapuntando a la GSA correcta - El IAM Binding
roles/iam.workloadIdentityUserexiste con elmembercorrecto - El Deployment referencia explícitamente la KSA en
serviceAccountName - No existe ninguna clave JSON creada ni distribuida para esta GSA
- La identidad se verificó con el endpoint del Metadata Server desde dentro del Pod
Relación con otros estándares HERA
Sección titulada «Relación con otros estándares HERA»| Estándar | Relación con Workload Identity |
|---|---|
Naming GCP (infraestructura/estandares-naming-gcp) | Las GSA siguen el formato <servicio>-gsa@<proyecto>.iam.gserviceaccount.com |
Gestión de Secretos (seguridad/gestion-secretos) | Los secretos de negocio se acceden desde Secret Manager usando el token obtenido por Workload Identity |
Cloud SQL (infraestructura/cloudsql) | La autenticación IAM DB Auth elimina contraseñas de base de datos cuando se combina con Workload Identity |
Gestión de Identidades IAM (seguridad/gestion-identidades) | Workload Identity es la extensión del modelo IAM hacia las cargas de trabajo en Kubernetes |
Variables de Entorno (arquitectura/estandares-configuracion) | Las credenciales de infraestructura no son variables de entorno — son identidades obtenidas dinámicamente |