
Azure環境からClaudeを呼び出す——Entra IDだけでBedrockを使う(AWSアクセスキー不要)
企業環境でAzureを主軸に使っている場合、「Claudeを使いたいがAWSのIAMユーザーやアクセスキーの管理はしたくない」というケースがある。Azure Entra IDのOIDCフェデレーションを使えば、Azure側の認証情報だけでAWS Bedrock上のClaudeを呼び出せる。AWS側の静的APIキーは一切発行しない。
この記事でわかること:
- Azure App Service・Functions・AKSなどからClaude(Bedrock)を呼ぶOIDC連携構成
- MSAL + boto3 で
AssumeRoleWithWebIdentityから Bedrock 呼び出しまでの検証スクリプト - 個人テナントでの制約と回避策、ハマりやすい4つのエラーと対処
前提: 本記事は Entra ID の v1.0 エンドポイント(
sts.windows.net)で検証している。v2.0 エンドポイント(login.microsoftonline.com/.../v2.0)を使う場合は Issuer URL・issクレーム・トークンバージョン設定が変わる点に注意。
なぜAPIキーを使わないのか
BedrockをAPIキーで利用する場合、IAMユーザーのアクセスキーとシークレットキーを発行して、アプリ側に埋め込む形になる。この方式には2つの問題がある。
- 流出リスク: ソースコードや設定ファイルにキーが残りやすく、GitHubへの誤プッシュなどで漏洩する
- ローテーション運用: 定期的に更新する仕組みを自前で用意しなければならない
Azure Entra IDのOIDCを使う方式では、静的なAPIキーを一切発行しない。AzureがOIDCトークンを発行し、それをAWS STSに渡すことで一時認証情報を取得してBedrockを呼ぶ。一時認証情報はデフォルト1時間(ロールの MaxSessionDuration で最大12時間まで延長可)で自動失効するため、ローテーション運用も不要になる。
仕組み
[アプリ(Azure App Service など)]
↓ ①クライアント認証情報でEntra IDにアクセス
[Azure Entra ID]
↓ ②OIDCトークン発行
[AWS IAM OIDC IDプロバイダ]
↓ ③トークン検証 → 一時認証情報払い出し(デフォルト1時間/最大12時間)
[Amazon Bedrock]
↓ ④API呼び出し
[Claude モデル]
AWS側では「このEntra IDテナントのトークンを信頼する」というOIDCプロバイダをIAMに登録しておく。アプリがトークンを持ってきたとき、STSがプロバイダの公開鍵で検証し、問題なければ一時認証情報を払い出す(AssumeRoleWithWebIdentity)。
AWS側の設定
1. OIDCプロバイダの追加
IAM → IDプロバイダ → 「プロバイダを追加」で以下を入力する。
| 項目 | 値 |
|---|---|
| プロバイダのタイプ | OpenID Connect |
| プロバイダのURL | https://sts.windows.net/<テナントID>/ |
| 対象者(Audience) | api://sts.amazonaws.com |
URLの末尾スラッシュを忘れずに。sts.windows.net はv1.0エンドポイントで、Azureの企業テナントで一般的に使われる。
2. IAMポリシーの作成
Bedrockの呼び出しに必要な最小権限のポリシーを作成する。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "bedrockInvokePolicy",
"Effect": "Allow",
"Action": [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream",
"bedrock:ListFoundationModels"
],
"Resource": [
"arn:aws:bedrock:*:*:foundation-model/*",
"arn:aws:bedrock:*:*:inference-profile/*"
]
},
{
"Sid": "ApplyGuardrail",
"Effect": "Allow",
"Action": ["bedrock:ApplyGuardrail"],
"Resource": "*"
}
]
}
3. IAMロールの作成
IAM → IDプロバイダのページから、作成したプロバイダを選んで「ロールの割り当て → 新しいロールを作成」を選ぶ。この手順だと信頼ポリシー(プロバイダURL・Audience)が自動入力されるので楽になる。
ロール作成後、「許可ポリシー」で手順2のポリシーをアタッチする。
作成完了後にロールのARN(arn:aws:iam::xxxxxxxxxxxx:role/BedrockInvokeRole)をコピーしておく。
Azure側の設定
1. アプリ登録
Azure Portal → Microsoft Entra ID → アプリ登録(App registrations)→ 新規登録でアプリを作成する。
2. Application ID URIの設定
「APIの公開」→「アプリケーション ID URI の追加」で以下を設定する。
api://sts.amazonaws.com
個人アカウントの場合: 上記URIは企業テナントのポリシーにより個人テナントでは設定不可。後述の回避策を参照。
3. クライアントシークレットの発行
「証明書とシークレット」→「新しいクライアントシークレット」でシークレットを作成する。表示される「値」(IDではない)を控えておく。
4. トークンバージョンの確認
「マニフェスト」を開き、accessTokenAcceptedVersion が null または 1 になっていることを確認する(v1.0トークンを受け入れる設定)。2 に設定されていると iss が login.microsoftonline.com/.../v2.0 のv2.0トークンが発行され、本記事で設定した sts.windows.net のOIDCプロバイダと不整合になる。
検証スクリプト
MSALとboto3を使ってフロー全体を確認するスクリプトを用意した。
pip install msal boto3
import msal
import boto3
import json
TENANT_ID = "your-tenant-id"
CLIENT_ID = "your-client-id"
CLIENT_SECRET = "your-client-secret" # シークレットの「値」
ROLE_ARN = "arn:aws:iam::xxxxxxxxxxxx:role/BedrockInvokeRole"
REGION = "us-east-1"
# Step 1: Entra IDからOIDCトークン取得
print("=== Step 1: Entra IDトークン取得 ===")
app = msal.ConfidentialClientApplication(
CLIENT_ID,
authority=f"https://login.microsoftonline.com/{TENANT_ID}",
client_credential=CLIENT_SECRET
)
# 個人テナントで検証したscope。企業テナントなら "api://sts.amazonaws.com/.default"
token_result = app.acquire_token_for_client(
scopes=[f"api://{CLIENT_ID}/.default"]
)
if "access_token" not in token_result:
raise Exception(f"トークン取得失敗: {token_result.get('error_description')}")
token = token_result["access_token"]
print("✓ トークン取得成功")
# Step 2: STSで一時認証情報を取得
print("\n=== Step 2: STS AssumeRoleWithWebIdentity ===")
sts = boto3.client("sts", region_name=REGION)
assumed = sts.assume_role_with_web_identity(
RoleArn=ROLE_ARN,
RoleSessionName="verification-session",
WebIdentityToken=token
)
creds = assumed["Credentials"]
print("✓ 一時認証情報取得成功")
print(f" 有効期限: {creds['Expiration']}")
# Step 3: Bedrockを呼び出し
print("\n=== Step 3: Bedrock呼び出し ===")
bedrock = boto3.client(
"bedrock-runtime",
region_name=REGION,
aws_access_key_id=creds["AccessKeyId"],
aws_secret_access_key=creds["SecretAccessKey"],
aws_session_token=creds["SessionToken"]
)
response = bedrock.invoke_model(
modelId="us.anthropic.claude-haiku-4-5-20251001-v1:0",
body=json.dumps({
"anthropic_version": "bedrock-2023-05-31",
"max_tokens": 50,
"messages": [{"role": "user", "content": "Hello"}]
})
)
response_body = json.loads(response["body"].read())
print("✓ Bedrock呼び出し成功")
print(f" レスポンス: {response_body['content'][0]['text']}")
ハマったエラーと対処
① InvalidIdentityToken: Incorrect token audience
An error occurred (InvalidIdentityToken) when calling the
AssumeRoleWithWebIdentity operation: Incorrect token audience
原因: スクリプトのscopeと、AWS OIDCプロバイダのAudienceが一致していない。
トークンには aud クレームが含まれており、これがAWS側のAudienceと完全一致しないと弾かれる。jwt.io でトークンをデコードして aud の値を確認し、AWS側と合わせる。
② AccessDenied: Not authorized to perform sts:AssumeRoleWithWebIdentity
An error occurred (AccessDenied) when calling the AssumeRoleWithWebIdentity
operation: Not authorized to perform sts:AssumeRoleWithWebIdentity
原因: IAMロールの信頼ポリシーの aud 条件が、トークンの aud と一致していない。
OIDCプロバイダのAudienceを後から変更しても、IAMロールの信頼ポリシーは自動更新されない。ロールの「信頼関係」タブを開いて aud 条件を手動で修正する必要がある。
"Condition": {
"StringEquals": {
"sts.windows.net/<テナントID>/:aud": "api://sts.amazonaws.com"
}
}
③ ValidationException: model identifier is invalid
ValidationException: 1 validation error detected:
Value 'anthropic.claude-haiku-4-5-20251001' at 'modelId' failed to satisfy
constraint: Member must satisfy regular expression pattern
原因: モデルIDに -v1:0 のバージョンサフィックスが不足している。
anthropic.claude-haiku-4-5-20251001 → anthropic.claude-haiku-4-5-20251001-v1:0 に修正する。
補足: このエラーを解消しても、Claude 4.x系ではこの後に次のエラー④が発生する。on-demandスループット非対応のため、最終的には
us.プレフィックス付きのクロスリージョン推論プロファイルIDを使う必要がある。
④ ValidationException: on-demand throughput isn't supported
ValidationException: Invocation of model ID anthropic.claude-haiku-4-5-20251001-v1:0
with on-demand throughput isn't supported.
原因: Claude 4.x系のモデルはオンデマンドスループットに対応していない。クロスリージョン推論プロファイルのID形式が必要。
anthropic.claude-haiku-4-5-20251001-v1:0 → us.anthropic.claude-haiku-4-5-20251001-v1:0 に修正する(us. プレフィックスを追加)。
Claude 4.x系のモデルIDフォーマット:
| 要素 | 値 | 例 |
|---|---|---|
| リージョンプレフィックス | us. |
クロスリージョン推論プロファイル |
| モデル名 | anthropic.claude-haiku-4-5-20251001 |
モデル名 |
| バージョンサフィックス | -v1:0 |
バージョン指定 |
完成形: us.anthropic.claude-haiku-4-5-20251001-v1:0
個人アカウントで検証する場合の注意
企業テナントでは api://sts.amazonaws.com をApplication ID URIに設定できるが、個人テナントでは以下のエラーになる。
Failed to add identifier URI api://sts.amazonaws.com.
All newly added URIs must contain a tenant verified domain,
tenant ID, or app ID, as per the default tenant policy of your organization.
回避策: Application ID URIを api://<クライアントID> に変更し、AWS側のOIDC Audienceとスクリプトのscopeも合わせる。
| 設定箇所 | 企業テナント | 個人テナント(代替) |
|---|---|---|
| Azure Application ID URI | api://sts.amazonaws.com |
api://<クライアントID> |
| AWS OIDC Audience | api://sts.amazonaws.com |
api://<クライアントID> |
| スクリプトのscope | api://sts.amazonaws.com/.default |
api://<クライアントID>/.default |
両側の値が一致していれば動作する。 値の文字列が異なるだけで、OIDCの仕組み自体は同じ。
まとめ
Azure Entra ID × AWS BedrockのOIDC連携を個人アカウントで検証した。静的なAPIキーを一切使わずに認証できることを確認できた。
ポイントをまとめると:
- IAMユーザーのアクセスキーは不要。一時認証情報が自動失効するのでローテーション運用なし
audクレームの一致はOIDCプロバイダ・IAMロール信頼ポリシー・スクリプトのscopeの3か所で揃える必要がある- OIDCプロバイダのAudienceを変更しても、IAMロールの信頼ポリシーは自動更新されない
- Claude 4.x系のモデルIDは
us.anthropic.〜-v1:0形式(クロスリージョン推論プロファイル)が必要
APIキーの流出・ローテーションから解放されるため、個人検証から企業利用まで選択肢になる構成といえる。