Claude Media
WIFをMicrosoft Entra ID(Azure)と連携する — Managed IdentityとAKS

WIFをMicrosoft Entra ID(Azure)と連携する — Managed IdentityとAKS

Azure上のワークロードをMicrosoft Entra IDのトークンでClaude APIに認証させる方法を、Managed Identityの構成とAKSのEntra Workload Identityの2経路で解説します。

対象ワークロードと共通の設定フロー

Azure上のワークロードを、Workload Identity Federation(WIF)を使ってMicrosoft Entra IDが発行するJWTでClaude APIに認証させる方法を扱います。VM・VM Scale Set・App Service・Functions・Container Appsで使うManaged Identity方式と、AKSのPodで使うEntra Workload Identity方式の2経路があり、どちらも最終的にはAnthropicのPOST /v1/oauth/tokenでトークンを交換します。

前提条件:

  • WIFの基本概念(サービスアカウント・連合発行者・連合ルール)への理解
  • Managed Identityを割り当てられる権限を持つAzureサブスクリプション(またはAKSでEntra Workload Identityを構成できる権限)
  • Microsoft Entraテナントでアプリ登録とサービスプリンシパルを1つ作成できる権限
  • AzureポータルのMicrosoft Entra ID → Overview → Tenant IDで確認できるテナントID
  • Anthropic組織でサービスアカウント・連合発行者・連合ルールを作成できる権限

両方の経路に共通する骨格は4段階です。①Claude API用のオーディエンスをテナントに登録する ②プラットフォームに応じたアイデンティティを設定する ③Anthropic側で発行者・サービスアカウント・ルールを組む ④実行時にトークンを交換してClaudeを呼ぶ。

トークンのオーディエンスをテナントに登録する

Microsoft Entra IDは、要求されたオーディエンスがテナント内にアプリ登録として存在する場合にしかトークンを発行しません。Claude APIのオーディエンスを表すアプリ登録を1つ作れば、テナント内のすべてのワークロードがそのオーディエンス宛てにトークンを要求できます。

APP_ID=$(az ad app create --display-name claude-api-federation --query appId -o tsv)
 
az ad app update --id "$APP_ID" \
  --identifier-uris "api://$APP_ID" \
  --set api.requestedAccessTokenVersion=2
 
az ad sp create --id "$APP_ID"

この登録を省くと、トークン要求がManaged IdentityエンドポイントからはAADSTS50001、EntraのトークンエンドポイントからはAADSTS500011という「リソースがテナント内に見つからない」エラーで失敗します。

Managed Identityを使う方式

VM・VM Scale Set・App Service・Functions・Container Appsで動くワークロードでは、プラットフォームのローカルなトークンエンドポイントからManaged Identity用のJWTを取得し、それをAnthropicと交換します。

Managed Identityの設定

Azureリソースにシステム割り当てまたはユーザー割り当てのManaged Identityを付与し、Object(principal)IDを控えます。このGUIDはトークンのsubクレームとoidクレームの両方に現れ、連合ルールがこの値をマッチ条件にします。

プラットフォームごとにトークンエンドポイントが異なります。VM・VM Scale SetはMetadata: trueヘッダー付きのIMDS(http://169.254.169.254/metadata/identity/oauth2/token)、App Service・Functions・Container AppsはIDENTITY_ENDPOINT環境変数のURL(IMDSには到達できません)です。ユーザー割り当てのIdentityが複数あるリソースでは、client_idパラメーターで対象を明示しないと、システム割り当てが設定されている場合は黙ってそちらへフォールバックし連合ルールのoidマッチが失敗します。設定されていない場合はリクエスト自体が失敗します。

取得したトークンをデコードすると、次のようなクレームが確認できます。

{
  "iss": "https://login.microsoftonline.com/<TENANT_ID>/v2.0",
  "sub": "9f8e7d6c-1a2b-3c4d-5e6f-...",
  "aud": "<APP_ID>",
  "oid": "9f8e7d6c-1a2b-3c4d-5e6f-...",
  "tid": "<TENANT_ID>",
  "azp": "<IDENTITY_CLIENT_ID>",
  "ver": "2.0"
}

Anthropic側の設定

Claude ConsoleのSettings → Workload identityConnect workloadを選び、Microsoft Entraタイルから進めます。Token issuerセレクターでv2.0(login.microsoftonline.com)を選びます(既定はv1になっているため注意が必要です)。

{
  "name": "azure-prod-tenant",
  "issuer_url": "https://login.microsoftonline.com/<TENANT_ID>/v2.0",
  "jwks": { "type": "discovery" },
  "max_jwt_lifetime_seconds": 86400
}

連合ルールはManaged IdentityのoidとテナントIDをマッチさせます。

{
  "name": "azure-inference-worker",
  "issuer_id": "fdis_...",
  "match": {
    "audience": "<APP_ID>",
    "claims": {
      "oid": "9f8e7d6c-1a2b-3c4d-5e6f-...",
      "tid": "<TENANT_ID>"
    }
  },
  "target": { "type": "service_account", "service_account_id": "svac_..." },
  "workspace_id": "wrkspc_...",
  "oauth_scope": "workspace:developer",
  "token_lifetime_seconds": 600
}

トークンを取得して使う

ENTRA_TOKEN=$(curl -sS -H "Metadata: true" \
  "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=api://<APP_ID>" \
  | jq -r .access_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": "$ENTRA_TOKEN",
  "federation_rule_id": "$ANTHROPIC_FEDERATION_RULE_ID",
  "organization_id": "$ANTHROPIC_ORGANIZATION_ID",
  "service_account_id": "$ANTHROPIC_SERVICE_ACCOUNT_ID",
  "workspace_id": "$ANTHROPIC_WORKSPACE_ID"
}
JSON
)
 
ACCESS_TOKEN=$(echo "$RESPONSE" | jq -r .access_token)

AKSでEntra Workload Identityを使う方式

AKSのPodでは、Entra Workload IdentityがKubernetesのサービスアカウントとユーザー割り当てManaged Identityを連合させます。KubernetesがAKSクラスターのOIDC発行者で署名したサービスアカウントトークンをAZURE_FEDERATED_TOKEN_FILEのパスにPodへ投影しますが、このトークン自体はEntra発行のトークンではありません。そのためワークロードは2段階の交換を行います。まずこのトークンをhttps://login.microsoftonline.com/<TENANT_ID>/oauth2/v2.0/token(client_credentialsグラント)でEntra発行のアクセストークンに交換し、そのEntraトークンをAnthropicのSDKへ渡します。

Entra Workload Identityの設定

クラスターでOIDC発行者とWorkload Identityを有効化し、発行者URLを控えます。

az aks update \
  --resource-group <RESOURCE_GROUP> \
  --name <CLUSTER_NAME> \
  --enable-oidc-issuer \
  --enable-workload-identity
 
AKS_OIDC_ISSUER=$(az aks show \
  --resource-group <RESOURCE_GROUP> \
  --name <CLUSTER_NAME> \
  --query oidcIssuerProfile.issuerUrl -o tsv)

続けてユーザー割り当てManaged Identityを作成し、Kubernetesのサービスアカウントにクライアントの識別子をアノテーションで紐づけ、Managed Identity側にはクラスターのOIDC発行者を信頼する連合クレデンシャルを作成します。--audience api://AzureADTokenExchangeはKubernetesサービスアカウントトークンを受け取るためのEntra固有のオーディエンスで、先に登録したClaude API用のオーディエンスとは別物です。

az identity federated-credential create \
  --resource-group <RESOURCE_GROUP> \
  --identity-name claude-inference-identity \
  --name claude-inference-aks \
  --issuer "$AKS_OIDC_ISSUER" \
  --subject system:serviceaccount:inference:claude-inference \
  --audience api://AzureADTokenExchange

Podにはazure.workload.identity/use: "true"ラベルを付け、アノテーション済みのサービスアカウントで実行します。WebhookがAZURE_FEDERATED_TOKEN_FILEAZURE_CLIENT_IDAZURE_TENANT_IDをPodへ注入します。

apiVersion: v1
kind: Pod
metadata:
  name: inference-worker
  namespace: inference
  labels:
    azure.workload.identity/use: "true"
spec:
  serviceAccountName: claude-inference
  containers:
    - name: app
      image: your-registry/inference-worker:latest

Anthropicの連合ルールが実際に見るのは、投影されたファイルではなくclient_credentials交換で得たEntra発行トークンです。クレームの形はManaged Identity方式と同じですが、有効期間は24時間ではなくclient_credentialsトークンの既定である60〜90分のランダムな幅になります。

Anthropic側の設定

発行者のmax_jwt_lifetime_secondsは、client_credentialsトークンの既定寿命をカバーする7500秒(2時間強)で足ります。テナントのトークン有効期間ポリシーやCAE(継続的アクセス評価)がこれを超えて延長する場合は値を引き上げます。同じテナントでManaged Identity方式のワークロードも動かすなら、86400秒に統一しても両方をカバーできます。

{
  "name": "azure-prod-tenant",
  "issuer_url": "https://login.microsoftonline.com/<TENANT_ID>/v2.0",
  "jwks": { "type": "discovery" },
  "max_jwt_lifetime_seconds": 7500
}

連合ルールの形はManaged Identity方式と同じで、oidとテナントIDをマッチさせます。

トークンがv1.0のとき

既存のアプリ登録を流用しrequestedAccessTokenVersionを未設定のままにすると、Entraはv1.0トークンを発行します。デコードしたverクレームが1.0なら、4点が変わります。発行者のisshttps://sts.windows.net/<TENANT_ID>/になり、Consoleウィザードではv1(sts.windows.net)を選びます。audクレームはアプリ登録のクライアントIDではなく、resourceとして渡した識別子URI(api://<APP_ID>)になります。呼び出し元のクライアントIDはazpではなくappidクレームに入るため、azpにマッチするルールはv1.0トークンには通りません。oidsubtidは両バージョンで共通です。

ルールのスコープを絞る

EntraのGUIDは固定長の正規形式のため、subject_prefixに完全なオブジェクトIDを設定すればその主体だけにマッチします。ワークロードごとにルールを分けておけば、1つのワークロードのアクセスだけを個別に無効化できます。

まとめ

Azure上のワークロードをWIFでClaude APIに繋ぐには、まずテナントにClaude API用のオーディエンスを1つ登録します。そのうえで、VM・App Service系ならManaged Identity方式、AKSのPodならEntra Workload Identity方式のどちらかを選びます。両方式ともクレームの形はほぼ同じですが、Managed Identityはトークン寿命が最大24時間に達するため発行者側のmax_jwt_lifetime_secondsを86400秒へ引き上げる必要がある点が最大の落とし穴です。WIF自体の仕組みはWIFとは何か、環境変数やプロファイルの完全なリファレンスはWIFリファレンス、AWS環境での同様の手順はWIFをAWSと連携するにまとめています。

この記事を共有:XはてブLinkedIn