Despliega en GCP desde GitHub Actions SIN Claves JSON usando Workload Identity Federation
La autenticación entre GitHub Actions y Google Cloud no debería depender de una clave privada almacenada como secreto. Una arquitectura moderna de CI/CD utiliza OpenID Connect (OIDC) para que GitHub emita una identidad de corta duración y Google Cloud la valide mediante Workload Identity Federation.
El objetivo no es simplemente "hacer que el pipeline funcione", sino diseñar una cadena de confianza auditable, restringida por repositorio y compatible con una estrategia empresarial de least privilege, DevSecOps y reducción de credenciales persistentes.
Lo que aprenderás
El problema real: una clave JSON convierte CI/CD en un sistema de secretos
Durante años fue habitual crear una cuenta de servicio en Google Cloud, generar una clave JSON, copiarla a GitHub Secrets y utilizarla desde el workflow. El patrón es sencillo, pero introduce una credencial persistente que debe protegerse, rotarse, revocarse y auditarse durante todo su ciclo de vida.
El problema arquitectónico aparece cuando esa credencial adquiere permisos amplios. Una filtración del secreto no depende ya de la duración de un job: el atacante puede intentar reutilizar la clave hasta que sea revocada o expire por otra política.
Con OIDC, GitHub puede presentar una identidad verificable asociada a una ejecución del workflow. Google Cloud puede intercambiar esa identidad mediante Workload Identity Federation sin exigir que el repositorio almacene una clave privada de larga duración.
Matriz de decisión: ¿JSON, WIF directo o Service Account?
No todas las arquitecturas de Workload Identity Federation son idénticas. La decisión importante es determinar si el recurso de Google Cloud puede autorizar directamente a la identidad federada o si necesitamos utilizar una cuenta de servicio como capa de impersonación.
| Patrón | Credencial persistente | Modelo de identidad | Seguridad | Complejidad | Cuándo usarlo |
|---|---|---|---|---|---|
| Service Account Key JSON | Sí | Clave privada | Media / baja si está mal gestionada | Baja | Legacy, integraciones que realmente exijan claves y casos excepcionales. |
| WIF directo | No | Identidad federada | Muy alta | Media | Recursos que soportan autorización mediante identidades federadas y principalSet. |
| WIF + Service Account | No | OIDC → WIF → Service Account | Muy alta | Media / alta | Cuando se necesita impersonación, access tokens OAuth o una cuenta de servicio como frontera IAM. |
La recomendación general es preferir federación frente a claves de servicio y elegir entre federación directa o impersonación según las capacidades del recurso y el modelo de autorización requerido.
Arquitectura recomendada para producción
Para una organización empresarial, el punto crítico no es solamente configurar un provider. La seguridad está en la combinación de claims, attribute mapping, attribute conditions, IAM y permisos del workflow.
GitHub como Identity Provider
GitHub emite un token OIDC para la ejecución. El workflow solicita explícitamente el permiso id-token: write.
Google como Federation Broker
Workload Identity Federation valida el token y transforma sus claims en atributos que pueden utilizarse en políticas IAM.
IAM como Policy Enforcement
IAM decide finalmente si la identidad puede acceder al recurso y con qué permisos. La autenticación no equivale automáticamente a autorización.
Un error frecuente consiste en crear un Workload Identity Provider que acepte tokens válidos de GitHub pero no restrinja adecuadamente qué organización, repositorio o contexto puede federarse. La identidad debe estar limitada antes de llegar a los permisos sensibles.
En términos de threat modeling, no basta con preguntar "¿el token está firmado?". Hay que preguntar también "¿qué workload concreto representa este token y qué recursos puede alcanzar?".
Configuración de Google Cloud con gcloud
El siguiente patrón utiliza una cuenta de servicio como frontera de autorización. Es una arquitectura especialmente útil cuando el pipeline necesita utilizar herramientas de Google Cloud que esperan credenciales asociadas a una cuenta de servicio.
#!/usr/bin/env bash
set -euo pipefail
PROJECT_ID="my-project"
PROJECT_NUMBER="123456789"
POOL_ID="github"
PROVIDER_ID="github-repository"
SERVICE_ACCOUNT_ID="github-deployer"
GITHUB_ORG="my-org"
GITHUB_REPO="my-org/my-repo"
SERVICE_ACCOUNT="${SERVICE_ACCOUNT_ID}@${PROJECT_ID}.iam.gserviceaccount.com"
POOL_RESOURCE="projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${POOL_ID}"
# 1. Cuenta de servicio dedicada al despliegue.
gcloud iam service-accounts create "${SERVICE_ACCOUNT_ID}" \
--project="${PROJECT_ID}" \
--display-name="GitHub Actions Deployer"
# 2. Workload Identity Pool.
gcloud iam workload-identity-pools create "${POOL_ID}" \
--project="${PROJECT_ID}" \
--location="global" \
--display-name="GitHub Actions Pool"
# 3. Provider OIDC.
# La condición debe limitar quién puede entrar en el pool.
gcloud iam workload-identity-pools providers create-oidc "${PROVIDER_ID}" \
--project="${PROJECT_ID}" \
--location="global" \
--workload-identity-pool="${POOL_ID}" \
--issuer-uri="https://token.actions.githubusercontent.com" \
--attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository,attribute.repository_owner=assertion.repository_owner,attribute.ref=assertion.ref" \
--attribute-condition="assertion.repository_owner == '${GITHUB_ORG}' && assertion.repository == '${GITHUB_REPO}'"
# 4. Permitir que únicamente el repositorio esperado
# pueda impersonar la Service Account.
gcloud iam service-accounts add-iam-policy-binding "${SERVICE_ACCOUNT}" \
--project="${PROJECT_ID}" \
--role="roles/iam.workloadIdentityUser" \
--member="principalSet://iam.googleapis.com/${POOL_RESOURCE}/attribute.repository/${GITHUB_REPO}"
# 5. Conceder únicamente los permisos necesarios para el despliegue.
# Ejemplo conceptual:
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
--member="serviceAccount:${SERVICE_ACCOUNT}" \
--role="roles/run.developer"
echo "Provider configurado: ${POOL_RESOURCE}/providers/${PROVIDER_ID}"
echo "Service Account: ${SERVICE_ACCOUNT}"
GitHub Actions: autenticación sin credentials.json
Una vez creado el provider, el workflow puede solicitar una identidad OIDC y utilizar la acción oficial de autenticación para intercambiarla por credenciales federadas de Google Cloud.
name: Deploy to Google Cloud
on:
push:
branches:
- main
permissions:
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
env:
PROJECT_ID: my-project
REGION: europe-west1
SERVICE: my-service
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Authenticate to Google Cloud
uses: google-github-actions/auth@v3
with:
project_id: ${{ env.PROJECT_ID }}
workload_identity_provider: projects/123456789/locations/global/workloadIdentityPools/github/providers/github-repository
service_account: github-deployer@my-project.iam.gserviceaccount.com
- name: Set up gcloud
uses: google-github-actions/setup-gcloud@v3
- name: Deploy
run: |
gcloud run deploy "${SERVICE}" \
--source . \
--region "${REGION}" \
--project "${PROJECT_ID}" \
--quiet
El antipatron más peligroso: autenticar bien pero autorizar demasiado
No necesariamente. Workload Identity Federation elimina una clase importante de riesgo: las credenciales privadas persistentes. Pero no corrige automáticamente un diseño IAM excesivamente permisivo.
Si cualquier workflow de una organización puede federarse y esa identidad termina impersonando una cuenta de servicio con permisos de administración del proyecto, el atacante solamente necesita comprometer una ejecución de GitHub suficientemente privilegiada.
La frontera correcta debe ser: identidad GitHub → condición de federación → principal IAM → Service Account → permisos mínimos.
Restringe el repositorio
Evita confiar únicamente en la organización. Un repositorio comprometido dentro de la misma organización no debería heredar automáticamente acceso a producción.
Separa entornos
Utiliza identidades y permisos distintos para desarrollo, staging y producción. La identidad que publica en producción debe tener una superficie mucho menor.
Audita IAM
Revisa periódicamente quién puede impersonar la cuenta de servicio y qué permisos efectivos posee esa cuenta.
Claims, mappings y condiciones: la verdadera superficie de seguridad
Un provider OIDC transforma información del token de GitHub en atributos que Google Cloud puede utilizar en políticas. Esto permite construir controles más precisos que una simple autorización basada en "GitHub es confiable".
GitHub OIDC claims
assertion.repository
assertion.repository_owner
assertion.ref
assertion.sub
│
▼
Google attribute mapping
google.subject
attribute.repository
attribute.repository_owner
attribute.ref
│
▼
Attribute condition
repository_owner == "my-org"
AND
repository == "my-org/my-repo"
│
▼
IAM principalSet
principalSet://iam.googleapis.com/
projects/PROJECT_NUMBER/
locations/global/
workloadIdentityPools/github/
attribute.repository/my-org/my-repo
│
▼
roles/iam.workloadIdentityUser
│
▼
Dedicated deployer Service Account
│
▼
Minimum required GCP permissions
La ventaja de este modelo es que la confianza se puede expresar como una cadena de restricciones. No se trata de confiar en GitHub de forma global, sino de confiar en una combinación concreta de issuer + claims + condiciones + IAM.
Direct WIF vs WIF con Service Account
Federación directa
La identidad federada obtiene acceso directamente sobre recursos que soportan el modelo de principalSet. El diseño elimina la cuenta de servicio intermedia y puede reducir la superficie de configuración.
Es una opción especialmente atractiva cuando el servicio destino soporta correctamente identidades federadas y no se necesita generar un token OAuth asociado a una Service Account.
Federación mediante Service Account
GitHub OIDC se intercambia mediante WIF y la identidad obtiene autorización para impersonar una cuenta de servicio. La cuenta de servicio contiene entonces los permisos efectivos sobre los recursos de Google Cloud.
Este patrón introduce una capa adicional, pero resulta muy práctico para workloads existentes, herramientas que esperan una cuenta de servicio y arquitecturas donde se desea centralizar la frontera de permisos en una identidad técnica dedicada.
FinOps y seguridad: el coste de una mala arquitectura IAM
Aunque Workload Identity Federation suele asociarse a seguridad, también tiene una dimensión FinOps. Un pipeline con permisos excesivos puede desplegar recursos inesperados, modificar configuraciones de autoscaling o acceder a servicios cuyo consumo no estaba contemplado.
Evita roles globales
Concede permisos al nivel más pequeño razonable: recurso, servicio, proyecto o rol personalizado cuando la organización lo justifique.
Separa deploy de administración
Una identidad que publica una aplicación no debería tener automáticamente capacidad para administrar IAM, billing, organizaciones o proyectos.
Diseña para revocación
Si un repositorio queda comprometido, debes poder retirar su acceso modificando una condición o una binding sin rotar una colección de claves privadas distribuidas.
Patrones de diseño recomendados para producción
1. Una Service Account por dominio de despliegue
Evita una única cuenta de servicio todopoderosa para todos los pipelines. Divide identidades por aplicación, entorno o dominio operativo según el tamaño de la plataforma.
2. Producción con identidad dedicada
El workflow de producción debe tener una frontera diferente a desarrollo. Esto reduce el blast radius ante compromisos de repositorios o workflows.
3. Condiciones antes que confianza implícita
Configura condiciones de atributos que limiten la entrada al pool. La existencia de un token OIDC válido no debería equivaler a acceso al proyecto.
4. Permisos explícitos del job
Mantén contents: read e id-token: write como permisos deliberados. No concedas permisos GitHub adicionales sin una necesidad concreta.
5. Pinning y supply chain
En organizaciones maduras, considera políticas de gobierno sobre GitHub Actions, revisión de versiones y controles de supply chain. La autenticación segura no compensa una acción de terceros comprometida.
6. Observabilidad y auditoría
Correlaciona ejecuciones de GitHub con actividad de Google Cloud. La trazabilidad debe permitir responder qué workflow obtuvo identidad y qué recurso modificó.
Checklist empresarial de implementación
Define la frontera de confianza
Determina qué organización, repositorio y contexto de ejecución puede solicitar acceso.
Crea el Workload Identity Pool
Usa una nomenclatura consistente y una ubicación adecuada para la estrategia de identidad de la organización.
Configura el provider OIDC
Mapea los claims necesarios y establece una condición explícita de entrada.
Decide entre WIF directo o Service Account
Elige en función de las capacidades del recurso destino y del modelo de autorización requerido.
Crea una identidad de despliegue dedicada
Evita reutilizar una Service Account administrativa para CI/CD.
Aplica mínimo privilegio
Concede exclusivamente los roles necesarios para compilar, publicar, desplegar o consultar los recursos.
Configura GitHub OIDC
Declara explícitamente id-token: write en el job que necesita autenticación.
Elimina las claves JSON
Una vez validada la federación, elimina las claves antiguas y revoca las credenciales persistentes que ya no sean necesarias.
Prueba el blast radius
Verifica explícitamente qué puede y qué no puede hacer el workflow autenticado.
Audita periódicamente
Revisa bindings IAM, condiciones del provider, cuentas de servicio y permisos efectivos.
Errores críticos que debes evitar
| Error | Impacto | Corrección arquitectónica |
|---|---|---|
| Guardar una clave JSON en GitHub Secrets | Credencial persistente y riesgo de exfiltración | Migrar a OIDC + Workload Identity Federation. |
| Provider sin attribute condition | Superficie de confianza excesiva | Restringir la entrada por claims verificables. |
| Usar una Service Account con Owner | Blast radius extremo | Crear una identidad específica y aplicar mínimo privilegio. |
| Confiar en toda la organización | Cualquier repositorio comprometido puede convertirse en vector de ataque | Limitar la autorización al repositorio y contexto requeridos. |
| Mezclar staging y producción | Escalación lateral entre entornos | Separar pools, providers, Service Accounts o bindings según el modelo operativo. |
| Olvidar la revocación de claves antiguas | La migración deja credenciales activas innecesariamente | Revocar y eliminar las claves después de validar WIF. |
¿Qué cambia realmente con OIDC?
La diferencia fundamental es conceptual. Con una clave JSON, el pipeline posee una credencial que representa a una identidad técnica de forma relativamente estática. Con OIDC, el workflow presenta una identidad asociada a una ejecución y Google Cloud decide si esa identidad puede convertirse en una identidad federada autorizada.
Esto desplaza el problema desde la distribución de secretos hacia la gestión declarativa de identidad y autorización. Es un cambio mucho más apropiado para plataformas modernas donde la infraestructura se administra mediante código y las políticas deben ser reproducibles.
Preguntas frecuentes sobre GitHub Actions + GCP + WIF
¿Por qué usar Workload Identity Federation en lugar de una clave JSON?
Porque WIF permite utilizar una identidad federada sin almacenar una clave privada de larga duración en GitHub. El workflow utiliza OIDC para demostrar su identidad y Google Cloud aplica las condiciones y políticas IAM configuradas. Esto reduce el riesgo asociado a credenciales persistentes y simplifica su ciclo de vida operativo.
¿Es suficiente con configurar el proveedor OIDC de Google Cloud?
No. El provider es solamente una parte de la arquitectura. Debes limitar quién puede federarse mediante attribute conditions y determinar qué identidad puede acceder a qué recursos mediante IAM. Una configuración OIDC sin restricciones adecuadas puede seguir siendo demasiado permisiva.
¿Qué permisos necesita un workflow para autenticarse mediante OIDC?
El job necesita normalmente contents: read y id-token: write. El segundo permiso permite solicitar el token OIDC que posteriormente será validado y federado por Google Cloud. Los permisos efectivos sobre GCP son independientes y vienen determinados por IAM.
Conclusión: CI/CD sin claves no es magia, es arquitectura de identidad
Migrar de Service Account Keys a Workload Identity Federation no debería tratarse como un simple cambio de configuración en un workflow. Es una oportunidad para rediseñar la frontera de confianza entre el sistema de control de código y la plataforma cloud.
La arquitectura madura combina GitHub OIDC + Workload Identity Federation + attribute conditions + IAM de mínimo privilegio + identidades de despliegue dedicadas + observabilidad.
El resultado es un pipeline donde la autenticación no depende de secretos persistentes y donde cada acceso puede expresarse como una relación explícita entre una identidad, un contexto y un conjunto limitado de permisos.
Para equipos Senior, Staff y Platform Engineering, esa es la diferencia entre "hacer deploy desde GitHub" y construir una plataforma CI/CD segura, gobernable y preparada para producción.
