Identidad y credenciales del agente
Haz que tu servidor autoalojado de Claude Managed Agents firme un token de corta duración que nombre a cada agente, guarda las credenciales de vault en tu gestor de secretos y mantén los secretos fuera de los sandboxes con el gateway de salida.
Esta página muestra cómo permitir que los sistemas fuera de tu servidor confíen en un agente y dónde guardar las credenciales que usan tus agentes:
- Identidad del agente: Permite que un servidor MCP o un gateway le dé a cada agente su propio acceso. El servidor firma un token de corta duración que nombra al agente.
- Gestor de secretos: El servidor guarda las credenciales de vault en AWS Secrets Manager, Google Cloud Secret Manager, HashiCorp Vault o Azure Key Vault.
- Credenciales de variables de entorno: Permite que los comandos de un agente llamen a un servicio mientras el sandbox contiene solo un marcador de posición. El “egress gateway” (gateway de salida) coloca el valor real en las solicitudes del agente.
Identidad del agente
Tu servidor puede firmar un “JSON Web Token” (token web JSON), o JWT, de corta duración que nombre a un agente, y enviarlo con las llamadas MCP de ese agente. El receptor, un servidor MCP o un “gateway” (puerta de enlace), verifica el token con las claves públicas que publicas y, a continuación, puede darle a cada agente su propio acceso.
Configura el emisor
-
Elige la URL del emisor. Publicas tus claves públicas en esta URL en el paso 3, y los receptores las obtienen desde ella. Un host web estático funciona. No uses la dirección de tu servidor, porque el servidor no sirve las claves en las rutas que obtienen los receptores. Usa una URL
https://sin ruta ni barra final, en un nombre de host que puedas conservar. -
Crea la clave de firma. Ejecuta estos comandos en el directorio superior del archivo extraído:
mkdir -m 700 agent-identity openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out agent-identity/signing-key.pem -
Publica las claves públicas. Este comando las escribe en
issuer-files/.well-known/. Sirveissuer-filesen la raíz del nombre de host del emisor, con el tipo de contenidoapplication/json.CMA_AGENT_IDENTITY__ISSUER=https://agents.example.com \ CMA_AGENT_IDENTITY__KEY_FILE=./agent-identity/signing-key.pem \ ./cma-server export-issuer -out issuer-files -
Dale la clave al servidor.
- Si el archivo tiene un directorio
compose, mueve el directorio de la clave dentro de él:mv agent-identity compose/agent-identity. - En
docker-compose.yml, elimina la líneavolumes: *server_mountsdel serviciocma-servery quita el comentario del bloquevolumes:que está debajo. Si cambiaste la listax-server-mounts, haz el mismo cambio en ese bloque, porque el serviciocma-serverya no lee la lista. - En el directorio que contiene
agent-identity, ejecutasudo chown -R root:root agent-identity, a menos que uses Docker Desktop en macOS o Docker sin root.
Ejecuta
kubectl -n cma-server create secret generic cma-agent-identity --from-file=agent-identity/signing-key.pem. Luego estableceserver.agentIdentity.secretNameencma-agent-identityen el archivo de valores del chart del servidor. - Si el archivo tiene un directorio
-
Modifica el archivo de configuración. Incluye el nombre de host del receptor en
mcp.allowed_hostnamesy agrega esta sección:agent_identity: issuer: https://agents.example.com key_file: /run/cma-server/agent-identity/signing-key.pem direct: audiences: - audience: https://mcp-gateway.example.com urls: - https://mcp-gateway.example.comCada
audiencenombra a un receptor, como una URLhttps://. Susurlsson los prefijos de URL de los servidores MCP que pueden recibir un token para él. -
Reinicia el servidor. En el stack de Compose, ejecuta
docker compose up -ddesde el directorio del archivo de Compose en lugar de reiniciar.
Para mantener la clave privada fuera de los archivos, usa key_secret (tu gestor de secretos) o kms_key (AWS KMS o Google Cloud KMS). Referencia de configuración describe ambas configuraciones.
Envía el token a un servidor MCP
Conector MCP describe los campos de la entrada del servidor MCP de un agente. Agrega un campo auth a esa entrada:
mcp_servers:
- type: url
name: tickets
url: https://mcp-gateway.example.com/tickets
auth:
type: agent_token
audience: https://mcp-gateway.example.comPara cada listado de herramientas o llamada a herramienta, tu servidor firma un token nuevo. Envía el token como Authorization: Bearer <token>, en lugar de una credencial del vault. Ni el modelo ni el worker lo reciben.
Para enviar tanto el token como una credencial de bóveda, reemplaza el campo auth por un campo agent_token_header:
mcp_servers:
- type: url
name: tickets
url: https://mcp-gateway.example.com/tickets
agent_token_header:
audience: https://mcp-gateway.example.comLa credencial de bóveda va en el encabezado Authorization, como ocurre con una entrada que no tiene ninguno de los dos campos. El token va en un encabezado Agent-Identity-Token, sin el prefijo Bearer.
El SDK no tiene los campos auth y agent_token_header. En el código del SDK, agrega el campo a la entrada del servidor MCP como un campo adicional, o envía la solicitud como JSON simple.
Estas páginas muestran cómo enviar campos adicionales:
SDK de Python · SDK de TypeScript · SDK de Go · SDK de Java · SDK de PHP · SDK de Ruby
Algunas de esas páginas muestran campos adicionales solo en el nivel superior de una solicitud, no dentro de una entrada de lista. En ese caso, haz que mcp_servers sea el campo adicional. Envía toda la lista de esa forma, con auth o agent_token_header en su entrada.
Para detener los tokens de un agente, elimina la entrada del agente o archiva el agente. Un token ya enviado sigue siendo válido hasta su exp, como máximo 5 minutos de forma predeterminada.
Qué verifica el receptor
Haz que el receptor acepte una solicitud solo si se cumplen todas estas condiciones:
- La firma se verifica con una clave de tu conjunto de claves,
<issuer>/.well-known/jwks.json. La clave correcta es aquella cuyo ID coincide conkiden el encabezado del token. Para una clave RSA, el algoritmo esRS256. isses igual a la URL de tu emisor, yaudes igual a la audiencia del receptor.expestá en el futuro, yiatno está en el futuro.typen el encabezado del token esagent+jwt, ytoken_useesagent.
Luego aplica estas reglas:
- Basa las reglas de acceso de cada agente en el claim
agent_id, el ID del agente en la API. - Acepta un
jtirepetido, porque un listado o una llamada puede requerir varias solicitudes con el mismo token. - Haz que un gateway llame a cada herramienta con su propia credencial y que nunca reenvíe el token.
Con el inicio de sesión único, el token de una llamada a herramienta también nombra al autor de la llamada que creó la sesión, en los claims actor_sub y actor_iss. actor_sub no significa que el autor de la llamada haya aprobado la llamada. El modelo elige cada llamada.
Estos tokens no tienen actor_sub:
- El token de un listado de herramientas
- El token de una llamada de un subagente
- Todos los tokens de una sesión creada con la clave de API del servidor
Si una regla depende del autor de la llamada, rechaza una llamada a herramienta que no tenga actor_sub.
Prueba el gateway MCP
El comando check-gateway envía a un gateway MCP tokens válidos e inválidos. Dale al comando un archivo de configuración propio, aquí check-gateway.yaml:
- Copia en el archivo solo las secciones
mcpyagent_identityde la configuración del servidor, ylimits.mcp_call_timeoutsi el servidor lo establece. - En la copia, cambia
key_filea la ruta de la clave en la máquina donde ejecutas el comando, como./agent-identity/signing-key.pem. Si moviste el directorio dentro decompose, la ruta es./compose/agent-identity/signing-key.pem.
Para -agent, indica el ID de un agente que el gateway permita. Si root es el propietario de la clave, usa sudo.
./cma-server check-gateway -config check-gateway.yaml -agent agent_011CYm1BLqPXpQRk5khsSXrs \
-url https://mcp-gateway.example.com/ticketsEl comando imprime una línea por cada solicitud que envía, con la respuesta del gateway. Una ejecución correcta imprime luego una línea que comienza con check-gateway: PASS y sale con el código 0. Una ejecución fallida indica qué salió mal, en una línea que comienza con check-gateway:, y sale con el código 1.
Gestor de secretos
De forma predeterminada, el servidor almacena los secretos de las credenciales de vault en su base de datos. Con una sección secret_store, el servidor escribe el secreto de cada nueva credencial de vault en tu gestor de secretos, con un prefijo de nombre que reservas para ello. La base de datos guarda solo una referencia.
Agrega el bloque de tu gestor de secretos al archivo de configuración:
secret_store:
type: aws_secrets_manager
region: us-east-1
prefix: cma-server/prod/secret_store:
type: gcp_secret_manager
project: my-project # the project ID, not its number
prefix: cma-server-prod--secret_store:
type: azure_key_vault
vault_url: https://my-vault.vault.azure.net
prefix: cma-server-prod--secret_store:
type: hashicorp_vault
address: https://vault.internal:8200
prefix: cma-server/prod/
approle:
role_id: <role-id>
secret_id_file: /run/vault/secret-id
#kubernetes: { role: cma-server }
#token_file: /run/vault/tokenEstablece exactamente uno de los tres métodos de inicio de sesión:
approle: Úsalo con Docker Compose, en un host o con el chart de Helm del servidor. El servidor inicia sesión con un ID de rol y con un ID secreto que lee de un archivo.kubernetes: Úsalo solo en una instalación de Kubernetes propia, cuyo pod del servidor tenga un token de cuenta de servicio. El servidor inicia sesión con ese token. El chart de Helm del servidor no les da ese token a los pods del servidor, así que este método no funciona con el chart.token_file: Úsalo para cualquier otro método de inicio de sesión de Vault. Ejecuta Vault Agent junto al servidor y haz que escriba su token en este archivo.
Con el chart de Helm del servidor, dale al servidor el ID secreto en un Secret:
- Coloca el ID secreto en un Secret en el namespace del servidor e indica el nombre de ese Secret en
server.extensionFiles.secretNamedel chart. - Establece
approle.secret_id_fileen la ruta del ID secreto. El chart monta cada clave de ese Secret como un archivo en/run/cma-server/extension-files/, así que una clave llamadasecret-idestá en/run/cma-server/extension-files/secret-id.
Para el método kubernetes, vincula el rol de Kubernetes de Vault al namespace y a la cuenta de servicio del servidor, no al namespace de los sandboxes, cma.
Conceder acceso
Dale al servidor una identidad y limítala al prefijo. El directorio iam/ del archivo tiene un archivo para cada gestor de secretos:
- AWS Secrets Manager: Reemplaza los marcadores de posición en
aws-secrets-manager-policy.jsony adjunta la política a la identidad con la que se ejecuta el servidor. - Google Cloud Secret Manager: Ejecuta los comandos de los comentarios de
gcp-secret-manager-role.yaml. - Azure Key Vault: Un rol de Azure abarca todo un key vault, no un prefijo. Así que dale a la implementación un key vault propio, uno que use el control de acceso basado en roles de Azure. Reemplaza
SUBSCRIPTION_IDenazure-key-vault-role.jsony crea un rol personalizado a partir de él. Asigna el rol en el key vault a la identidad con la que se ejecuta el servidor. - HashiCorp Vault: Reemplaza los marcadores de posición en
hashicorp-vault-policy.hcly adjunta la política a la identidad con la que se ejecuta el servidor.
Ante AWS y Google Cloud, el servidor se autentica igual que para la inferencia. Ante Azure Key Vault, se autentica con Microsoft Entra ID, igual que para Microsoft Foundry.
Comprobar la configuración
Ejecuta validate-store antes del primer inicio y después de cualquier cambio de política. Crea, lee y elimina un secreto de prueba bajo el prefijo, sin iniciar el servidor. Ejecuta el comando donde se ejecuta el servidor, con el entorno del servidor:
-
Docker Compose: Ejecútalo en el contenedor del servidor. En Arm, reemplaza
linux_amd64en este comando porlinux_arm64:docker compose exec cma-server /opt/cma-server/bin/linux_amd64/cma-server validate-store -config /etc/cma-server/config.yaml -
En un host:
./cma-server validate-store -config /etc/cma-server/config.yaml -
Kubernetes: Ejecuta el mismo comando como un Job con la cuenta de servicio del servidor.
Una ejecución correcta termina con una línea que dice pass y sale con el código 0.
Con Azure Key Vault, ejecuta esta comprobación contra tu key vault antes de confiar en él.
Límites del gestor de secretos
-
Elige la configuración una sola vez. Después de cualquiera de estos cambios, el servidor deja de encontrar los secretos que escribió antes del cambio:
- Eliminas la sección
secret_store. - Cambias
type,prefix,region,project,vault_url,mountonamespace. Los dos últimos son configuraciones opcionales de HashiCorp Vault. - Diriges
addressa otro Vault.
El servidor vuelve a encontrar esos secretos solo cuando restauras los valores anteriores.
- Eliminas la sección
-
Una identidad lee todo el prefijo. Si dos grupos no deben poder acceder a las credenciales del otro, dale a cada grupo su propia implementación. Cada implementación necesita su propio prefijo o key vault y su propia identidad.
Credenciales de variables de entorno
Con una credencial de variable de entorno, los comandos de un agente pueden llamar a un servicio mientras el sandbox contiene solo un marcador de posición para el secreto. El gateway de salida coloca el valor real en las solicitudes a los hosts que la credencial enumera.
El gateway, cma-egress, es un proxy incluido en el archivo de la versión que se sitúa entre tus sandboxes e internet. Está desactivado de forma predeterminada, y tu servidor acepta estas credenciales solo con el gateway activado.
Con el gateway activado, se aplican dos límites a tus sandboxes:
- Los sandboxes llegan a internet solo a través del gateway.
- El gateway se conecta solo a los hosts que enumeras en la configuración
egress.allowed_hostnamesdel servidor.
Enumera nombres de host públicos exactos, sin comodines. Incluye todos los hosts desde los que descargan los comandos de tus agentes.
Si creaste tu propia imagen de sandbox, inicia el worker mediante cma-with-egress, como se muestra en Crea tu propia imagen de sandbox.
Activa el gateway en el stack de Compose
Desde el directorio que contiene docker-compose.yml, agrega dos líneas a .env. La primera enumera los hosts a los que se conecta el gateway, separados por comas. La segunda carga el archivo de Compose del gateway. Luego inicia el stack:
echo 'CMA_EGRESS__ALLOWED_HOSTNAMES=api.github.com' >> .env
echo 'COMPOSE_FILE=docker-compose.yml:docker-compose.egress.yml' >> .env
docker compose up --build -dSi también usas otro archivo de Compose, agrégalo a la línea COMPOSE_FILE. Una variable COMPOSE_FILE en tu shell anula la de .env, así que elimina la variable del shell.
El archivo del gateway establece las demás configuraciones egress del servidor, así que no agregues una sección egress a compose.config.yaml.
Activa el gateway en Kubernetes
Estos pasos parten de la implementación de Implementa en Kubernetes. Usan las variables REGISTRY, TAG y PLATFORM de esa página y sus dos archivos de valores. Ejecuta los comandos desde el directorio superior del archivo, con OpenSSL 3.0 o posterior. El chart del sandbox no ofrece el gateway en Azure Kubernetes Service (AKS).
La actualización del chart del servidor en estos pasos también agrega una política de red sobre los pods de los servidores. Revisa dos de los puertos que cubre antes de empezar:
- Puerto 9464, el puerto de métricas: La política lo cierra. Si Prometheus recopila métricas de ese puerto, establece
server.telemetry.prometheus.scraper.namespaceencma-server-values.yamlen el namespace en el que se ejecuta Prometheus. - Puerto 8400, el puerto de la API: La política admite cualquier origen. Si una política propia limita quién llega al puerto 8400, ese límite deja de funcionar. Las políticas de red se suman, así que una conexión pasa si cualquier política la admite.
Compila y sube la imagen del gateway
docker buildx build --platform "$PLATFORM" -f kubernetes/egress/Dockerfile -t "$REGISTRY/cma-egress:$TAG" --push .Crea la autoridad de certificación y la clave del gateway
(umask 077 && openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes -days 825 \ -subj "/CN=cma-server egress gateway" \ -addext "basicConstraints=critical,CA:TRUE,pathlen:0" \ -addext "keyUsage=critical,keyCertSign,cRLSign" \ -keyout egress-ca.key -out egress-ca.crt) kubectl -n cma create secret tls cma-egress-ca --cert=egress-ca.crt --key=egress-ca.key kubectl -n cma-server create configmap cma-egress-ca --from-file=ca.crt=egress-ca.crt GATEWAY_KEY=$(openssl rand -hex 32) printf %s "$GATEWAY_KEY" | kubectl -n cma create secret generic cma-egress-gateway-key --from-file=gateway-key=/dev/stdin printf %s "$GATEWAY_KEY" | kubectl -n cma-server create secret generic cma-egress-gateway-key --from-file=gateway-key=/dev/stdin unset GATEWAY_KEYLuego elimina
egress-ca.key, la clave privada de la autoridad de certificación. Cualquiera que la tenga puede suplantar cualquier sitio web ante tus sandboxes. El certificado es válido durante 825 días. Consulta Renueva el certificado.Elimina los sandboxes de sesiones anteriores
Si el entorno no ha ejecutado ninguna sesión, omite este paso. Un sandbox de antes del cambio no puede iniciar su worker después. Estos comandos también eliminan el espacio de trabajo de cada sandbox:
kubectl -n cma scale deployment cma-dispatcher --replicas=0 kubectl -n cma delete sandboxwarmpool cma-sandbox kubectl -n cma delete sandboxclaims --allEn Google Kubernetes Engine (GKE), ejecuta también este comando:
kubectl -n cma delete sandboxes --allRepite
kubectl -n cma get sandboxes,pods,pvchasta que no encuentre nada. Elhelm upgradedel paso “Activa el lado de los sandboxes” vuelve a iniciar el dispatcher.Activa el lado del servidor
Elige una dirección IPv4 libre en el rango de Service del clúster para el gateway. La columna
CLUSTER-IPdekubectl get svc -Amuestra direcciones de ese rango. Agrega esto acma-server-values.yaml. Si el archivo ya tiene un bloqueserver, combina estas líneas en él:egressGateway: enabled: true proxyAddress: 34.118.224.53:3128 # the address that you chose, and port 3128 server: config: egress: allowed_hostnames: - api.github.comLuego ejecuta la actualización:
helm upgrade cma-server kubernetes/server/chart --namespace cma-server -f cma-server-values.yaml --waitActiva el lado de los sandboxes
Ejecuta
kubectl -n cma-server get svcpara enumerar los dos Services del servidor. En una instalación nueva, se llamancma-serverycma-server-egress.En
cma-values.yaml, cambiaegress.modeagatewayy agrega un bloquegatewaydebajo deegress. Indica en el bloque los dos nombres que enumeró el comando:egress: mode: gateway gateway: serviceIP: 34.118.224.53 # the address that you chose serverService: cma-server serverEgressService: cma-server-egress apiServerCIDRs: - 203.0.113.10/32 # the cluster's API endpointConserva los demás valores
egressdel archivo. Para imprimir las direcciones y el puerto del endpoint de la API, ejecutakubectl get endpoints kubernetes -n default. Si el puerto no es 443, establece tambiénegress.gateway.apiServerPort.helm upgrade cma kubernetes/chart --namespace cma -f cma-values.yaml --waitSi la actualización se detiene por un conflicto sobre
.spec.replicas, ejecutakubectl -n cma scale deployment cma-dispatcher --replicas=1y luego vuelve a ejecutar la actualización.
Agrega una credencial
Crea una credencial de variable de entorno como se muestra en Agrega una credencial. Las guías del servicio alojado indican que estas credenciales no son compatibles con sandboxes autoalojados. Eso describe el servicio alojado, no tu servidor.
Tu servidor agrega reglas propias. Rechaza una solicitud que incumpla alguna con un error 400 que nombra el campo. A continuación se indican dos de esas reglas:
networkingdebe tener el tipolimited, y cada host enallowed_hostsdebe estar en la listaegress.allowed_hostnamesdel servidor.injection_locationdebe ser{"header": true}en JSON, y no se puede omitir.
Después de agregar un host a la lista del servidor, aplica el cambio. En Docker Compose, ejecuta docker compose up -d. En Kubernetes, ejecuta el comando helm upgrade del servidor y kubectl -n cma-server rollout restart deployment -l anthropic.com/role=server.
Verifica el gateway de salida
Crea una sesión con el vault de la credencial y pídele al agente que ejecute dos comandos. Este ejemplo es para una credencial llamada GITHUB_TOKEN que enumera api.github.com:
printenv GITHUB_TOKEN
curl -sS -H "Authorization: Bearer $GITHUB_TOKEN" https://api.github.com/userEl primer comando imprime un marcador de posición que comienza con cma_ph_. El segundo imprime el perfil de la cuenta de GitHub del token, porque el gateway reemplazó el marcador de posición por el token. El gateway rechaza una solicitud a un host que no está en tu lista con un error 403.
En Kubernetes, si todas las solicitudes reciben un error 503, probablemente la red de tu clúster reescribe las direcciones de los pods, como lo hace la opción --masquerade-all de kube-proxy. El gateway distingue los sandboxes por las direcciones de sus pods, así que esas direcciones deben llegarle sin cambios.
Renueva el certificado
En Kubernetes, renueva el certificado mientras no se ejecute ninguna sesión. Repite todo el paso “Crea la autoridad de certificación y la clave del gateway” de Activa el gateway en Kubernetes. Ese paso vuelve a crear la autoridad de certificación y la clave del gateway, así que no necesitas el archivo egress-ca.key que eliminaste. Haz un cambio: agrega --dry-run=client -o yaml | kubectl apply -f - al final de cada una de las cuatro líneas que ejecutan kubectl create. Por ejemplo, una línea que termina en --from-file=gateway-key=/dev/stdin termina entonces en --from-file=gateway-key=/dev/stdin --dry-run=client -o yaml | kubectl apply -f -.
Luego reinicia los servidores y el gateway:
kubectl -n cma-server rollout restart deployment -l anthropic.com/role=server
kubectl -n cma rollout restart deployment/cma-egressLímites del gateway de salida
- Encabezados: El gateway coloca un valor solo en un encabezado de solicitud, nunca en una URL ni en un cuerpo. De forma predeterminada, el único encabezado es
Authorization. Para permitir otros, enuméralos junto conAuthorizationenegress.swap_header_names, o enCMA_EGRESS__SWAP_HEADER_NAMESen.envpara el stack de Compose. - Programas que ignoran las variables de proxy: Los sandboxes encuentran el gateway mediante
HTTPS_PROXYy variables relacionadas. Las herramientas de Java como Maven y Gradle no leen esas variables, así que no llegan a nada.
¿Te resultó útil esta página?