Los secrets permanentes en pipelines suelen terminar replicados entre repositorios, expuestos accidentalmente en logs o activos durante meses sin rotación.

Con OpenID Connect (OIDC), un job de GitHub Actions puede demostrar su identidad ante Vault sin almacenar una credencial permanente. GitHub emite un JWT firmado con datos del repositorio, la rama y la ejecución; Vault valida esos datos y entrega un token de acceso de corta duración.

Importante: el token de Vault es temporal, pero un valor almacenado en KV puede seguir siendo estático. Para obtener credenciales realmente efímeras, utiliza un motor de secretos dinámicos de Vault, como Database, AWS o PKI.

Cuándo conviene aplicarlo

Este enfoque resulta especialmente útil para:

  • Despliegues desde GitHub Actions.
  • Repositorios con acceso a infraestructura o servicios cloud.
  • Organizaciones que todavía rotan credenciales manualmente.
  • Ambientes de producción que necesitan trazabilidad por repositorio y rama.

Requisitos previos

Necesitarás:

  • Una instancia de Vault inicializada, desbloqueada y accesible desde el runner.
  • Acceso administrativo para configurar métodos de autenticación, políticas y auditoría.
  • Un secreto KV o un motor de secretos dinámicos ya configurado.
  • Un entorno protegido de GitHub, por ejemplo production.
  • Un workflow con id-token: write.
  • La URL HTTPS y la cadena de confianza de Vault correctamente configuradas.

Los siguientes comandos administrativos deben ejecutarse desde una estación de operación segura, no dentro del pipeline.

Cómo funciona el intercambio

  1. El job solicita un JWT al proveedor OIDC de GitHub.
  2. GitHub firma el token con claims como repositorio, rama, workflow y ejecución.
  3. Vault valida la firma, el issuer, el audience y los claims permitidos.
  4. Si la identidad coincide, Vault emite un token con política y TTL limitados.
  5. El job utiliza ese token para leer únicamente el secreto autorizado.
  6. La credencial se entrega al proceso de despliegue y desaparece al finalizar el job.

El permiso id-token: write solo habilita la solicitud del JWT; no concede acceso de escritura al repositorio ni a Vault por sí mismo. GitHub documenta este comportamiento y el flujo con Vault.

Workflow de Vault

Paso 1: configurar GitHub como emisor confiable

Comprueba primero si el método JWT ya está habilitado:

vault auth list

Si no aparece montado en jwt/, habilítalo y configura el issuer:

vault auth enable jwt

vault write auth/jwt/config \
  bound_issuer="https://token.actions.githubusercontent.com" \
  oidc_discovery_url="https://token.actions.githubusercontent.com"

Vault utilizará el documento de descubrimiento de GitHub y sus claves públicas para verificar la firma del JWT.

Paso 2: crear una política de mínimo privilegio

Para KV v2, la ruta utilizada por la política incluye el segmento /data/:

# deploy-production.hcl
path "secret/data/deploy/prod" {
  capabilities = ["read"]
}

Aplica y comprueba la política:

vault policy write deploy-production deploy-production.hcl
vault policy read deploy-production

No concedas acceso a secret/data/* si el workflow solo necesita una ruta.

Paso 3: restringir repositorio, rama y audience

Crea el rol mediante JSON para evitar errores al representar bound_claims:

{
  "role_type": "jwt",
  "user_claim": "repository",
  "bound_audiences": ["vault-prod"],
  "bound_claims_type": "string",
  "bound_claims": {
    "repository": "ORG/REPO",
    "ref": "refs/heads/main"
  },
  "claim_mappings": {
    "repository": "repository",
    "ref": "ref",
    "workflow_ref": "workflow_ref",
    "run_id": "run_id"
  },
  "policies": ["deploy-production"],
  "ttl": "10m",
  "max_ttl": "15m"
}

Valida el JSON y aplica el rol:

jq empty deploy-production-role.json

vault write auth/jwt/role/deploy-production \
  @deploy-production-role.json

vault read auth/jwt/role/deploy-production

El valor vault-prod será el audience solicitado por el workflow. Desde Vault 1.17, cuando el JWT contiene aud, al menos un valor de bound_audiences debe coincidir exactamente. Documentación del método JWT de Vault.

Para mayor resistencia ante renombres o transferencias, considera restringir también repository_id y repository_owner_id. Si utilizas bound_subject, inspecciona el formato real: los repositorios creados desde el 15 de julio de 2026 pueden usar subjects inmutables con los identificadores del propietario y del repositorio. Referencia actual de claims OIDC de GitHub.

Paso 4: solicitar el secreto desde el workflow

El siguiente job autentica mediante OIDC y expone la credencial únicamente al proceso de despliegue:

permissions: {}

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production

    permissions:
      contents: read
      id-token: write

    steps:
      - uses: actions/checkout@v4

      - name: Obtener credencial desde Vault
        id: vault
        uses: hashicorp/vault-action@v4
        with:
          url: https://vault.ejemplo.com
          method: jwt
          role: deploy-production
          jwtGithubAudience: vault-prod
          exportEnv: false
          secrets: |
            secret/data/deploy/prod token | DEPLOY_TOKEN

      - name: Desplegar
        env:
          DEPLOY_TOKEN: ${{ steps.vault.outputs.DEPLOY_TOKEN }}
        run: ./deploy.sh

La acción solicita el JWT directamente a GitHub y realiza el login contra auth/jwt/login; no existe una variable automática llamada ACTIONS_ID_TOKEN. La sintaxis de secretos y el método JWT están documentados en HashiCorp Vault Action.

En producción, fija las acciones a un SHA completo revisado, protege el entorno production con aprobaciones y evita ejecutar este job para pull requests provenientes de forks.

Paso 5: validar antes de producción

Realiza la migración en paralelo:

  1. Conserva temporalmente la credencial anterior como punto de retorno.
  2. Prueba el rol OIDC en un entorno aislado.
  3. Ejecuta una prueba positiva desde main.
  4. Ejecuta una prueba negativa desde otra rama y confirma que Vault rechaza el login.
  5. Comprueba el despliegue, la salud del servicio y los eventos de auditoría.
  6. Revoca la credencial anterior y elimínala de GitHub solo después de completar las verificaciones.

No decodifiques ni imprimas el JWT completo en logs. Para investigar claims, utiliza una ejecución controlada sin datos sensibles o herramientas específicas de diagnóstico.

Paso 6: comprobar la auditoría

Primero confirma que Vault tiene dispositivos de auditoría activos:

vault audit list -detailed

Este comando solo enumera los dispositivos configurados; no muestra los accesos. Los eventos deben consultarse en el archivo, syslog o plataforma donde se envía la auditoría.

Vault aplica HMAC a muchos valores de texto. Para localizar un repositorio en un dispositivo llamado file, calcula su representación y búscala en el registro:

REPO_HMAC="$(
  vault write -field=hash \
    sys/audit-hash/file \
    input="ORG/REPO"
)"

grep -F "$REPO_HMAC" /var/log/vault_audit.log

La consulta debe realizarla un operador de Vault; el runner no debería tener acceso al archivo de auditoría. HashiCorp recomienda disponer de más de un dispositivo para evitar que un fallo de auditoría afecte la disponibilidad. Auditoría de Vault.

Problemas frecuentes

Vault rechaza el login

Verifica el issuer, la sincronización horaria, el audience y los claims. vault-prod debe coincidir exactamente entre jwtGithubAudience y bound_audiences.

El login funciona desde una rama no autorizada

Revisa que bound_claims contenga ref y que no se haya configurado bound_claims_type: glob con un patrón demasiado amplio.

Vault devuelve 403 al leer el secreto

Comprueba la política y la ruta. En KV v2, la política utiliza secret/data/deploy/prod, aunque con la CLI normalmente se consulte como vault kv get secret/deploy/prod.

El token expira durante el despliegue

Mide la duración real del job y asigna un TTL ligeramente superior. No utilices un TTL de horas para resolver un despliegue que debería durar minutos; divide el proceso o implementa renovación controlada cuando sea necesario.

La credencial aparece en los logs

Elimina echo, printenv, set -x y el modo debug. Aunque la acción enmascare sus salidas, otra herramienta podría transformar el valor e impedir que GitHub lo reconozca.

Grafico de Pasos con Vault

Buenas prácticas para producción

  • Separa roles, políticas y rutas por ambiente.
  • Protege los entornos de GitHub con aprobaciones y reglas de rama.
  • Usa IDs inmutables del repositorio cuando el modelo de riesgo lo requiera.
  • Mantén TTL y privilegios mínimos.
  • Fija acciones de terceros a commits revisados.
  • Supervisa fallos de autenticación y lecturas anómalas.
  • Elimina los secrets heredados cuando la migración haya sido verificada.
  • Usa motores dinámicos si la credencial final también debe ser temporal.

Cloud Serversby Donweb

Todo el poder de la nube a tus proyectos y aplicaciones.
Alojamiento ultra rápido, escalable y con alta disponibilidad.

  • Performance que te sorprenderá
  • Rápida escalabilidad y sin limitaciones
  • Arquitectura de alta disponibilidad
  • Soporte experto y ejecutivos de cuenta
  • Pagos en tu moneda y facturación local

Descubre la mejor solución de Cloud Hosting