CI や Kubernetes から Claude API を呼ぶとき、sk-ant-... で始まる静的な API キーをシークレットとして置いている構成は多い。Workload Identity Federation(WIF)は、その代わりに自分がすでに運用している ID プロバイダ(IdP)が発行する短命の OIDC トークンを使って認証する仕組みで、2026年に一般提供(GA)になった。
このページでは、先に作る3つの資材、交換の流れと環境変数、既存の API キーからの移行手順、そしてトークンの寿命と更新までを順に見ていく。
静的なAPIキーの何が問題か
API キーの問題は、単に「漏れると危ない」ことではない。期限が無いことである。一度発行した sk-ant-... は、明示的に失効させるまで永久に有効で、CI のシークレット、コンテナの環境変数、開発者のシェル設定、過去のログと、置かれた場所すべてに同じ強さのまま残り続ける。
WIF はこの前提を入れ替える。ワークロードは IdP が署名した JWT を提示し、Anthropic はそれを Console 側で設定した信頼ルールと突き合わせて、数分から数十分で失効する短命のアクセストークンを返す。CI に置くべき静的なシークレットが無くなるので、作る・保管する・回す・漏らす、という一連の作業そのものが消える。
ただし公式ドキュメントは、これが単独で完結するセキュリティ対策ではないことも明記している。フェデレーション認証の強さは、JWT に署名する上流の IdP の強さを超えない。ワークロードのID紐付け、条件付きアクセス、監査ログといった IdP 側の統制と組み合わせて多層で守る前提である。
対応する IdP は、AWS IAM、Google Cloud、Microsoft Entra ID、GitHub Actions、Kubernetes、SPIFFE、Okta など、標準に準拠した OIDC 発行者であれば広く使える。
先に作る3つの資材
ワークロードがフェデレーションできるようになる前に、Claude Console で3つの資材を作る。この3つで「発行者 X が署名し、クレームが Y の形をしたトークンは、サービスアカウント Z として振る舞ってよい」という文を組み立てる。
サービスアカウント(svac_...)
組織の中の、人ではない名前付きの主体である。フェデレートされたトークンが「誰として」振る舞うかを表す。組織レベルに存在し、ワークスペースのメンバーに追加すると、そのワークスペースで有効になる。メールもパスワードも Console へのログインも持たない。
API キーとの違いを一文で言うと、API キーは資格情報そのものだが、サービスアカウントは資格情報を必要に応じて発行してもらう対象である。どのワークロードがどのサービスアカウントとして動いたかを監査できるのは、この違いから来る。
フェデレーション発行者(fdis_...)
OIDC の ID プロバイダを組織に登録する。設定は2つで、JWT に現れる iss クレームの値そのもの(例: https://token.actions.githubusercontent.com)と、署名検証用の公開鍵をどう取得するかである。
鍵の取得方法は3種類ある。既定の discovery は、発行者 URL の /.well-known/openid-configuration を読む。explicit_url は JWKS エンドポイントを直接指す。inline は鍵セットそのものを貼り付ける形で、公開インターネットから到達できない私設 Kubernetes クラスタなどのためにある。
Anthropic が取りに行く URL は https・ポート443・公開DNSのホスト名である必要があり、IPリテラルは受け付けない。ただしこの制約が掛かるのは実際に取得する URL だけで、explicit_url と inline のときの issuer_url は文字列比較なので内部のホスト名でも構わない。
発行者は環境ごとに1つ登録するのが普通である。本番の EKS クラスタ、ステージングのクラスタ、GitHub Actions は、それぞれ別の発行者になる。
フェデレーションルール(fdrl_...)
発行者とサービスアカウントを橋渡しする。マッチ条件・対象・権限の3つを持つ。
- マッチ:
subject_prefix(末尾に*を付けると前方一致)、厳密なaudience、クレームの完全一致マップ、複雑な条件のための CEL 式condition、またはその組み合わせ。subject_prefix/claims/conditionのうち少なくとも1つは必須で、設定したマッチャはすべて通る必要がある。 - 対象: マッチした JWT が写像されるサービスアカウント。
- 権限: 発行されるトークンの OAuth スコープ。既定は
workspace:developerで、そのワークスペース向けの API キーと同じ範囲になる。あわせてtoken_lifetime_seconds(60〜86400・既定3600)を設定する。
ここで押さえておきたいのは、ルールは自動で探索されないことである。クライアントが交換リクエストでどのルールを使うかを指定し、Anthropic はその JWT が指定されたルールの条件を満たすかだけを検証する。1つの発行者に、チーム別・名前空間別・権限レベル別に複数のルールをぶら下げる形になる。
Console の「Connect workload」ウィザードを使うと、この3つを1つの流れで作れる。ウィザードは作成後15分間、実際のトークン交換が来るのを待って接続を確認する。ここで作られるルールID(fdrl_...)とサービスアカウントID(svac_...)は、以後ワークロードが毎回の交換で渡す値なので控えておく。
交換の流れと環境変数
実行時の流れは3段である。
- IdP がワークロードに JWT を発行する。 多くのプラットフォームではこれは環境から自然に得られる。Kubernetes の projected service-account トークン、Google Cloud のメタデータサーバ、Azure の IMDS、GitHub Actions の OIDC エンドポイントなどである。
- SDK が JWT をアクセストークンへ交換する。
POST /v1/oauth/tokenに対し、RFC 7523 のjwt-bearerグラントで投げる。Anthropic は発行者の JWKS とルールのマッチ条件で検証し、sk-ant-oat01-...で始まる短命のトークンを返す。 - SDK がそのトークンを毎リクエストに付け、期限前に交換をやり直す。 アプリケーション側のコードは
api_keyを渡さずにクライアントを構築するだけでよい。
本番のワークロードで推奨されているのは引数なしでクライアントを構築する形である。同じコンテナイメージをどの環境にも配り、環境変数だけを環境ごとに注入する。
ANTHROPIC_FEDERATION_RULE_ID
ANTHROPIC_ORGANIZATION_ID
ANTHROPIC_SERVICE_ACCOUNT_ID
ANTHROPIC_WORKSPACE_ID
ANTHROPIC_IDENTITY_TOKEN_FILE
この形なら、コードは次の1行で済む。
from anthropic import Anthropic
client = Anthropic()
資格情報を明示したいときは WorkloadIdentityCredentials を渡す。
from anthropic import Anthropic, WorkloadIdentityCredentials, IdentityTokenFile
client = Anthropic(
credentials=WorkloadIdentityCredentials(
identity_token_provider=IdentityTokenFile(
"/var/run/secrets/anthropic.com/token"
),
federation_rule_id="fdrl_...",
organization_id="00000000-0000-0000-0000-000000000000",
service_account_id="svac_...",
workspace_id="wrkspc_...",
),
)
message = client.messages.create(
model="claude-opus-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello, Claude"}],
)
SDK が無い言語やシェルスクリプトからは、交換を直接叩ける。
JWT=$(cat /var/run/secrets/anthropic.com/token)
RESPONSE=$(curl -sS https://api.anthropic.com/v1/oauth/token \
-H "content-type: application/json" \
-d @- <<JSON
{
"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_..."
}
JSON
)
ACCESS_TOKEN=$(jq -r .access_token <<<"$RESPONSE")
得たトークンは x-api-key ではなく authorization: Bearer ヘッダで送る。API キーからの書き換えは、キーの差し替えではなくヘッダの差し替えである点に注意する。
curl -sS https://api.anthropic.com/v1/messages \
-H "authorization: Bearer $ACCESS_TOKEN" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{"model":"claude-opus-5","max_tokens":1024,"messages":[{"role":"user","content":"Hello, Claude"}]}'
ANTHROPIC_WORKSPACE_ID は、フェデレーションの有効化そのものには関与しない。ルールが複数のワークスペースにまたがるときに必要で、その場合に省くと 400 workspace_id_required が返る。単一ワークスペースのルールなら省略できる。
APIキーから移行する
移行でいちばん引っかかるのは、資格情報の優先順位である。SDK はどの言語でも同じ5段で解決する。
- コンストラクタ引数
ANTHROPIC_API_KEY/ANTHROPIC_AUTH_TOKEN- 明示された
ANTHROPIC_PROFILE - フェデレーションの環境変数
- 暗黙の有効なプロファイル
最初に資格情報を返した段が勝つ。ここで重要なのは、ANTHROPIC_API_KEY がフェデレーションより上にあることである。環境に残った古いキーは、エラーも警告も出さずにフェデレーションを覆い隠す。「設定したのに効かない」の大半はこれである。
無停止で切り替える手順は次のとおり。
- 並行して構成する。 発行者・サービスアカウント・ルールを作り、ワークロードのトークンがルールにマッチすることを確認する。既存の
ANTHROPIC_API_KEYはまだ残しておく。 - どちらが勝っているかを実測する。 ワークロードの中から
ant auth statusを実行する。この段階では優先順位のとおり API キーが勝っている。 ANTHROPIC_API_KEYを注入している場所すべてから外す。 CI のシークレット、コンテナの環境変数、シェルの設定。外したらant auth statusを再実行し、今度はフェデレーションが選ばれていることを確認する。- API キーを失効させる。 フェデレーションで動いていることを確認してから、Console の Settings → API keys で削除する。
3段目を「外したつもり」で終わらせないこと。ant auth status はどの資格情報源が採用されたかを実際に報告するので、これを見ずに次へ進むと、キーを失効させた瞬間に落ちる。
トークンの寿命と更新
発行されるトークンの寿命は、次の2つのうち短いほうになる。
- ルールの
token_lifetime_seconds(既定3,600秒) - 提示した IdP の JWT の残り寿命の2倍
ただし結果が60秒を下回ることはない。2つ目の上限があるのは、Anthropic 側のトークンが、その根拠となった上流のIDより長く生き続けることを防ぐためである。
SDK はトークンをキャッシュし、botocore にならった2段階で更新する。
- 予告更新: 期限の120秒前に交換をやり直す。ここで交換エンドポイントに到達できなくても、キャッシュ済みのトークンはまだ90秒ほど有効なので、SDK はそのまま使い続ける。
- 強制更新: 期限の30秒前。この時点での交換失敗はエラーになる。期限に近すぎて使い続けるのが安全でないためである。
この2段構えは、「一時的にネットワークが揺れただけ」と「本当に交換できない」を区別するためのものである。1段だけだと、前者でリクエストが落ちるか、後者を見逃して期限切れのトークンを送るかのどちらかになる。
もうひとつ実務上ありがたい性質として、SDK は交換のたびに ANTHROPIC_IDENTITY_TOKEN_FILE を読み直す。Kubernetes の projected service-account トークンは exp よりかなり前に回されるが、読み直すので回転が透過的に取り込まれる。ファイルを起動時に一度だけ読む実装だと、ここで詰まる。
プロバイダ別の JWT の取り方、クレームの形、発行者とルールの設定は、公式の各プロバイダ別ガイド(AWS / Google Cloud / Microsoft Entra ID / GitHub Actions / Kubernetes / SPIFFE / Okta)に分かれている。3つの資材と環境変数の考え方はどのプロバイダでも共通なので、この記事の内容を土台に、自分の環境のガイドを読むとよい。
一次情報は公式ドキュメントの Workload Identity Federation と、環境変数・プロファイルのスキーマ・検証ルール・エラーコードをまとめた WIF reference にある。本ページは非公式の日本語解説なので、仕様の細部は必ず原典で確認すること。