Logo GCP con Eduardo

GCP con Eduardo

Descarga el código de la lección

Despliega en GCP desde GitHub Actions SIN Claves JSON (Workload Identity Federation)
✦ Guía Técnica & Arquitectura

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

Diseñar una federación OIDC segura entre GitHub Actions y Google Cloud.
Eliminar claves JSON persistentes de los pipelines de CI/CD.
Restringir identidades por organización, repositorio, branch o contexto.
Aplicar IAM con mínimo privilegio y evitar escalaciones accidentales.
GitHub Actions OIDC Google Cloud Workload Identity Federation IAM gcloud YAML DevSecOps CI/CD

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.

GitHub Workflow GitHub OIDC Token WIF Provider IAM GCP Resource

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 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.

01

GitHub como Identity Provider

GitHub emite un token OIDC para la ejecución. El workflow solicita explícitamente el permiso id-token: write.

02

Google como Federation Broker

Workload Identity Federation valida el token y transforma sus claims en atributos que pueden utilizarse en políticas IAM.

03

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.

⚠ La condición de entrada no es opcional desde una perspectiva de seguridad

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.

bootstrap-gcp.sh Google Cloud IAM
#!/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}"
En una implementación real, los roles de ejemplo deben sustituirse por los permisos exactos requeridos por el servicio desplegado. Evita utilizar roles/owner, roles/editor o permisos administrativos amplios como solución rápida.

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.

.github/workflows/deploy.yml GitHub Actions
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 orden importa: el checkout debe ejecutarse antes de la autenticación y el job debe declarar explícitamente id-token: write. La acción de autenticación proporciona las credenciales federadas que posteriormente pueden consumir las herramientas compatibles con Google Cloud.

El antipatron más peligroso: autenticar bien pero autorizar demasiado

✕ "Quité la clave JSON, por tanto ya es seguro"

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.

A

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.

B

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.

C

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".

attribute-model.txt Identity Boundary
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.

01

Evita roles globales

Concede permisos al nivel más pequeño razonable: recurso, servicio, proyecto o rol personalizado cuando la organización lo justifique.

02

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.

03

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.

Secret Management Identity Federation Policy as Code Least Privilege

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.

Sobre el Autor: Eduardo Martínez Agrelo

AI & Data Architect

Eduardo Martínez Agrelo es AI & Data Architect, especializado en arquitectura de datos, inteligencia artificial, cloud, automatización y diseño de plataformas tecnológicas. Su enfoque combina profundidad técnica con decisiones de arquitectura orientadas a producción, escalabilidad, seguridad, gobierno y eficiencia operativa.

En sus contenidos técnicos aborda problemas reales de arquitectura y DevSecOps, con especial atención a los trade-offs que aparecen cuando una solución pasa de un laboratorio o proof of concept a un entorno empresarial.

© 2026 Eduardo Martínez Agrelo · AI & Data Architect · Guía técnica sobre GitHub Actions, Google Cloud, OIDC y Workload Identity Federation.