Las cargas de trabajo de AWS pueden autenticarse ante la API de Claude sin claves de API estáticas intercambiando un token de identidad OIDC firmado por AWS. La ruta recomendada llama a la API GetWebIdentityToken de AWS STS, que funciona en cualquier lugar donde la carga de trabajo tenga credenciales de AWS: Lambda, EC2, ECS y EKS. Las cargas de trabajo de EKS pueden usar alternativamente la ruta de token proyectado de Kubernetes, que tiene menos pasos de configuración pero solo funciona dentro de un pod.
Esta guía muestra ambas rutas. Para los conceptos subyacentes (cuentas de servicio, emisores de federación y reglas de federación), consulta Workload Identity Federation.
aws o un SDK de AWS disponible en la carga de trabajo.La API GetWebIdentityToken de AWS STS devuelve un token OIDC firmado por AWS que afirma la identidad de IAM del llamador. Como usa las credenciales de AWS ambientales de la carga de trabajo, la misma integración cubre Lambda, EC2, ECS y EKS.
Sigue el tutorial de configuración para registrar un emisor de federación, crear una cuenta de servicio de Anthropic y crear una regla de federación en Claude Console. Usa estos valores específicos de STS.
Emisor de federación: Registra la URL del emisor de STS por cuenta que copiaste en el paso anterior. Expone un endpoint JWKS público, así que usa el modo de descubrimiento.
{
"name": "aws-sts",
"issuer_url": "https://<uuid>.tokens.sts.global.api.aws",
"jwks_source": "discovery"
}Regla de federación: Haz coincidir la audiencia que pasas a GetWebIdentityToken y el ARN del rol de IAM del rol llamador en el claim sub. El valor de sub es el ARN del rol de IAM de la carga de trabajo que llamó a la API, con la forma arn:aws:iam::<account>:role/<role-name>. El token también incluye un claim https://sts.amazonaws.com/ con aws_account, org_id, principal_id y cualquier request_tags que hayas pasado; puedes hacer coincidir esos valores con el mapa claims de la regla o una condition de CEL para un control más fino.
{
"name": "prod-inference",
"issuer_id": "fdis_...",
"match": {
"subject_prefix": "arn:aws:iam::123456789012:role/inference-worker",
"audience": "https://api.anthropic.com"
},
"target": { "type": "service_account", "service_account_id": "svac_..." },
"workspace_id": "wrkspc_...",
"oauth_scope": "workspace:developer",
"token_lifetime_seconds": 600
}Sé tan específico como la carga de trabajo lo permita. Haz coincidir el ARN exacto del rol, y solo amplía subject_prefix (por ejemplo, a arn:aws:iam::123456789012:role/*) si varios roles de IAM deben asignarse a la misma cuenta de servicio de Anthropic.
Llama a GetWebIdentityToken con https://api.anthropic.com como audiencia, luego pasa el resultado a las credenciales de federación del SDK. El proveedor de tokens es un callable, por lo que el SDK vuelve a invocar a STS en cada actualización.
GetWebIdentityToken solo está disponible en endpoints regionales de STS. Si recibes 'STS' object has no attribute 'get_web_identity_token' o un error similar, fija tu cliente de STS a una región (por ejemplo, boto3.client("sts", region_name="us-east-1")) y asegúrate de que tu SDK de AWS sea lo suficientemente reciente como para incluir la API.
Desde dentro de la carga de trabajo, intercambia un token emitido por STS directamente e inspecciona la respuesta:
JWT=$(aws sts get-web-identity-token \
--region us-east-1 \
--audience "https://api.anthropic.com" \
--signing-algorithm RS256 \
--duration-seconds 900 \
--query WebIdentityToken --output text)
curl -sS https://api.anthropic.com/v1/oauth/token \
-H "content-type: application/json" \
-d "{
\"grant_type\": \"urn:ietf:params:oauth:grant-type:jwt-bearer\",
\"assertion\": \"$JWT\",
\"federation_rule_id\": \"fdrl_...\",
\"organization_id\": \"00000000-0000-0000-0000-000000000000\",
\"service_account_id\": \"svac_...\",
\"workspace_id\": \"wrkspc_...\"
}" | jqUn intercambio exitoso devuelve un access_token que comienza con sk-ant-oat01- y un valor expires_in en segundos. Si recibes 400 invalid_grant, consulta Solucionar problemas de un intercambio fallido; la causa más común del lado de AWS es una discrepancia de iss (la URL del emisor de STS por cuenta debe coincidir exactamente con la issuer_url registrada).
Si tu carga de trabajo se ejecuta en un pod de EKS, puedes omitir la llamada a STS y leer un token de cuenta de servicio proyectado por Kubernetes directamente desde el disco. Kubernetes proyecta de forma nativa un token compatible con OIDC en el pod, y el SDK puede leerlo desde una ruta de archivo, por lo que no se requiere un callable proveedor de tokens. Esta ruta tiene dos pasos de configuración de AWS menos que la ruta de STS, pero solo funciona dentro de un pod; el mecanismo subyacente es el mismo que el de la integración genérica de Kubernetes.
Esta ruta requiere adicionalmente un clúster de EKS con un proveedor OIDC de IAM habilitado y acceso kubectl al clúster.
Sigue el tutorial de configuración para registrar un emisor de federación, crear una cuenta de servicio de Anthropic y crear una regla de federación en Claude Console. Usa estos valores específicos de EKS.
Emisor de federación: Los emisores de EKS exponen un endpoint JWKS público, así que usa el modo de descubrimiento. La URL del emisor debe coincidir exactamente con el claim iss del token. Registra un emisor por clúster.
{
"name": "prod-eks-uswest2",
"issuer_url": "https://oidc.eks.us-west-2.amazonaws.com/id/6FA42E7BFDE8549CB...",
"jwks_source": "discovery"
}Regla de federación: Haz coincidir el claim sub de Kubernetes y la audiencia de Anthropic https://api.anthropic.com. (Proyecta un token de cuenta de servicio dedicado con esa audiencia; no reutilices el token predeterminado de IRSA sts.amazonaws.com).
{
"name": "prod-inference",
"issuer_id": "fdis_...",
"match": {
"subject_prefix": "system:serviceaccount:inference:inference-worker",
"audience": "https://api.anthropic.com"
},
"target": { "type": "service_account", "service_account_id": "svac_..." },
"workspace_id": "wrkspc_...",
"oauth_scope": "workspace:developer",
"token_lifetime_seconds": 600
}Sé tan específico como la carga de trabajo lo permita. Relaja subject_prefix a system:serviceaccount:inference:* (el * final lo convierte en una coincidencia de prefijo) solo si todas las cuentas de servicio del namespace deben asignarse a la misma cuenta de servicio de Anthropic.
Dentro del pod, el token proyectado está en /var/run/secrets/anthropic.com/token (expuesto como ANTHROPIC_IDENTITY_TOKEN_FILE en la especificación del Pod). Pasa ese archivo a las credenciales de federación del SDK y el SDK se encarga del intercambio y la actualización.
La especificación del Pod ya establece ANTHROPIC_IDENTITY_TOKEN_FILE, ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID y ANTHROPIC_WORKSPACE_ID, por lo que puedes construir el cliente sin argumentos y el SDK lee las variables de entorno de federación automáticamente.
Desde dentro del pod, intercambia el token proyectado directamente e inspecciona la respuesta:
JWT=$(cat "$ANTHROPIC_IDENTITY_TOKEN_FILE")
curl -sS https://api.anthropic.com/v1/oauth/token \
-H "content-type: application/json" \
-d "{
\"grant_type\": \"urn:ietf:params:oauth:grant-type:jwt-bearer\",
\"assertion\": \"$JWT\",
\"federation_rule_id\": \"$ANTHROPIC_FEDERATION_RULE_ID\",
\"organization_id\": \"$ANTHROPIC_ORGANIZATION_ID\",
\"service_account_id\": \"$ANTHROPIC_SERVICE_ACCOUNT_ID\",
\"workspace_id\": \"$ANTHROPIC_WORKSPACE_ID\"
}" | jqUn intercambio exitoso devuelve un access_token que comienza con sk-ant-oat01- y un valor expires_in en segundos. Si recibes 400 invalid_grant, consulta Solucionar problemas de un intercambio fallido; la causa más común del lado de EKS es que el aud del token proyectado no coincida con la regla (proyecta un token con audience: https://api.anthropic.com, no el predeterminado de IRSA sts.amazonaws.com).
Un subject_prefix de arn:aws:iam::123456789012:role/* coincide con todos los roles de IAM de la cuenta. Cualquier principal que pueda asumir cualquier rol coincidente puede obtener un token federado de Anthropic.
Restringe el bloque match de la regla al alcance más estrecho que se ajuste a tu caso de uso:
subject_prefix: "arn:aws:iam::<account>:role/<role-name>" sin * final para que otros roles de la cuenta no coincidan.aws_account del claim https://sts.amazonaws.com/ del token mediante el mapa claims o una condition de CEL como una verificación de defensa en profundidad contra un prefijo mal configurado.system:serviceaccount:<namespace>:<name> sin * después del prefijo system:serviceaccount:.Was this page helpful?
Habilita la federación de identidad web saliente para la cuenta
Este es un indicador a nivel de cuenta, desactivado de forma predeterminada. En la consola de AWS, abre IAM, elige Account settings y habilita Outbound web identity federation. Para habilitarlo mediante programación:
python3 -c "import boto3; boto3.client('iam').enable_outbound_web_identity_federation()"Si esto no está habilitado, las llamadas a GetWebIdentityToken fallan con OutboundWebIdentityFederationDisabledException.
Otorga al rol de IAM de la carga de trabajo permiso para llamar a la API
Adjunta esta política al rol de IAM con el que se ejecuta tu función de Lambda, instancia de EC2 o tarea de ECS:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["sts:GetWebIdentityToken"],
"Resource": "*"
}
]
}Encuentra la URL del emisor de STS de tu cuenta
Después de habilitar la federación saliente, la página IAM > Account settings muestra un campo Get Token Issuer URL con un valor de la forma https://<uuid>.tokens.sts.global.api.aws. Esta URL es única para tu cuenta de AWS; cópiala para el siguiente paso. Para recuperarla mediante programación:
python3 -c "import boto3; print(boto3.client('iam').get_outbound_web_identity_federation_info())"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": "Hello from AWS"}],
)
print(message.content[0].text)Encuentra la URL del emisor OIDC de tu clúster
Cada clúster de EKS tiene un emisor OIDC único. Recupéralo con la CLI de AWS:
aws eks describe-cluster \
--name <cluster-name> \
--query "cluster.identity.oidc.issuer" \
--output textLa salida se ve como https://oidc.eks.us-west-2.amazonaws.com/id/6FA42E7BFDE8549CB.... Registrarás esta URL como un emisor de federación en la siguiente sección.
Crea la cuenta de servicio y proyecta un token con audiencia de Anthropic
El webhook de identidad de pod de EKS detecta la anotación eks.amazonaws.com/role-arn y proyecta automáticamente un token con aud: sts.amazonaws.com, exponiendo su ruta como AWS_WEB_IDENTITY_TOKEN_FILE. Ese token es para la asunción de roles de AWS. Para el intercambio con Anthropic, proyecta un segundo token con audience: https://api.anthropic.com y móntalo en una ruta dedicada.
apiVersion: v1
kind: ServiceAccount
metadata:
name: inference-worker
namespace: inference
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/inference-workerapiVersion: v1
kind: Pod
metadata:
name: inference-worker
namespace: inference
spec:
serviceAccountName: inference-worker
volumes:
- name: anthropic-token
projected:
sources:
- serviceAccountToken:
audience: https://api.anthropic.com
expirationSeconds: 3600
path: token
containers:
- name: app
image: your-registry/inference-worker:latest
env:
- name: ANTHROPIC_IDENTITY_TOKEN_FILE
value: /var/run/secrets/anthropic.com/token
- name: ANTHROPIC_FEDERATION_RULE_ID
value: fdrl_...
- name: ANTHROPIC_ORGANIZATION_ID
value: 00000000-0000-0000-0000-000000000000
- name: ANTHROPIC_SERVICE_ACCOUNT_ID
value: svac_...
- name: ANTHROPIC_WORKSPACE_ID # required when the rule covers multiple workspaces
value: wrkspc_...
volumeMounts:
- name: anthropic-token
mountPath: /var/run/secrets/anthropic.com
readOnly: trueObserva la forma de los claims del token
El token proyectado es un "JSON Web Token" (token web JSON), o JWT, firmado por el emisor OIDC de tu clúster. Su claim sub sigue la convención de Kubernetes system:serviceaccount:<namespace>:<service-account-name>:
{
"iss": "https://oidc.eks.us-west-2.amazonaws.com/id/6FA42E7BFDE8549CB...",
"sub": "system:serviceaccount:inference:inference-worker",
"aud": ["https://api.anthropic.com"],
"kubernetes.io": {
"namespace": "inference",
"serviceaccount": { "name": "inference-worker", "uid": "..." }
},
"exp": 1775527120,
"iat": 1775523520
}La proyección serviceAccountToken establece aud en https://api.anthropic.com. El token separado inyectado por IRSA en AWS_WEB_IDENTITY_TOKEN_FILE lleva aud: sts.amazonaws.com y es para llamadas a la API de AWS, no para este intercambio.
import os
import anthropic
from anthropic import IdentityTokenFile, WorkloadIdentityCredentials
client = anthropic.Anthropic(
credentials=WorkloadIdentityCredentials(
identity_token_provider=IdentityTokenFile(
os.environ["ANTHROPIC_IDENTITY_TOKEN_FILE"]
),
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": "Hello from EKS"}],
)
print(message.content[0].text)