ankuro.dev
← ブログ一覧に戻る
Azure環境からClaudeを呼び出す——Entra IDだけでBedrockを使う(AWSアクセスキー不要)
2026-04-24#AWS#Bedrock#Azure#Entra ID#OIDC#IAM#Python

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. トークンバージョンの確認

「マニフェスト」を開き、accessTokenAcceptedVersionnull または 1 になっていることを確認する(v1.0トークンを受け入れる設定)。2 に設定されていると isslogin.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-20251001anthropic.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:0us.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キーの流出・ローテーションから解放されるため、個人検証から企業利用まで選択肢になる構成といえる。