代理身分與憑證
讓您自行託管的 Claude Managed Agents 伺服器簽署一個標示每個代理的短期權杖,將 vault 憑證保存在您的密鑰管理器中,並透過輸出閘道讓密鑰不進入沙箱。
本頁說明如何讓您伺服器以外的系統信任代理,以及將代理使用的憑證保存在何處:
- 代理身分:讓 MCP 伺服器或閘道為每個代理提供各自的存取權限。伺服器會簽署一個標示代理的短期權杖。
- 密鑰管理器:伺服器將 vault 憑證保存在 AWS Secrets Manager、Google Cloud Secret Manager、HashiCorp Vault 或 Azure Key Vault 中。
- 環境變數憑證:讓代理的命令在沙箱僅持有預留位置值的情況下呼叫服務。「egress gateway」(輸出閘道)會將實際值放入代理的請求中。
代理身分
您的伺服器可以簽署一個標示代理的短期「JSON Web Token」(JSON 網路權杖),即 JWT,並將其隨該代理的 MCP 呼叫一併傳送。接收方(MCP 伺服器或閘道)會依據您發布的公開金鑰檢查該權杖,然後即可為每個代理提供各自的存取權限。
設定簽發者
-
選擇簽發者 URL。 您會在步驟 3 中於此 URL 發布公開金鑰,接收方會從此 URL 擷取這些金鑰。靜態網站主機即可使用。請勿使用您伺服器的位址,因為伺服器不會在接收方擷取的路徑上提供金鑰。請使用不含路徑或結尾斜線的
https://URL,並使用您可以長期保有的主機名稱。 -
建立簽署金鑰。 在解壓縮後的封存最上層執行以下命令:
mkdir -m 700 agent-identity openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out agent-identity/signing-key.pem -
發布公開金鑰。 此命令會將公開金鑰寫入
issuer-files/.well-known/。請在簽發者主機名稱的根目錄提供issuer-files,內容類型為application/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 -
將金鑰提供給伺服器。
- 如果封存中有
compose目錄,請將金鑰的目錄移入其中:mv agent-identity compose/agent-identity。 - 在
docker-compose.yml中,刪除cma-server服務的volumes: *server_mounts這一行,並取消註解其下方的volumes:區塊。如果您變更了x-server-mounts清單,請在該區塊中進行相同的變更,因為cma-server服務不再讀取該清單。 - 在包含
agent-identity的目錄中,執行sudo chown -R root:root agent-identity,除非您在 macOS 上使用 Docker Desktop 或使用 rootless Docker。
執行
kubectl -n cma-server create secret generic cma-agent-identity --from-file=agent-identity/signing-key.pem。然後在伺服器 chart 的 values 檔案中,將server.agentIdentity.secretName設為cma-agent-identity。 - 如果封存中有
-
變更設定檔。 在
mcp.allowed_hostnames中列出接收方的主機名稱,並新增以下區段: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.com每個
audience以https://URL 的形式標示一個接收方。其urls是可以接收該 audience 權杖的 MCP 伺服器 URL 前綴。 -
重新啟動伺服器。 在 Compose 堆疊中,請從 Compose 檔案所在的目錄執行
docker compose up -d而非重新啟動。
若要避免將私密金鑰存放在檔案中,請使用 key_secret(您的密鑰管理器)或 kms_key(AWS KMS 或 Google Cloud KMS)。設定參考說明了這兩項設定。
將權杖傳送至 MCP 伺服器
MCP 連接器說明了代理 MCP 伺服器項目的欄位。請在該項目中新增 auth 欄位:
mcp_servers:
- type: url
name: tickets
url: https://mcp-gateway.example.com/tickets
auth:
type: agent_token
audience: https://mcp-gateway.example.com對於每次工具列出或工具呼叫,您的伺服器都會簽署一個新的權杖。它會以 Authorization: Bearer <token> 的形式傳送權杖,取代保管庫憑證。模型和 worker 都不會收到該權杖。
若要同時傳送權杖和保管庫憑證,請以 agent_token_header 欄位取代 auth 欄位:
mcp_servers:
- type: url
name: tickets
url: https://mcp-gateway.example.com/tickets
agent_token_header:
audience: https://mcp-gateway.example.com保管庫憑證會放在 Authorization 標頭中,與未包含這兩個欄位的項目相同。權杖會放在 Agent-Identity-Token 標頭中,且不含 Bearer 前綴。
SDK 沒有 auth 和 agent_token_header 欄位。在 SDK 程式碼中,請將該欄位作為額外欄位加入 MCP 伺服器項目,或以純 JSON 傳送請求。
這些頁面會說明如何傳送額外欄位:
Python SDK · TypeScript SDK · Go SDK · Java SDK · PHP SDK · Ruby SDK
其中部分頁面僅說明如何在請求的最上層傳送額外欄位,而非在清單項目內。在此情況下,請將 mcp_servers 本身作為額外欄位。以該方式傳送整個清單,並在其項目中包含 auth 或 agent_token_header。
若要停止代理的權杖,請從代理中移除該項目,或封存該代理。已傳送的權杖在其 exp 之前仍然有效,預設最長為 5 分鐘。
接收方檢查的項目
請讓接收方僅在以下所有條件皆成立時才接受請求:
- 簽章可透過您金鑰集
<issuer>/.well-known/jwks.json中的某個金鑰驗證。正確的金鑰是 ID 與權杖標頭中kid相符的那一個。對於 RSA 金鑰,演算法為RS256。 iss等於您的簽發者 URL,且aud等於接收方的 audience。exp在未來,而iat不在未來。- 權杖標頭中的
typ為agent+jwt,且token_use為agent。
然後套用以下規則:
- 請以
agent_id宣告(即代理在 API 中的 ID)作為每個代理存取規則的依據。 - 請接受重複的
jti,因為一次列出或呼叫可能會以相同權杖發出多個請求。 - 請讓閘道以各工具自己的憑證呼叫每個工具,且絕不將權杖轉傳出去。
使用單一登入時,工具呼叫的權杖也會在 actor_sub 和 actor_iss 宣告中標示建立該工作階段的呼叫者。actor_sub 並不代表呼叫者已核准該呼叫。每次呼叫都是由模型選擇的。
以下權杖沒有 actor_sub:
- 工具列出的權杖
- 子代理呼叫的權杖
- 由伺服器 API 金鑰建立之工作階段的所有權杖
如果某條規則取決於呼叫者,請拒絕沒有 actor_sub 的工具呼叫。
測試 MCP 閘道
check-gateway 命令會向 MCP 閘道傳送有效和無效的權杖。為該命令提供專屬的設定檔(此處為 check-gateway.yaml):
- 僅將伺服器設定中的
mcp和agent_identity區段複製到該檔案中;若伺服器有設定limits.mcp_call_timeout,也請一併複製。 - 在副本中,將
key_file變更為金鑰在您執行命令之機器上的路徑,例如./agent-identity/signing-key.pem。如果您已將該目錄移入compose,則路徑為./compose/agent-identity/signing-key.pem。
對於 -agent,請提供閘道允許的代理 ID。如果金鑰由 root 擁有,請使用 sudo。
./cma-server check-gateway -config check-gateway.yaml -agent agent_011CYm1BLqPXpQRk5khsSXrs \
-url https://mcp-gateway.example.com/tickets該命令會為其傳送的每個請求印出一行,並附上閘道的回應。通過的執行接著會印出以 check-gateway: PASS 開頭的一行,並以代碼 0 結束。失敗的執行會在以 check-gateway: 開頭的一行中說明出錯之處,並以代碼 1 結束。
密鑰管理器
根據預設,伺服器會將 vault 憑證的密鑰儲存在其資料庫中。若有 secret_store 區段,伺服器會將每個新 vault 憑證的密鑰寫入您的密鑰管理器,並使用您為其保留的名稱前綴。資料庫僅保留一個參照。
將您密鑰管理器的區塊新增至設定檔:
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/token請僅設定三種登入方法中的一種:
approle: 搭配 Docker Compose、在主機上,或搭配伺服器 Helm chart 使用。伺服器會以角色 ID,以及從檔案讀取的密鑰 ID 登入。kubernetes: 僅在您自行安裝的 Kubernetes 上使用,且其伺服器 pod 須具有服務帳戶權杖。伺服器會以該權杖登入。伺服器 Helm chart 不會為伺服器的 pod 提供此類權杖,因此此方法無法搭配該 chart 使用。token_file: 用於任何其他 Vault 登入方法。請在伺服器旁執行 Vault Agent,並讓它將其權杖寫入此檔案。
使用伺服器 Helm chart 時,請透過 Secret 將密鑰 ID 提供給伺服器:
- 將密鑰 ID 放入伺服器命名空間中的 Secret,並在 chart 的
server.extensionFiles.secretName中指定該 Secret 的名稱。 - 將
approle.secret_id_file設為密鑰 ID 的路徑。chart 會將該 Secret 的每個索引鍵掛載為/run/cma-server/extension-files/下的檔案,因此名為secret-id的索引鍵位於/run/cma-server/extension-files/secret-id。
對於 kubernetes 方法,請將 Vault Kubernetes 角色繫結至伺服器的命名空間和服務帳戶,而非沙箱的命名空間 cma。
授與存取權
為伺服器提供單一身分,並將其限制在該前綴。封存的 iam/ 目錄中為每個密鑰管理器提供一個檔案:
- AWS Secrets Manager: 替換
aws-secrets-manager-policy.json中的預留位置值,並將原則附加至伺服器執行時所用的身分。 - Google Cloud Secret Manager: 執行
gcp-secret-manager-role.yaml註解中的命令。 - Azure Key Vault: Azure 角色涵蓋整個金鑰保存庫,而非前綴。因此請為部署提供專屬的金鑰保存庫,且該金鑰保存庫須使用 Azure 角色型存取控制。請替換
azure-key-vault-role.json中的SUBSCRIPTION_ID,並以其建立自訂角色。在該金鑰保存庫上將此角色指派給伺服器執行時所用的身分。 - HashiCorp Vault: 替換
hashicorp-vault-policy.hcl中的預留位置值,並將原則附加至伺服器執行時所用的身分。
對於 AWS 和 Google Cloud,伺服器會以與推論相同的方式進行驗證。對於 Azure Key Vault,它會透過 Microsoft Entra ID 進行驗證,與 Microsoft Foundry 相同。
檢查設定
請在首次啟動前以及任何原則變更後執行 validate-store。它會在前綴下建立、讀取並刪除一個測試密鑰,而不會啟動伺服器。請在伺服器執行的位置,以伺服器的環境執行此命令:
-
Docker Compose: 在伺服器的容器中執行。在 Arm 上,請將此命令中的
linux_amd64替換為linux_arm64:docker compose exec cma-server /opt/cma-server/bin/linux_amd64/cma-server validate-store -config /etc/cma-server/config.yaml -
在主機上:
./cma-server validate-store -config /etc/cma-server/config.yaml -
Kubernetes: 以伺服器服務帳戶下的 Job 執行相同的命令。
通過的執行會以一行顯示 pass 的內容結束,並以代碼 0 結束。
使用 Azure Key Vault 時,請在依賴它之前針對您的金鑰保存庫執行此檢查。
密鑰管理器限制
-
設定只選擇一次。 進行下列任何變更後,伺服器將無法再找到其在變更前寫入的密鑰:
- 您移除
secret_store區段。 - 您變更
type、prefix、region、project、vault_url、mount或namespace。後兩者是選用的 HashiCorp Vault 設定。 - 您將
address指向另一個 Vault。
只有在您還原舊值後,伺服器才會再次找到這些密鑰。
- 您移除
-
單一身分可讀取整個前綴。 如果兩個群組不得存取彼此的憑證,請為每個群組提供各自的部署。每個部署都需要各自的前綴或金鑰保存庫和各自的身分。
環境變數憑證
透過環境變數憑證,代理的命令可以在沙箱僅持有密鑰預留位置值的情況下呼叫服務。出口閘道會將實際值放入傳送至憑證所列主機的請求中。
該閘道 cma-egress 是發行封存中的一個代理伺服器,位於您的沙箱與網際網路之間。它預設為關閉,且您的伺服器僅在閘道開啟時才接受這些憑證。
開啟閘道後,您的沙箱會受到兩項限制:
- 沙箱僅能透過閘道連線至網際網路。
- 閘道僅會連線至您在伺服器
egress.allowed_hostnames設定中列出的主機。
請列出確切的公開主機名稱,不使用萬用字元。請包含您代理的命令會從中下載內容的每個主機。
如果您建置了自己的沙箱映像檔,請透過 cma-with-egress 啟動 worker,如建置您自己的沙箱映像檔所示。
在 Compose 堆疊中開啟閘道
在包含 docker-compose.yml 的目錄中,於 .env 新增兩行。第一行列出閘道會連線的主機,以逗號分隔。第二行會載入閘道的 Compose 檔案。然後啟動堆疊:
echo 'CMA_EGRESS__ALLOWED_HOSTNAMES=api.github.com' >> .env
echo 'COMPOSE_FILE=docker-compose.yml:docker-compose.egress.yml' >> .env
docker compose up --build -d如果您也使用其他 Compose 檔案,請將其加入 COMPOSE_FILE 這一行。Shell 中的 COMPOSE_FILE 變數會覆寫 .env 中的變數,因此請取消設定 shell 中的該變數。
閘道的檔案會設定伺服器的其他 egress 設定,因此請勿在 compose.config.yaml 中新增 egress 區段。
在 Kubernetes 上開啟閘道
這些步驟以在 Kubernetes 上部署中的部署為起點。它們使用該頁面的 REGISTRY、TAG 和 PLATFORM 變數及其兩個 values 檔案。請在封存的最上層目錄中,以 OpenSSL 3.0 或更新版本執行這些命令。沙箱 chart 在 Azure Kubernetes Service (AKS) 上不提供閘道。
這些步驟中伺服器 chart 的升級也會在伺服器的 pod 上新增一個網路原則。開始之前,請檢查它涵蓋的其中兩個連接埠:
- 連接埠 9464(指標連接埠): 該原則會關閉此連接埠。如果 Prometheus 會抓取該連接埠,請在
cma-server-values.yaml中將server.telemetry.prometheus.scraper.namespace設為 Prometheus 執行所在的命名空間。 - 連接埠 8400(API 的連接埠): 該原則會允許所有來源。如果您自己的原則限制了誰能連線至連接埠 8400,該限制將會失效。網路原則會累加,因此只要任何一個原則允許某個連線,該連線就能通過。
建置並推送閘道的映像檔
docker buildx build --platform "$PLATFORM" -f kubernetes/egress/Dockerfile -t "$REGISTRY/cma-egress:$TAG" --push .建立憑證授權單位和閘道金鑰
(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_KEY然後刪除
egress-ca.key,也就是「certificate authority」(憑證授權單位)的私密金鑰。任何持有它的人,都可以對您的沙箱冒充任何網站。該憑證的有效期為 825 天。請參閱更新憑證。移除先前工作階段的沙箱
如果該環境尚未執行任何工作階段,請略過此步驟。變更之前建立的沙箱在變更之後無法啟動其 worker。這些命令也會刪除每個沙箱的工作區:
kubectl -n cma scale deployment cma-dispatcher --replicas=0 kubectl -n cma delete sandboxwarmpool cma-sandbox kubectl -n cma delete sandboxclaims --all在 Google Kubernetes Engine (GKE) 上,也請執行此命令:
kubectl -n cma delete sandboxes --all重複執行
kubectl -n cma get sandboxes,pods,pvc,直到找不到任何項目為止。「開啟沙箱端」步驟中的helm upgrade會再次啟動 dispatcher。開啟伺服器端
為閘道在叢集的 Service 範圍內選擇一個可用的 IPv4 位址。
kubectl get svc -A的CLUSTER-IP欄會顯示該範圍內的位址。將以下內容新增至cma-server-values.yaml。如果該檔案已有server區塊,請將這些行合併至其中:egressGateway: enabled: true proxyAddress: 34.118.224.53:3128 # the address that you chose, and port 3128 server: config: egress: allowed_hostnames: - api.github.com然後執行升級:
helm upgrade cma-server kubernetes/server/chart --namespace cma-server -f cma-server-values.yaml --wait開啟沙箱端
執行
kubectl -n cma-server get svc以列出伺服器的兩個 Service。在新安裝中,它們的名稱為cma-server和cma-server-egress。在
cma-values.yaml中,將egress.mode變更為gateway,並在egress下新增gateway區塊。在該區塊中填入該命令列出的兩個名稱: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 endpoint保留該檔案的其他
egress值。若要印出 API 端點的位址和連接埠,請執行kubectl get endpoints kubernetes -n default。如果連接埠不是 443,也請設定egress.gateway.apiServerPort。helm upgrade cma kubernetes/chart --namespace cma -f cma-values.yaml --wait如果升級因
.spec.replicas的衝突而停止,請執行kubectl -n cma scale deployment cma-dispatcher --replicas=1,然後再次執行升級。
新增憑證
依照新增憑證所示建立環境變數憑證。託管服務的指南表示,這些憑證不支援自行託管的沙箱。該說明描述的是託管服務,而非您的伺服器。
您的伺服器會新增自己的規則。它會以指出該欄位的 400 錯誤拒絕違反規則的請求。其中兩條規則如下:
networking的類型必須為limited,且allowed_hosts中的每個主機都必須在伺服器的egress.allowed_hostnames清單上。injection_location在 JSON 中必須為{"header": true},且不能省略。
將主機新增至伺服器的清單後,請套用變更。在 Docker Compose 上,請執行 docker compose up -d。在 Kubernetes 上,請執行伺服器的 helm upgrade 命令和 kubectl -n cma-server rollout restart deployment -l anthropic.com/role=server。
檢查輸出閘道
使用該憑證的保管庫建立工作階段,並要求代理執行兩個命令。此範例適用於名為 GITHUB_TOKEN 且列出 api.github.com 的憑證:
printenv GITHUB_TOKEN
curl -sS -H "Authorization: Bearer $GITHUB_TOKEN" https://api.github.com/user第一個命令會印出以 cma_ph_ 開頭的預留位置值。第二個命令會印出該權杖所屬 GitHub 帳戶的個人資料,因為閘道已將預留位置值替換為權杖。閘道會以 403 錯誤拒絕傳送至不在您清單上之主機的請求。
在 Kubernetes 上,如果每個請求都收到 503 錯誤,您叢集的網路可能會改寫 pod 的位址,就像 kube-proxy 的 --masquerade-all 選項所做的那樣。閘道會依據 pod 的位址區分沙箱,因此這些位址必須在未經變更的情況下到達閘道。
更新憑證
在 Kubernetes 上,請在沒有任何工作階段執行時更新憑證。重複在 Kubernetes 上開啟閘道中的整個「建立憑證授權單位和閘道金鑰」步驟。該步驟會再次建立憑證授權單位和閘道金鑰,因此您不需要已刪除的 egress-ca.key 檔案。請做一項變更:在執行 kubectl create 的四行中,於每一行的結尾加上 --dry-run=client -o yaml | kubectl apply -f -。例如,原本以 --from-file=gateway-key=/dev/stdin 結尾的行,會改為以 --from-file=gateway-key=/dev/stdin --dry-run=client -o yaml | kubectl apply -f - 結尾。
然後重新啟動伺服器和閘道:
kubectl -n cma-server rollout restart deployment -l anthropic.com/role=server
kubectl -n cma rollout restart deployment/cma-egress輸出閘道限制
- 標頭: 閘道只會將值放入請求標頭,絕不會放入 URL 或主體。預設情況下,唯一的標頭是
Authorization。若要允許其他標頭,請將它們與Authorization一起列在egress.swap_header_names中,或針對 Compose 堆疊列在.env的CMA_EGRESS__SWAP_HEADER_NAMES中。 - 忽略代理變數的程式: 沙箱透過
HTTPS_PROXY及相關變數找到閘道。Maven 和 Gradle 等 Java 工具不會讀取這些變數,因此這些工具無法連線到任何地方。
這個頁面有幫助嗎?