Ir al contenido

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.


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:

  1. La clave es un credencial de larga duración. Si se filtra, el atacante tiene acceso hasta que alguien la rote manualmente.
  2. La clave debe distribuirse, almacenarse y mantenerse en sync entre ambientes. Esto crea superficie de ataque en cada eslabón de la cadena.
  3. 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.


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 microservicio
apiVersion: v1
kind: ServiceAccount
metadata:
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.com

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.

Ventana de terminal
# Crear la GSA con nombre descriptivo según el estándar de naming HERA
gcloud iam service-accounts create mi-app-gsa \
--display-name="Service Account para mi-app (GKE)" \
--project=mi-proyecto

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.

Ventana de terminal
# Binding: autoriza a mi-app-ksa en namespace mi-app a ser mi-app-gsa
gcloud 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>].


Workload Identity — Enlace KSA ↔ GSA
Clúster GKE
Namespace: mi-app
ServiceAccount
mi-app-ksa
annotation iam.gke.io/gcp-service-account: mi-app-gsa@proyecto.iam.gserviceaccount.com
Pod: mi-app-*
serviceAccountName: mi-app-ksa
IAM Policy Binding
roles/iam.workloadIdentityUser
member serviceAccount:proyecto.svc.id.goog[mi-app/mi-app-ksa]
Google Cloud (IAM)
Service Account (GSA)
mi-app-gsa@proyecto.iam.gserviceaccount.com
roles/cloudsql.client
roles/secretmanager.secretAccessor
roles/storage.objectViewer
El Pod obtiene tokens de corta duración del GKE Metadata Server automáticamente — sin claves JSON, sin secretos que rotar.

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.

Workload Identity — Cadena de Confianza (Token Flow)
1
Código de la Aplicación
Llama a ADC (Application Default Credentials)
google.auth.default()
2
GKE SDK Interceptor
Detecta entorno GKE → redirige al Metadata Server local
http://metadata.google.internal/
3
GKE Metadata Server (MDS)
Valida que el Pod usa la KSA correcta y solicita token a GCP
Verifica KSA Enlace IAM Binding
4
OAuth 2.0 Token de Acceso
Token de corta duración emitido para la GSA vinculada
TTL: 1 hora Scoped a GSA
5
GCP API (destino)
Valida el token y aplica los permisos IAM de la GSA
Cloud SQL Secret Manager Cloud Storage Pub/Sub
Zero credentials en disco: En ningún punto del flujo se almacena, distribuye ni rota ninguna clave. El token se obtiene dinámicamente en tiempo de ejecución. Si el Pod es comprometido, el token expira en máximo 1 hora.

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.


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):

Ventana de terminal
# Verificar que WI esté habilitado — debe mostrar el workload pool
gcloud container clusters describe gke-hera-prod-01 \
--format="value(workloadIdentityConfig.workloadPool)"
# Salida esperada: mi-proyecto.svc.id.goog

Paso 2 — Crear la GSA con permisos mínimos:

Ventana de terminal
# GSA con solo los permisos que la aplicación necesita
gcloud 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:

Ventana de terminal
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.com

Paso 4 — Crear el IAM Binding:

Ventana de terminal
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/v1
kind: Deployment
metadata:
name: pedidos-api
namespace: pedidos
spec:
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áticamente

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 Identity
containers:
- 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: true

La 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.com
CREATE 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";
from google.cloud import secretmanager
# ADC resuelve la identidad automáticamente — no hay credencial explícita
client = 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")
from google.cloud import storage
# Sin ninguna credencial hardcodeada
client = storage.Client()
bucket = client.bucket("ghdz-pedidos-assets")
blob = bucket.blob("exports/reporte-diario.csv")
blob.download_to_filename("/tmp/reporte.csv")

Anti-patrónRiesgoAlternativa canónica
Claves JSON en variables de entornoCredencial de larga duración filtrable en logsWorkload Identity + ADC
Claves JSON en Kubernetes SecretsEl Secret es legible por cualquier pod del namespace con los permisos correctosWorkload Identity + ADC
Claves JSON en el repositorioExposición permanente aunque se eliminen despuésWorkload Identity + ADC
default compute SA del nodoTodos los Pods del nodo comparten la misma identidad — imposible auditar qué pod hizo quéKSA dedicada por microservicio
KSA sin anotación correctaEl Pod no adquiere la identidad de la GSA — falla silenciosamente hasta que se lee el log del MDSAnotación iam.gke.io/gcp-service-account obligatoria
GSA con roles/editor o roles/ownerBlast radius total si el Pod es comprometidoRoles granulares: roles/cloudsql.client, roles/secretmanager.secretAccessor, etc.

Antes de desplegar un microservicio que acceda a servicios GCP, verifica:

  • El clúster GKE tiene Workload Identity habilitado (workloadPool configurado)
  • 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, no roles/owner)
  • La KSA existe en el namespace correcto del microservicio
  • La KSA tiene la anotación iam.gke.io/gcp-service-account apuntando a la GSA correcta
  • El IAM Binding roles/iam.workloadIdentityUser existe con el member correcto
  • 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

EstándarRelació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