
Claude API Workload Identity Federation を使って AWS Lambda からClaude APIキーなしでClaudeを動かしてみた
こんにちは、せーのです。
前回は、Claude API Workload Identity Federation(以下 WIF)を使って、GitHub Actions から API キーなしで Claude API を呼び出しました。
今回はその第二弾として、AWS Lambda から API キーなしで Claude API を呼んでみたいと思います。
結論から言うと、Lambda でも問題なく動きました。ですが、GitHub Actions 編とは違って、AWS 側ならではのハマりどころがいくつかあります。この記事ではそのあたりを Tips 多めでまとめます。
前回との違い
前回(GitHub Actions 編)は、GitHub が発行する OIDC トークンを使って Anthropic 側の短命トークンに交換しました。
今回は、AWS STS の GetWebIdentityToken で発行した JWT を使います。
流れだけ並べると次のとおりです。

- Lambda が STS から Web Identity Token(JWT)を取得
- その JWT を Anthropic の
/v1/oauth/tokenに渡す - Anthropic から
sk-ant-oat01-...の短命アクセストークンを受け取る - そのトークンで Claude Messages API を呼ぶ
違いを整理すると、GitHub Actions 編は「GitHub OIDC を使う」、AWS Lambda 編は「STS GetWebIdentityToken を使う」、というイメージです。
Workload Identity Federation とは(おさらい)
WIF は、ざっくり言うと「実行環境がその場で手に入れた短命 JWT を、Claude API 用の短命トークンに交換する仕組み」です。
つまり、sk-ant-... の長期 API キーを Secrets に置き続ける運用から離れやすくなります。
今回のような Lambda 実行基盤でも、この交換フローを組み込めば API キーレスで呼び出せます。
今回のゴール
今回のスモークテストのゴールはシンプルです。
- Lambda から
ANTHROPIC_API_KEYなしで呼ぶ Anthropic WIF on AWS Lambda smoke test OK.が返る- CloudWatch Logs で実行完了を確認する
全体構成
今回作る要素は次の 4 つです。
- AWS 側: Outbound web identity federation を有効化
- AWS 側: Lambda 実行ロール(
sts:GetWebIdentityTokenを付与) - Anthropic 側: Federation Issuer / Service Account / Federation Rule
- Lambda 実装:
WorkloadIdentityCredentialsで実行
やってみた
1. AWS 側の前提設定(ここが最初の落とし穴)
GetWebIdentityToken は、アカウント設定の Outbound web identity federation がデフォルトで無効です。
有効化前に確認すると、次のようなエラーになります。
FeatureDisabledException: Outbound identity federation is disabled for account ...
有効化は IAM クライアントから実行できます。
import boto3
iam = boto3.client("iam", region_name="us-east-1")
iam.enable_outbound_web_identity_federation()
その後、Issuer 情報を取得すると、アカウント固有の Issuer URL が払い出されます。
https://<uuid>.tokens.sts.global.api.aws
この URL をあとで Anthropic 側の Federation Issuer として登録します。

2. IAM Role を作る
Lambda 実行ロールに、少なくとも次の権限が必要です。
{
"Effect": "Allow",
"Action": ["sts:GetWebIdentityToken"],
"Resource": "*"
}
今回の sub は IAM Role ARN になるので、この ARN があとで Federation Rule の subject_prefix 設計に効いてきます。
arn:aws:iam::<account-id>:role/claude-wif-lambda-role
3. Anthropic Console で3点セットを作る
前回と同じく、次の 3 つを作ります。
- Federation Issuer(
fdis_...) - Service Account(
svac_...) - Federation Rule(
fdrl_...)
今回の AWS 向けでは、要点はここです。
issuer_url: AWS のアカウント固有 Issuer URL(https://<uuid>.tokens.sts.global.api.aws)audience:https://api.anthropic.com(完全一致)subject_prefix: Lambda 実行ロール ARN に寄せて狭く

4. Lambda 実装(Python SDK)
今回は Python SDK の WorkloadIdentityCredentials を使いました。
import os
import anthropic
import boto3
from anthropic import WorkloadIdentityCredentials
def get_sts_web_identity_token() -> str:
sts = boto3.client("sts", region_name="us-east-1")
resp = sts.get_web_identity_token(
Audience=["https://api.anthropic.com"],
SigningAlgorithm="RS256",
DurationSeconds=900,
)
return resp["WebIdentityToken"]
client = anthropic.Anthropic(
credentials=WorkloadIdentityCredentials(
identity_token_provider=get_sts_web_identity_token,
federation_rule_id=os.environ["ANTHROPIC_FEDERATION_RULE_ID"],
organization_id=os.environ["ANTHROPIC_ORGANIZATION_ID"],
service_account_id=os.environ["ANTHROPIC_SERVICE_ACCOUNT_ID"],
),
)
lambda_handler では固定文を返すスモークテストを実行しました。
def lambda_handler(event, context):
message = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=64,
messages=[
{
"role": "user",
"content": "Respond with exactly this sentence: Anthropic WIF on AWS Lambda smoke test OK.",
}
],
)
return {"statusCode": 200, "body": message.content[0].text}
5. デプロイと実行確認
invoke 結果は次のとおりでした。
{"statusCode": 200, "body": "Anthropic WIF on AWS Lambda smoke test OK."}
CloudWatch Logs 側でも正常終了しています。
START RequestId: ...
END RequestId: ...
REPORT RequestId: ...
Duration: 2490.17 ms
Init Duration: 1316.33 ms
無事、API キーなしで Lambda から Claude API 呼び出しが通りました。
AWSでWIFを使うときのTips(ここが本題)
ここからは、今回やっていて「ここで詰まりやすい」と感じたポイントです。
1. Outbound web identity federation はデフォルト無効
まずここを有効化しないと、GetWebIdentityToken に進めません。
GitHub Actions 編だとこのステップが不要だったので、同じ感覚で入ると地味にハマります。
2. STS クライアントはリージョンを明示する
get_web_identity_token を使うときは、リージョナル STS を使う前提で region_name を明示した方が安全です。
sts = boto3.client("sts", region_name="us-east-1")
この指定が曖昧だと、環境依存でエラーになるケースがあります。
3. audience は https://api.anthropic.com で完全一致
これは前回記事でも触れましたが、今回も最重要です。
https://api.anthropic.com
api.anthropic.com(スキームなし)とは別物です。
JWT 側の aud と Rule 側の audience が一致しないと、トークン交換で invalid_grant になりやすいです。
4. subject は広げすぎない
AWS の場合 sub が IAM Role ARN になるため、subject_prefix をロール ARN に寄せて狭く切ると設計しやすいです。
例えば次のように、対象ロールを明確にするイメージです。
arn:aws:iam::<account-id>:role/claude-wif-lambda-role
「とりあえず広く許可」より、最初から狭く作って必要に応じて広げる方が安心です。
5. Lambda パッケージは Linux ターゲットでビルドする
これは認証そのものではないですが、実装時に効く Tips です。
macOS でそのまま作った zip を Lambda に上げると、pydantic_core などのネイティブ依存でこけることがあります。Docker で linux/arm64 を指定してビルドすると安定しました。
docker run --platform linux/arm64 --rm \
-v $(pwd):/work python:3.12-slim \
bash -c "pip install 'anthropic>=0.98.0' boto3 -t /work/package/ -q"
6. anthropic>=0.98.0 を明示しておく
WorkloadIdentityCredentials を使うので、バージョン要件は明示しておくのが安全です。
anthropic>=0.98.0
今回の実験では 0.99.0 で実施しました。
7. 移行時は ANTHROPIC_API_KEY の残存に注意
移行フェーズで「設定したのに WIF が使われない」場合、既存の ANTHROPIC_API_KEY が残っているケースがあります。
空文字でも枠を占有する挙動があるため、ANTHROPIC_API_KEY="" ではなく unset する つもりで整理するのが無難です。
まとめ
AWS Lambda でも、Claude API Workload Identity Federation を使って API キーなしで呼び出せました。
今回の学びを要点だけ並べると、次の 4 つです。
- AWS 編では、まず Outbound web identity federation 有効化が入口
- 認証の成否は
audienceとsubjectの設計でほぼ決まる - SDK 実装は薄く書けるが、Lambda パッケージングの罠は別である
- API キー移行時は優先順位(残存環境変数)まで確認しておくと安心
前回の GitHub Actions 編と合わせると、「実行基盤ごとに JWT の取り方は違うが、Claude 側の交換フローは同じ」 という整理がしやすくなった気がします。
Lambda や ECS で Claude API を直接呼んでいる方は、まず小さめの関数で今回のスモークテストを通してみると、導入の見通しが立てやすいはずです。









