エージェントアイデンティティと認証情報
セルフホスト型のClaude Managed Agentsサーバーに、各エージェントを識別する有効期間の短いトークンへ署名させ、ボールトの認証情報をシークレットマネージャーに保管し、エグレスゲートウェイでシークレットをサンドボックスの外に保ちます。
このページでは、サーバーの外部にあるシステムがエージェントを信頼できるようにする方法と、エージェントが使用する認証情報の保管場所を示します:
- エージェントアイデンティティ:MCPサーバーまたはゲートウェイが、各エージェントに個別のアクセス権を付与できるようにします。サーバーがエージェントを識別する有効期間の短いトークンに署名します。
- シークレットマネージャー:サーバーは、ボールトの認証情報をAWS Secrets Manager、Google Cloud Secret Manager、HashiCorp Vault、またはAzure Key Vaultに保管します。
- 環境変数の認証情報:サンドボックスがプレースホルダーのみを保持した状態で、エージェントのコマンドがサービスを呼び出せるようにします。「egress gateway」(エグレスゲートウェイ)が実際の値をエージェントのリクエストに挿入します。
エージェントアイデンティティ
サーバーは、エージェントを識別する有効期間の短い「JSON Web Token」(JSONウェブトークン)、すなわちJWTに署名し、そのエージェントのMCP呼び出しとともに送信できます。受信側(MCPサーバーまたはゲートウェイ)は、あなたが公開する公開鍵を使ってトークンを検証し、その後、各エージェントに個別のアクセス権を付与できます。
発行者を設定する
-
「issuer」(発行者)のURLを選択します。 手順3でこのURLに公開鍵を公開し、受信側はこのURLから公開鍵を取得します。静的なWebホストで問題ありません。サーバーは受信側が取得するパスで鍵を配信しないため、サーバーのアドレスは使用しないでください。パスや末尾のスラッシュのない
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サービスがそのリストを読み取らなくなるため、そのブロックでも同じ変更を行ってください。- macOS上のDocker Desktopまたはrootless Dockerを使用している場合を除き、
agent-identityがあるディレクトリでsudo chown -R root:root agent-identityを実行します。
kubectl -n cma-server create secret generic cma-agent-identity --from-file=agent-identity/signing-key.pemを実行します。次に、サーバーチャートの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は、1つの受信側を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>として送信されます。モデルもワーカーもこのトークンを受け取りません。
トークンとボールト認証情報の両方を送信するには、authフィールドをagent_token_headerフィールドに置き換えます:
mcp_servers:
- type: url
name: tickets
url: https://mcp-gateway.example.com/tickets
agent_token_header:
audience: https://mcp-gateway.example.comボールト認証情報は、どちらのフィールドもないエントリの場合と同様に、Authorizationヘッダーに入れて送信されます。トークンはBearerプレフィックスなしでAgent-Identity-Tokenヘッダーに入れて送信されます。
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であること。
次に、以下のルールを適用してください:
- 各エージェントのアクセスルールは、API上のエージェントのIDである
agent_idクレームに基づいて設定してください。 - 1回の一覧取得または呼び出しで、同じトークンを使って複数のリクエストが行われることがあるため、繰り返される
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このコマンドは、送信するリクエストごとに1行を、ゲートウェイの応答とともに出力します。成功した実行は、その後check-gateway: PASSで始まる行を出力し、コード0で終了します。失敗した実行は、check-gateway:で始まる行に問題の内容を示し、コード1で終了します。
シークレットマネージャー
デフォルトでは、サーバーはボールトの認証情報のシークレットをデータベースに保存します。secret_storeセクションを設定すると、サーバーは新しいボールト認証情報それぞれのシークレットを、そのために予約した名前プレフィックスの下で、シークレットマネージャーに書き込みます。データベースには参照のみが保持されます。
使用するシークレットマネージャーのブロックを設定ファイルに追加します:
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/token3つのログインメソッドのうち、1つだけを設定してください:
approle: Docker Compose、ホスト上、またはサーバーHelmチャートで使用します。サーバーはロールIDと、ファイルから読み取るシークレットIDでログインします。kubernetes: サーバーのPodにサービスアカウントトークンがある、独自のKubernetesインストールでのみ使用します。サーバーはそのトークンでログインします。サーバーHelmチャートはサーバーのPodにそのようなトークンを付与しないため、このメソッドはチャートでは機能しません。token_file: その他のVaultログインメソッドに使用します。サーバーの横でVault Agentを実行し、Vault Agentにトークンをこのファイルへ書き込ませます。
サーバーHelmチャートでは、シークレットIDをSecretでサーバーに渡します:
- シークレットIDをサーバーの名前空間のSecretに格納し、そのSecretの名前をチャートの
server.extensionFiles.secretNameに指定します。 approle.secret_id_fileをシークレットIDのパスに設定します。チャートはそのSecretの各キーを/run/cma-server/extension-files/の下にファイルとしてマウントするため、secret-idという名前のキーは/run/cma-server/extension-files/secret-idにあります。
kubernetesメソッドの場合は、VaultのKubernetesロールを、サンドボックスの名前空間cmaではなく、サーバーの名前空間とサービスアカウントにバインドします。
アクセスを付与する
サーバーに1つのアイデンティティを付与し、そのアクセス範囲をプレフィックスに限定します。アーカイブの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 Foundryの場合と同様に、Microsoft Entra IDで認証します。
セットアップを確認する
最初の起動前と、ポリシーを変更した後には、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を変更する。最後の2つは、HashiCorp Vaultのオプション設定です。addressを別のVaultに向ける。
古い値を元に戻した場合にのみ、サーバーはそれらのシークレットを再び見つけられます。
-
1つのアイデンティティがプレフィックス全体を読み取ります。 2つのグループが互いの認証情報にアクセスできてはならない場合は、各グループに独自のデプロイメントを用意してください。各デプロイメントには、独自のプレフィックスまたはキーボールトと独自のアイデンティティが必要です。
環境変数の認証情報
環境変数の認証情報を使用すると、サンドボックスがシークレットのプレースホルダーのみを保持した状態で、エージェントのコマンドがサービスを呼び出せます。エグレスゲートウェイは、認証情報に記載されたホストへのリクエストに実際の値を挿入します。
ゲートウェイcma-egressは、リリースアーカイブに含まれるプロキシで、サンドボックスとインターネットの間に位置します。ゲートウェイはデフォルトでは無効であり、サーバーはゲートウェイが有効な場合にのみこれらの認証情報を受け付けます。
ゲートウェイを有効にすると、サンドボックスに2つの制限が適用されます:
- サンドボックスはゲートウェイ経由でのみインターネットにアクセスします。
- ゲートウェイは、サーバーの
egress.allowed_hostnames設定に記載したホストにのみ接続します。
ワイルドカードを使わず、正確なパブリックホスト名を記載してください。エージェントのコマンドがダウンロード元とするすべてのホストを含めてください。
独自のサンドボックスイメージを構築した場合は、独自のサンドボックスイメージを構築するに示すとおり、cma-with-egressを介してワーカーを起動してください。
Composeスタックでゲートウェイを有効にする
docker-compose.ymlがあるディレクトリから、.envに2行を追加します。1行目には、ゲートウェイの接続先となるホストをカンマで区切って記載します。2行目は、ゲートウェイの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の行に追加してください。シェルのCOMPOSE_FILE変数は.env内の変数より優先されるため、シェルの変数の設定を解除してください。
ゲートウェイのファイルがサーバーのその他のegress設定を行うため、compose.config.yamlにegressセクションを追加しないでください。
Kubernetesでゲートウェイを有効にする
これらの手順は、Kubernetesにデプロイするのデプロイを出発点とします。そのページのREGISTRY、TAG、PLATFORM変数と、2つのvaluesファイルを使用します。コマンドは、OpenSSL 3.0以降を使用して、アーカイブの最上位ディレクトリから実行してください。サンドボックスチャートは、Azure Kubernetes Service(AKS)ではゲートウェイを提供しません。
これらの手順でのサーバーチャートのアップグレードでは、サーバーのPodに対するネットワークポリシーも追加されます。開始する前に、このポリシーが対象とするポートのうち2つを確認してください:
- ポート9464(メトリクスのポート): ポリシーはこのポートを閉じます。Prometheusがそのポートをスクレイプする場合は、
cma-server-values.yamlでserver.telemetry.prometheus.scraper.namespaceを、Prometheusが実行される名前空間に設定してください。 - ポート8400(APIのポート): ポリシーはすべての送信元を許可します。独自のポリシーでポート8400にアクセスできる送信元を制限している場合、その制限は機能しなくなります。ネットワークポリシーは加算的に適用されるため、いずれか1つのポリシーが許可すれば接続は通過します。
ゲートウェイのイメージをビルドしてプッシュする
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を削除します。これを保持する者は誰でも、サンドボックスに対して任意のWebサイトになりすますことができます。証明書の有効期間は825日です。証明書を更新するを参照してください。以前のセッションのサンドボックスを削除する
環境でセッションを一度も実行していない場合は、この手順をスキップしてください。変更前のサンドボックスは、変更後にワーカーを起動できません。これらのコマンドは、各サンドボックスのワークスペースも削除します:
kubectl -n cma scale deployment cma-dispatcher --replicas=0 kubectl -n cma delete sandboxwarmpool cma-sandbox kubectl -n cma delete sandboxclaims --allGoogle Kubernetes Engine(GKE)では、次のコマンドも実行してください:
kubectl -n cma delete sandboxes --allkubectl -n cma get sandboxes,pods,pvcが何も見つけなくなるまで繰り返します。「サンドボックス側を有効にする」の手順のhelm upgradeで、ディスパッチャーが再び起動します。サーバー側を有効にする
クラスターの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を実行して、サーバーの2つのServiceを一覧表示します。新規インストールでは、それらの名前はcma-serverとcma-server-egressです。cma-values.yamlで、egress.modeをgatewayに変更し、egressの下にgatewayブロックを追加します。ブロックには、コマンドが一覧表示した2つの名前を指定します: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エラーで拒否されます。そのうち2つのルールを以下に示します:
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を実行します。
エグレスゲートウェイを確認する
認証情報のボールトを使用してセッションを作成し、エージェントに2つのコマンドを実行するよう依頼します。この例は、api.github.comを記載したGITHUB_TOKENという名前の認証情報の場合です:
printenv GITHUB_TOKEN
curl -sS -H "Authorization: Bearer $GITHUB_TOKEN" https://api.github.com/user最初のコマンドは、cma_ph_で始まるプレースホルダーを出力します。2番目のコマンドは、ゲートウェイがプレースホルダーをトークンに置き換えたため、トークンのGitHubアカウントのプロフィールを出力します。ゲートウェイは、リストにないホストへのリクエストを403エラーで拒否します。
Kubernetesで、すべてのリクエストが503エラーになる場合は、kube-proxyの--masquerade-allオプションのように、クラスターのネットワークがPodのアドレスを書き換えている可能性があります。ゲートウェイはPodのアドレスによってサンドボックスを区別するため、それらのアドレスが変更されずにゲートウェイに届く必要があります。
証明書を更新する
Kubernetesでは、セッションが実行されていない間に証明書を更新してください。Kubernetesでゲートウェイを有効にするの「認証局とゲートウェイの鍵を作成する」の手順全体を繰り返します。この手順で認証局とゲートウェイの鍵が再度作成されるため、削除したegress-ca.keyファイルは必要ありません。変更点は1つだけです。kubectl createを実行する4行それぞれの末尾に--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ツールはこれらの変数を読み取らないため、これらのツールはどこにもアクセスできません。
このページは役に立ちましたか?