Cómo autenticar tu agente Claude sin API keys estáticas: guía paso a paso de Workload Identity Federation
Tutorial ejecutable para reemplazar las sk-ant-... estáticas en pipelines CI/CD y workloads en producción por tokens OIDC de corta duración usando WIF de Anthropic con GitHub Actions y AWS IAM.
En Cognitiva, agencia chilena de IA especializada en agentes de producción, hemos identificado el problema más frecuente en pipelines de CI/CD: las claves sk-ant-... estáticas que viven en secretos de repositorios, variables de entorno de contenedores y archivos .env que inevitablemente se filtran. Workload Identity Federation (WIF), disponible en general desde el 17 de junio de 2026, resuelve esto de raíz: la API de Claude ahora acepta tokens OIDC de corta duración emitidos por tu propio proveedor de identidad, sin necesidad de crear, rotar ni almacenar ninguna credencial estática de Anthropic. Este tutorial es ejecutable y concreto. Al final tendrás dos resultados reales: un workflow de GitHub Actions que llama a Claude sin un solo secreto en el repositorio, y un contenedor en ECS que se autentica con tokens STS que expiran en minutos. El tiempo estimado es de 45 minutos si ya tienes acceso de administrador a tu organización en Claude Console y a tu cuenta de AWS o repositorio de GitHub. Todo el código está verificado contra la documentación oficial publicada el 17 de junio de 2026.
Qué es WIF y por qué reemplaza las API keys estáticas
Workload Identity Federation transforma la autenticación de workloads: en lugar de que tu pipeline almacene una credencial de Anthropic, tu workload presenta al endpoint /v1/oauth/token un JWT firmado por el proveedor de identidad que ya opera en tu infraestructura —GitHub Actions, AWS IAM, Google Cloud, Azure, Kubernetes, SPIFFE u Okta— y recibe a cambio un token de acceso Anthropic de corta duración.
El flujo en tres pasos
- Tu IdP emite un JWT al workload. En GitHub Actions, el runner lo solicita al endpoint ACTIONS_ID_TOKEN_REQUEST_URL. En AWS ECS o Lambda, la llamada a sts.GetWebIdentityToken devuelve el token. En Kubernetes, el token se proyecta directamente al sistema de archivos del pod.
- El SDK intercambia el JWT por un token Anthropic. El SDK envía el JWT a POST /v1/oauth/token usando el grant type RFC 7523 jwt-bearer. Anthropic verifica la firma contra las JWKS del issuer registrado, evalúa las condiciones de la federation rule configurada, y devuelve un token sk-ant-oat01-... de corta duración.
- El SDK rota el token automáticamente. Tu código no cambia. El SDK re-lee el archivo de identidad antes de cada expiración y renueva el token sin intervención del desarrollador.
Qué se configura en Claude Console
Antes de que tu workload pueda federarse, configuras tres recursos en Settings → Workload identity con el wizard Connect workload:
- Service account (svac_...): identidad no-humana dentro de tu organización Anthropic. Reemplaza el concepto de API key asociada a un usuario. El service account tiene su propio audit trail.
- Federation issuer (fdis_...): registro del IdP con su issuer_url y la fuente de JWKS (discovery para proveedores públicos, URL explícita o inline para clusters sin acceso público a internet).
- Federation rule (fdrl_...): la regla que conecta el issuer con el service account. Define qué claims del JWT deben coincidir, qué service account recibe el token, y cuánto tiempo vive ese token (token_lifetime_seconds, entre 60 y 86400 segundos; el default es 3600).
El wizard Connect workload crea los tres recursos en un único flujo guiado y verifica el intercambio en tiempo real. También puedes crear y gestionar los tres recursos mediante la Admin API de Anthropic, lo que habilita infrastructure as code con Terraform o herramientas similares.
Prerrequisitos
Antes de iniciar necesitas contar con lo siguiente:
- Rol de admin, owner o primary owner en tu organización de Anthropic (Claude Console).
- Para GitHub Actions: un repositorio donde puedas editar workflows y conceder el permiso id-token: write.
- Para AWS: una cuenta con workloads en ECS, Lambda, EC2 o EKS; el CLI aws disponible; permiso para modificar políticas IAM.
- Python 3.9+ o Node.js 18+ con los SDKs de Anthropic instalados (pip install anthropic o npm install @anthropic-ai/sdk).
- El ID de tu organización Anthropic, visible en Settings → Organization del Claude Console.
En cuanto a versiones de SDK: WIF requiere las clases WorkloadIdentityCredentials en Python y oidcFederationProvider en TypeScript. Estas clases se publicaron junto con el GA del 17 de junio de 2026; actualiza a la versión más reciente del SDK antes de iniciar.
Configurar WIF para GitHub Actions
Paso 1: Registrar el issuer y la federation rule en Claude Console
En el Claude Console, abre Settings → Workload identity → Connect workload y selecciona el tile GitHub Actions. El wizard precargará la issuer URL con https://token.actions.githubusercontent.com, que es el valor exacto del claim iss en todos los tokens de GitHub Actions.
Para la federation rule, define el subject_prefix con el formato que GitHub usa en el claim sub. El trailing segment varía según el evento que disparó el workflow:
- Push a rama: repo:owner/repo:ref:refs/heads/main
- Pull request: repo:owner/repo:pull_request
- Environment gated: repo:owner/repo:environment:production
Aplica el principio de mínimo privilegio: nunca uses repo:owner/* sin acotar el ref o el environment. Un prefijo demasiado amplio permite que cualquier workflow de la organización obtenga un token Anthropic. Anota los IDs fdrl_..., svac_... y el ID de tu organización.
Paso 2: El workflow de GitHub Actions
GitHub solo emite el token OIDC a jobs que lo solicitan explícitamente con el permiso id-token: write. Este es el workflow mínimo funcional:
name: Call Claude via WIF
on: push
permissions:
id-token: write
contents: read
jobs:
call-claude:
runs-on: ubuntu-latest
env:
ANTHROPIC_FEDERATION_RULE_ID: fdrl_REEMPLAZA_CON_TU_ID
ANTHROPIC_ORGANIZATION_ID: 00000000-0000-0000-0000-REEMPLAZA
ANTHROPIC_SERVICE_ACCOUNT_ID: svac_REEMPLAZA_CON_TU_ID
ANTHROPIC_WORKSPACE_ID: wrkspc_REEMPLAZA_CON_TU_ID
ANTHROPIC_IDENTITY_TOKEN_FILE: /tmp/gha-jwt
steps:
- uses: actions/checkout@v4
- name: Obtener token OIDC de GitHub
run: |
curl -sS -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
"$ACTIONS_ID_TOKEN_REQUEST_URL&audience=https://api.anthropic.com" \
| jq -r .value > "$ANTHROPIC_IDENTITY_TOKEN_FILE"
- name: Instalar SDK
run: pip install anthropic
- name: Llamar a Claude
run: python mi_script.pyPaso 3: El script Python
El script que llama a Claude es tan simple como esto. No hay ninguna credencial estática:
import anthropic
# El SDK lee ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
# ANTHROPIC_SERVICE_ACCOUNT_ID, ANTHROPIC_WORKSPACE_ID y
# ANTHROPIC_IDENTITY_TOKEN_FILE del entorno del job automaticamente.
client = anthropic.Anthropic()
message = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
messages=[{"role": "user", "content": "Hola Claude desde GHA sin API key"}],
)
print(message.content[0].text)El token OIDC que emite GitHub expira aproximadamente 5 minutos después de su emisión. El endpoint ACTIONS_ID_TOKEN_REQUEST_URL permanece válido durante todo el job, por lo que puedes volver a solicitar el token si el job dura más que eso.
Paso 4: Verificar el intercambio
Un intercambio exitoso devuelve un access_token que comienza con sk-ant-oat01- y un campo expires_in en segundos. Si recibes 400 invalid_grant, el error más común en GitHub Actions es que el valor del claim sub no coincide con el subject_prefix de la rule: el trailing segment varía entre ref:..., environment:... y pull_request. Decodifica el JWT en jwt.io y compara el valor real del sub con lo que configuraste en la rule.
Configurar WIF para AWS ECS y Lambda
Paso 1: Habilitar Outbound Web Identity Federation en AWS IAM
Esta es una configuración a nivel de cuenta, deshabilitada por defecto. En la consola de AWS, ve a IAM → Account settings y habilita Outbound web identity federation. También puedes habilitarlo programáticamente:
python3 -c "import boto3; boto3.client('iam').enable_outbound_web_identity_federation()"Una vez habilitado, el panel muestra un campo Get Token Issuer URL con un valor único por cuenta de la forma https://UUID.tokens.sts.global.api.aws. Copia este valor; es el issuer_url que registrarás en Anthropic. Si omites este paso, las llamadas a GetWebIdentityToken fallarán con OutboundWebIdentityFederationDisabledException.
Paso 2: Conceder permiso al IAM role del workload
Adjunta esta política al IAM role que usa tu tarea ECS, función Lambda o instancia EC2:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["sts:GetWebIdentityToken"],
"Resource": "*"
}
]
}Paso 3: Configurar el issuer y la federation rule en Claude Console
En Settings → Workload identity → Connect workload, selecciona el tile AWS. Ingresa el issuer_url con el UUID de tu cuenta obtenido en el paso 1. El claim sub en estos tokens contiene el ARN del IAM role. Usa el ARN exacto como subject_prefix sin comodín al final para aplicar mínimo privilegio.
Paso 4: Código Python para ECS o Lambda
A diferencia de GitHub Actions, aquí el token_provider es un callable: el SDK lo invoca en cada renovación, garantizando que siempre se presenta un token STS fresco a Anthropic:
import os
import anthropic
import boto3
from anthropic import WorkloadIdentityCredentials
def get_sts_web_identity_token() -> str:
sts = boto3.client("sts", region_name="us-east-1")
resp = sts.get_web_identity_token(
Audience=["https://api.anthropic.com"],
SigningAlgorithm="RS256",
DurationSeconds=900,
)
return resp["WebIdentityToken"]
client = anthropic.Anthropic(
credentials=WorkloadIdentityCredentials(
identity_token_provider=get_sts_web_identity_token,
federation_rule_id=os.environ["ANTHROPIC_FEDERATION_RULE_ID"],
organization_id=os.environ["ANTHROPIC_ORGANIZATION_ID"],
service_account_id=os.environ["ANTHROPIC_SERVICE_ACCOUNT_ID"],
workspace_id=os.environ.get("ANTHROPIC_WORKSPACE_ID"),
),
)
message = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
messages=[{"role": "user", "content": "Hola desde ECS con WIF"}],
)
print(message.content[0].text)Paso 5: Variables de entorno en la task definition de ECS
En la definición de tu tarea ECS, agrega las variables como environment ordinario, no como secretos en Secrets Manager: son IDs de recursos, no credenciales sensibles.
{
"environment": [
{"name": "ANTHROPIC_FEDERATION_RULE_ID", "value": "fdrl_..."},
{"name": "ANTHROPIC_ORGANIZATION_ID", "value": "00000000-..."},
{"name": "ANTHROPIC_SERVICE_ACCOUNT_ID", "value": "svac_..."},
{"name": "ANTHROPIC_WORKSPACE_ID", "value": "wrkspc_..."}
]
}No hay ninguna ANTHROPIC_API_KEY en la definición. La autenticación ocurre en tiempo de ejecución a través del IAM role del task y la llamada a STS.
TypeScript: el equivalente completo
Para equipos que trabajan en Node.js o TypeScript, el patrón es análogo. En GitHub Actions, el SDK también lee las variables de entorno automáticamente cuando se construye sin argumentos:
import Anthropic from "@anthropic-ai/sdk";
// El SDK lee ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
// ANTHROPIC_SERVICE_ACCOUNT_ID, ANTHROPIC_WORKSPACE_ID y
// ANTHROPIC_IDENTITY_TOKEN_FILE automaticamente del entorno.
const client = new Anthropic();
const message = await client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 1024,
messages: [{ role: "user", content: "Hola desde GHA con WIF en TypeScript" }]
});
for (const block of message.content) {
if (block.type === "text") {
console.log(block.text);
}
}Para AWS con token STS explícito en TypeScript, el patron usa oidcFederationProvider y el cliente de STS del AWS SDK:
import Anthropic from "@anthropic-ai/sdk";
import { oidcFederationProvider } from "@anthropic-ai/sdk/lib/credentials/oidc-federation";
import { STSClient, GetWebIdentityTokenCommand } from "@aws-sdk/client-sts";
const sts = new STSClient({ region: "us-east-1" });
async function getStsToken(): Promise<string> {
const out = await sts.send(
new GetWebIdentityTokenCommand({
Audience: ["https://api.anthropic.com"],
SigningAlgorithm: "RS256",
DurationSeconds: 900
})
);
return out.WebIdentityToken!;
}
const client = new Anthropic({
credentials: oidcFederationProvider({
identityTokenProvider: getStsToken,
federationRuleId: process.env.ANTHROPIC_FEDERATION_RULE_ID!,
organizationId: process.env.ANTHROPIC_ORGANIZATION_ID!,
serviceAccountId: process.env.ANTHROPIC_SERVICE_ACCOUNT_ID,
workspaceId: process.env.ANTHROPIC_WORKSPACE_ID,
baseURL: "https://api.anthropic.com",
fetch
})
});Migrar workloads existentes sin downtime
Si ya tienes workloads con ANTHROPIC_API_KEY en producción, la migración es no-disruptiva porque la API key y la federación coexisten durante la transición. La secuencia recomendada:
- Configura WIF en paralelo: completa los pasos del issuer, service account y federation rule. Deja ANTHROPIC_API_KEY intacta.
- Verifica qué credencial gana: el SDK evalúa credenciales en orden de precedencia. ANTHROPIC_API_KEY está en el segundo nivel, por encima de las variables de federación, así que seguirá ganando mientras exista.
- Quita ANTHROPIC_API_KEY del entorno: elimínala de secretos de CI, variables de entorno del contenedor y shell profiles.
- Confirma con ant auth status: el CLI de Anthropic reporta qué fuente de credencial ganó.
- Revoca la API key: una vez confirmado que el workload funciona con federación, elimina la key en Settings → API keys del Claude Console.
Esta secuencia garantiza que en ningún momento tu workload quede sin autenticación. El rollback es sencillo: si algo falla con federación, reinstala ANTHROPIC_API_KEY y la API key vuelve a ganar automáticamente.
Checklist de seguridad y errores comunes
Checklist de implementación
- ANTHROPIC_API_KEY está completamente ausente del entorno del workload federado; su presencia silencia la federación sin advertencia.
- El subject_prefix de la federation rule apunta al recurso exacto: repo + branch para GHA, ARN completo del role para AWS.
- El audience en el JWT coincide exactamente con https://api.anthropic.com.
- Los IDs ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID y ANTHROPIC_WORKSPACE_ID están como variables de entorno ordinarias, no como secretos.
- El service account está agregado como miembro del workspace correcto en Claude Console.
- token_lifetime_seconds está configurado según la duración real del job; 600 segundos es el default del wizard.
Errores frecuentes y su solución
| Error | Causa probable | Solución |
|---|---|---|
| 400 invalid_grant | Claim sub no coincide con subject_prefix | Decodifica el JWT en jwt.io y compara el sub real con la rule |
| OutboundWebIdentityFederationDisabledException | Federación saliente no habilitada en AWS | Habilitar en IAM → Account settings |
| SDK usa API key en vez de WIF | ANTHROPIC_API_KEY presente en el entorno | Verificar con printenv | grep ANTHROPIC y eliminarla |
| STS sin atributo get_web_identity_token | Versión de boto3 desactualizada | Actualizar boto3 a la versión más reciente |
| Token GHA expirado | Token OIDC de GitHub dura ~5 minutos | Re-ejecutar el step de fetch antes de llamar al SDK |
Preguntas frecuentes
Da el siguiente paso
Hablemos
Cuéntanos sobre tu negocio. Respondemos en 24 horas.
Otros canales
Escríbenos por WhatsApp o agenda una llamada de 30 minutos.