Identità e credenziali dell’agente
Fai firmare al tuo server Claude Managed Agents self-hosted un token di breve durata che identifica ciascun agente, conserva le credenziali dei vault nel tuo gestore di segreti e tieni i segreti fuori dalle sandbox con l’egress gateway.
Questa pagina mostra come consentire ai sistemi esterni al tuo server di fidarsi di un agente e dove conservare le credenziali usate dai tuoi agenti:
- Identità dell’agente: consenti a un server MCP o a un gateway di concedere a ciascun agente il proprio accesso. Il server firma un token di breve durata che identifica l’agente.
- Gestore di segreti: il server conserva le credenziali dei vault in AWS Secrets Manager, Google Cloud Secret Manager, HashiCorp Vault o Azure Key Vault.
- Credenziali delle variabili d’ambiente: consenti ai comandi di un agente di chiamare un servizio mentre la sandbox contiene solo un segnaposto. L’“egress gateway” (gateway di uscita) inserisce il valore reale nelle richieste dell’agente.
Identità dell’agente
Il tuo server può firmare un “JSON Web Token” (token web JSON), o JWT, di breve durata che identifica un agente, e inviarlo insieme alle chiamate MCP di quell’agente. Il destinatario, un server MCP o un gateway, verifica il token rispetto alle chiavi pubbliche che pubblichi e può quindi concedere a ciascun agente il proprio accesso.
Configurare l’emittente
-
Scegli l’URL dell’emittente. Nel passaggio 3 pubblichi le tue chiavi pubbliche a questo URL, e i destinatari le recuperano da lì. Va bene un host web statico. Non usare l’indirizzo del tuo server, perché il server non serve le chiavi ai percorsi da cui i destinatari le recuperano. Usa un URL
https://senza percorso né barra finale, su un nome host che puoi mantenere. -
Crea la chiave di firma. Esegui questi comandi nella directory principale dell’archivio estratto:
mkdir -m 700 agent-identity openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out agent-identity/signing-key.pem -
Pubblica le chiavi pubbliche. Questo comando le scrive in
issuer-files/.well-known/. Serviissuer-filesalla radice del nome host dell’emittente, con il content typeapplication/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 -
Fornisci la chiave al server.
- Se l’archivio ha una directory
compose, sposta al suo interno la directory della chiave:mv agent-identity compose/agent-identity. - In
docker-compose.yml, elimina la rigavolumes: *server_mountsdel serviziocma-servere rimuovi il commento dal bloccovolumes:sottostante. Se hai modificato l’elencox-server-mounts, apporta la stessa modifica in quel blocco, perché il serviziocma-servernon legge più l’elenco. - Nella directory che contiene
agent-identity, eseguisudo chown -R root:root agent-identity, a meno che tu non usi Docker Desktop su macOS o Docker rootless.
Esegui
kubectl -n cma-server create secret generic cma-agent-identity --from-file=agent-identity/signing-key.pem. Quindi impostaserver.agentIdentity.secretNamesucma-agent-identitynel file dei valori del chart del server. - Se l’archivio ha una directory
-
Modifica il file delle impostazioni. Elenca il nome host del destinatario in
mcp.allowed_hostnamese aggiungi questa sezione: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.comOgni
audienceidentifica un destinatario, come URLhttps://. I suoiurlssono i prefissi URL dei server MCP che possono ricevere un token per esso. -
Riavvia il server. Nello stack Compose, esegui
docker compose up -ddalla directory del file Compose invece di un riavvio.
Per tenere la chiave privata fuori dai file, usa key_secret (il tuo gestore dei segreti) oppure kms_key (AWS KMS o Google Cloud KMS). Il riferimento di configurazione descrive entrambe le impostazioni.
Inviare il token a un server MCP
Il connettore MCP descrive i campi della voce del server MCP di un agente. Aggiungi un campo auth a quella voce:
mcp_servers:
- type: url
name: tickets
url: https://mcp-gateway.example.com/tickets
auth:
type: agent_token
audience: https://mcp-gateway.example.comPer ogni elenco di strumenti o chiamata a uno strumento, il tuo server firma un nuovo token. Lo invia come Authorization: Bearer <token>, al posto di una credenziale del vault. Né il modello né il worker lo ricevono.
Per inviare sia il token sia una credenziale del vault, sostituisci il campo auth con 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 credenziale del vault viene inserita nell’intestazione Authorization, come avviene per una voce senza nessuno dei due campi. Il token viene inserito in un’intestazione Agent-Identity-Token, senza il prefisso Bearer.
L’SDK non dispone dei campi auth e agent_token_header. Nel codice SDK, aggiungi il campo alla voce del server MCP come campo extra, oppure invia la richiesta come JSON semplice.
Queste pagine mostrano come inviare campi extra:
SDK Python · SDK TypeScript · SDK Go · SDK Java · SDK PHP · SDK Ruby
Alcune di queste pagine mostrano i campi extra solo al livello superiore di una richiesta, non all’interno di una voce di un elenco. In tal caso, rendi mcp_servers stesso il campo extra. Invia in quel modo l’intero elenco, con auth o agent_token_header nella sua voce.
Per interrompere i token di un agente, rimuovi la voce dall’agente oppure archivia l’agente. Un token già inviato rimane valido fino al suo exp, al massimo 5 minuti per impostazione predefinita.
Cosa verifica il destinatario
Fai in modo che il destinatario accetti una richiesta solo se sono soddisfatte tutte queste condizioni:
- La firma viene verificata con una chiave del tuo set di chiavi,
<issuer>/.well-known/jwks.json. La chiave giusta è quella il cui ID corrisponde akidnell’intestazione del token. Per una chiave RSA, l’algoritmo èRS256. issè uguale all’URL del tuo emittente eaudè uguale all’audience del destinatario.expè nel futuro eiatnon è nel futuro.typnell’intestazione del token èagent+jwtetoken_useèagent.
Quindi applica queste regole:
- Basa le regole di accesso di ciascun agente sulla claim
agent_id, l’ID dell’agente nell’API. - Accetta un
jtiripetuto, perché un singolo elenco o una singola chiamata può comportare diverse richieste con lo stesso token. - Fai in modo che un gateway chiami ogni strumento con la propria credenziale e non inoltri mai il token.
Con il single sign-on, il token di una chiamata a uno strumento identifica anche il chiamante che ha creato la sessione, nelle claim actor_sub e actor_iss. actor_sub non significa che il chiamante abbia approvato la chiamata. È il modello a scegliere ogni chiamata.
Questi token non hanno actor_sub:
- Il token di un elenco di strumenti
- Il token di una chiamata di un subagente
- Ogni token di una sessione creata dalla chiave API del server
Se una regola dipende dal chiamante, rifiuta una chiamata a uno strumento che non ha actor_sub.
Testare il gateway MCP
Il comando check-gateway invia a un gateway MCP token validi e non validi. Fornisci al comando un file delle impostazioni dedicato, qui check-gateway.yaml:
- Copia nel file solo le sezioni
mcpeagent_identitydelle impostazioni del server, elimits.mcp_call_timeoutse il server la imposta. - Nella copia, cambia
key_filenel percorso della chiave sulla macchina in cui esegui il comando, ad esempio./agent-identity/signing-key.pem. Se hai spostato la directory incompose, il percorso è./compose/agent-identity/signing-key.pem.
Per -agent, fornisci l’ID di un agente che il gateway consente. Se la chiave è di proprietà di root, usa sudo.
./cma-server check-gateway -config check-gateway.yaml -agent agent_011CYm1BLqPXpQRk5khsSXrs \
-url https://mcp-gateway.example.com/ticketsIl comando stampa una riga per ogni richiesta che invia, con la risposta del gateway. Un’esecuzione riuscita stampa quindi una riga che inizia con check-gateway: PASS ed esce con codice 0. Un’esecuzione non riuscita indica cosa è andato storto, in una riga che inizia con check-gateway:, ed esce con codice 1.
Gestore di segreti
Per impostazione predefinita, il server archivia nel proprio database i segreti delle credenziali dei vault. Con una sezione secret_store, il server scrive il segreto di ogni nuova credenziale del vault nel tuo gestore di segreti, sotto un prefisso di nome che riservi a tale scopo. Il database conserva solo un riferimento.
Aggiungi il blocco per il tuo gestore di segreti al file delle impostazioni:
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/tokenImposta esattamente uno dei tre metodi di accesso:
approle: Usalo con Docker Compose, su un host o con il chart Helm del server. Il server accede con un role ID e con un secret ID che legge da un file.kubernetes: Usalo solo su un’installazione Kubernetes personalizzata, il cui pod del server dispone di un token del service account. Il server accede con quel token. Il chart Helm del server non fornisce tale token ai pod del server, quindi questo metodo non funziona con il chart.token_file: Usalo per qualsiasi altro metodo di accesso a Vault. Esegui Vault Agent accanto al server e fai in modo che scriva il proprio token in questo file.
Con il chart Helm del server, fornisci al server il secret ID in un Secret:
- Inserisci il secret ID in un Secret nel namespace del server e indica il nome di quel Secret in
server.extensionFiles.secretNamedel chart. - Imposta
approle.secret_id_filesul percorso del secret ID. Il chart monta ogni chiave di quel Secret come file in/run/cma-server/extension-files/, quindi una chiave denominatasecret-idsi trova in/run/cma-server/extension-files/secret-id.
Per il metodo kubernetes, associa il ruolo Kubernetes di Vault al namespace e al service account del server, non al namespace delle sandbox, cma.
Concedere l’accesso
Assegna al server un’unica identità e limitala al prefisso. La directory iam/ dell’archivio contiene un file per ogni gestore di segreti:
- AWS Secrets Manager: Sostituisci i segnaposto in
aws-secrets-manager-policy.jsone associa la policy all’identità con cui viene eseguito il server. - Google Cloud Secret Manager: Esegui i comandi presenti nei commenti di
gcp-secret-manager-role.yaml. - Azure Key Vault: Un ruolo Azure copre un intero key vault, non un prefisso. Quindi assegna al deployment un key vault dedicato, che usi il controllo degli accessi in base al ruolo di Azure. Sostituisci
SUBSCRIPTION_IDinazure-key-vault-role.jsone crea da esso un ruolo personalizzato. Assegna il ruolo sul key vault all’identità con cui viene eseguito il server. - HashiCorp Vault: Sostituisci i segnaposto in
hashicorp-vault-policy.hcle associa la policy all’identità con cui viene eseguito il server.
Verso AWS e Google Cloud, il server si autentica come fa per l’inferenza. Verso Azure Key Vault, si autentica con Microsoft Entra ID, come fa per Microsoft Foundry.
Verificare la configurazione
Esegui validate-store prima del primo avvio e dopo ogni modifica alle policy. Crea, legge ed elimina un secret di test sotto il prefisso, senza avviare il server. Esegui il comando dove viene eseguito il server, con l’ambiente del server:
-
Docker Compose: Eseguilo nel container del server. Su Arm, sostituisci
linux_amd64in questo comando conlinux_arm64:docker compose exec cma-server /opt/cma-server/bin/linux_amd64/cma-server validate-store -config /etc/cma-server/config.yaml -
Su un host:
./cma-server validate-store -config /etc/cma-server/config.yaml -
Kubernetes: Esegui lo stesso comando come Job con il service account del server.
Un’esecuzione riuscita termina con una riga che riporta pass ed esce con codice 0.
Con Azure Key Vault, esegui questa verifica sul tuo key vault prima di farvi affidamento.
Limitazioni del gestore di segreti
-
Scegli le impostazioni una sola volta. Dopo una qualsiasi di queste modifiche, il server non trova più i secret che ha scritto prima della modifica:
- Rimuovi la sezione
secret_store. - Modifichi
type,prefix,region,project,vault_url,mountonamespace. Gli ultimi due sono impostazioni facoltative di HashiCorp Vault. - Punti
addressa un altro Vault.
Il server ritrova quei secret solo quando ripristini i vecchi valori.
- Rimuovi la sezione
-
Un’unica identità legge l’intero prefisso. Se due gruppi non devono poter accedere alle credenziali l’uno dell’altro, assegna a ciascun gruppo un proprio deployment. Ogni deployment necessita di un proprio prefisso o key vault e di una propria identità.
Credenziali delle variabili d’ambiente
Con una credenziale di variabile d’ambiente, i comandi di un agente possono chiamare un servizio mentre la sandbox contiene solo un segnaposto per il segreto. L’egress gateway inserisce il valore reale nelle richieste dirette agli host elencati dalla credenziale.
Il gateway, cma-egress, è un proxy incluso nell’archivio della release che si trova tra le tue sandbox e internet. È disattivato per impostazione predefinita, e il tuo server accetta queste credenziali solo con il gateway attivo.
Con il gateway attivo, alle tue sandbox si applicano due limitazioni:
- Le sandbox raggiungono internet solo attraverso il gateway.
- Il gateway si connette solo agli host che elenchi nell’impostazione
egress.allowed_hostnamesdel server.
Elenca nomi host pubblici esatti, senza caratteri jolly. Includi ogni host da cui i comandi dei tuoi agenti scaricano contenuti.
Se hai creato la tua immagine sandbox, avvia il worker tramite cma-with-egress, come mostrato in Creare la tua immagine sandbox.
Attivare il gateway nello stack Compose
Dalla directory che contiene docker-compose.yml, aggiungi due righe a .env. La prima elenca gli host a cui si connette il gateway, separati da virgole. La seconda carica il file Compose del gateway. Quindi avvia lo 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 -dSe usi anche un altro file Compose, aggiungilo alla riga COMPOSE_FILE. Una variabile COMPOSE_FILE nella tua shell ha la precedenza su quella in .env, quindi annulla l’impostazione della variabile della shell.
Il file del gateway imposta le altre impostazioni egress del server, quindi non aggiungere una sezione egress a compose.config.yaml.
Attivare il gateway su Kubernetes
Questi passaggi partono dal deployment descritto in Distribuire su Kubernetes. Usano le variabili REGISTRY, TAG e PLATFORM di quella pagina e i suoi due file di valori. Esegui i comandi dalla directory principale dell’archivio, con OpenSSL 3.0 o versione successiva. Il chart della sandbox non offre il gateway su Azure Kubernetes Service (AKS).
L’upgrade del chart del server in questi passaggi aggiunge anche una network policy sui pod dei server. Prima di iniziare, verifica due delle porte che copre:
- Porta 9464, la porta delle metriche: La policy la chiude. Se Prometheus esegue lo scraping di quella porta, imposta
server.telemetry.prometheus.scraper.namespaceincma-server-values.yamlsul namespace in cui viene eseguito Prometheus. - Porta 8400, la porta dell’API: La policy ammette qualsiasi origine. Se una tua policy limita chi raggiunge la porta 8400, quel limite smette di funzionare. Le network policy si sommano, quindi una connessione passa se una qualsiasi policy la ammette.
Crea ed esegui il push dell’immagine del gateway
docker buildx build --platform "$PLATFORM" -f kubernetes/egress/Dockerfile -t "$REGISTRY/cma-egress:$TAG" --push .Crea l’autorità di certificazione e la chiave 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_KEYQuindi elimina
egress-ca.key, la chiave privata dell’autorità di certificazione. Chiunque la detenga può impersonare qualsiasi sito web nei confronti delle tue sandbox. Il certificato è valido per 825 giorni. Consulta Rinnovare il certificato.Rimuovi le sandbox delle sessioni precedenti
Se l’ambiente non ha eseguito sessioni, salta questo passaggio. Una sandbox precedente alla modifica non può avviare il proprio worker dopo di essa. Questi comandi eliminano anche lo spazio di lavoro di ciascuna sandbox:
kubectl -n cma scale deployment cma-dispatcher --replicas=0 kubectl -n cma delete sandboxwarmpool cma-sandbox kubectl -n cma delete sandboxclaims --allSu Google Kubernetes Engine (GKE), esegui anche questo comando:
kubectl -n cma delete sandboxes --allRipeti
kubectl -n cma get sandboxes,pods,pvcfinché non trova più nulla. Ilhelm upgradenel passaggio “Attiva il lato delle sandbox” riavvia il dispatcher.Attiva il lato del server
Scegli per il gateway un indirizzo IPv4 libero nell’intervallo dei Service del cluster. La colonna
CLUSTER-IPdikubectl get svc -Amostra gli indirizzi in quell’intervallo. Aggiungi quanto segue acma-server-values.yaml. Se il file ha già un bloccoserver, unisci queste righe al suo interno:egressGateway: enabled: true proxyAddress: 34.118.224.53:3128 # the address that you chose, and port 3128 server: config: egress: allowed_hostnames: - api.github.comQuindi esegui l’upgrade:
helm upgrade cma-server kubernetes/server/chart --namespace cma-server -f cma-server-values.yaml --waitAttiva il lato delle sandbox
Esegui
kubectl -n cma-server get svcper elencare i due Service del server. In una nuova installazione, sono denominaticma-serverecma-server-egress.In
cma-values.yaml, cambiaegress.modeingatewaye aggiungi un bloccogatewaysottoegress. Inserisci nel blocco i due nomi elencati dal 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 endpointMantieni gli altri valori
egressdel file. Per stampare gli indirizzi e la porta dell’endpoint API, eseguikubectl get endpoints kubernetes -n default. Se la porta non è 443, imposta ancheegress.gateway.apiServerPort.helm upgrade cma kubernetes/chart --namespace cma -f cma-values.yaml --waitSe l’upgrade si interrompe per un conflitto su
.spec.replicas, eseguikubectl -n cma scale deployment cma-dispatcher --replicas=1, quindi esegui di nuovo l’upgrade.
Aggiungere una credenziale
Crea una credenziale di variabile d’ambiente come mostrato in Aggiungere una credenziale. Le guide del servizio ospitato indicano che queste credenziali non sono supportate con le sandbox self-hosted. Ciò descrive il servizio ospitato, non il tuo server.
Il tuo server aggiunge regole proprie. Rifiuta una richiesta che ne viola una con un errore 400 che indica il campo. Due di queste regole sono le seguenti:
networkingdeve avere il tipolimitede ogni host inallowed_hostsdeve trovarsi nell’elencoegress.allowed_hostnamesdel server.injection_locationdeve essere{"header": true}in JSON e non può essere omesso.
Dopo aver aggiunto un host all’elenco del server, applica la modifica. Su Docker Compose, esegui docker compose up -d. Su Kubernetes, esegui il comando helm upgrade del server e kubectl -n cma-server rollout restart deployment -l anthropic.com/role=server.
Verificare l’egress gateway
Crea una sessione con il vault della credenziale e chiedi all’agente di eseguire due comandi. Questo esempio riguarda una credenziale denominata GITHUB_TOKEN che elenca api.github.com:
printenv GITHUB_TOKEN
curl -sS -H "Authorization: Bearer $GITHUB_TOKEN" https://api.github.com/userIl primo comando stampa un segnaposto che inizia con cma_ph_. Il secondo stampa il profilo dell’account GitHub del token, perché il gateway ha sostituito il segnaposto con il token. Il gateway rifiuta una richiesta verso un host che non è nel tuo elenco con un errore 403.
Su Kubernetes, se ogni richiesta riceve un errore 503, la rete del tuo cluster probabilmente riscrive gli indirizzi dei pod, come fa l’opzione --masquerade-all di kube-proxy. Il gateway distingue le sandbox in base agli indirizzi dei loro pod, quindi tali indirizzi devono raggiungerlo invariati.
Rinnovare il certificato
Su Kubernetes, rinnova il certificato mentre non è in esecuzione alcuna sessione. Ripeti l’intero passaggio “Crea l’autorità di certificazione e la chiave del gateway” in Attivare il gateway su Kubernetes. Crea di nuovo l’autorità di certificazione e la chiave del gateway, quindi non ti serve il file egress-ca.key che hai eliminato. Apporta una sola modifica: aggiungi --dry-run=client -o yaml | kubectl apply -f - alla fine di ciascuna delle quattro righe che eseguono kubectl create. Una riga che termina con --from-file=gateway-key=/dev/stdin, ad esempio, termina quindi con --from-file=gateway-key=/dev/stdin --dry-run=client -o yaml | kubectl apply -f -.
Quindi riavvia i server e il gateway:
kubectl -n cma-server rollout restart deployment -l anthropic.com/role=server
kubectl -n cma rollout restart deployment/cma-egressLimitazioni dell’egress gateway
- Intestazioni: Il gateway inserisce un valore solo in un’intestazione di richiesta, mai in un URL o in un body. Per impostazione predefinita, l’unica intestazione è
Authorization. Per consentirne altre, elencale insieme adAuthorizationinegress.swap_header_names, oppure inCMA_EGRESS__SWAP_HEADER_NAMESin.envper lo stack Compose. - Programmi che ignorano le variabili proxy: Le sandbox trovano il gateway tramite
HTTPS_PROXYe variabili correlate. Strumenti Java come Maven e Gradle non leggono quelle variabili, quindi non raggiungono nulla.
Questa pagina ti è stata utile?