Entra ID で AI エージェントに ID を持たせよう! ~ Foundry × Claude で検証(その1)、(その2) で Entra ID で AI エージェントに ID を付与し、ロールを付与しました。いわゆる RBAC (ロールベースのアクセス制御) です。

1. AI エージェントのセキュリティを考える
AI エージェントは業務効率を大きく向上させる一方で、エージェント自体が意図しない操作をしたり、攻撃者に悪用されるリスクが指摘されています。
AI エージェントはあなたに寄り添った口調で回答をくれるけれど、残念ながら人ではありません。
- 動作が非決定的: 同じ指示でも毎回同じ行動をとらないことがある
- 他人の意図で動くことがある: 読み込んだデータに指示が埋め込まれている場合、その指示に従ってしまう (プロンプトインジェクション、Confused deputy problem)
- 高速、そして大量: 処理が速いため、被害が高速に拡大する
AI エージェントに与える権限は、「モデルが正しく振る舞うこと」を前提とせず、誤動作しても被害が限定される範囲で考える必要があります。
RBAC が決めるのは、「何ができるか」のみです。エージェントに権限を設計するには、さらに「誰の代わりに動くのか」と「人の承認なしにどこまで動くのか」という 2 つの問いが残ります。本記事では、これを「委任」と「自律」の 2 軸として整理していきます。
2. 権限モデルの 2 つの軸: 委任と自律
「誰の代わりに動くのか」が委任、「人の承認なしにどこまで動くのか」が自律となります。
例えば、Mail.Read という権限で、「委任されたアクセス許可」ならサインインしたユーザーの代わりに動き、そのユーザー自身のメールだけを読めます。
「アプリケーションの許可」として付けるとエージェントは自分の権限として動き、テナント全員のメールが読めるようになります。

自律の軸は、また別の話になります。例えば、読んだメールをもとに返信するとき、送信前に確認を挟むのか、エージェントが自分の判断で送ってしまうのか -- 同じ権限であっても、この設計によって誤動作したときの被害は大きく変わります。
ではこの 2 つの軸が実際にどのようなものか、具体的に紹介していきたいと思います。
まずは、「委任」です。アプリケーションを登録して、委任されたアクセス許可でどのような動きになるかを確認します。
「自律」については、次回の公開で書きたいと思います。

3. 検証: 委任 (On-Behalf-Of)
3-1: アプリ登録と設定
同意設定
テナント全体の同意設定を行います。ユーザーの同意設定は、ユーザーが自分の判断でアプリに委任アクセス許可 (delegated permission) を与えられる範囲を決める設定です。
同意を制御する設定は複数あり、組み合わせで挙動が変わります。今回は「ユーザーの同意を許可しない」 + スコープを「管理者のみ」 + Azure CLI を承認済みクライアントに登録という構成とします。
(スコープと承認済みのクライアントは、後のアプリ登録の手順で設定します)
この設定は、テナント内のすべてのユーザーとアプリに影響します。また、変更には特権ロール管理者などの権限が必要です。
設定の詳細については、Microsoft が公開するドキュメントを参照してください。
- Azure portal にサインインし、[Microsoft Entra ID] を選択します
- 左ペインにて [エンタープライズアプリケーション] を選択します
- 左ペインにて [セキュリティ] - [同意とアクセス許可] を選択し、左ペインで [ユーザーの同意設定] を選択します
- 「ユーザーの同意を許可しない」を選択し、[保存] をクリックします
ユーザーの同意設定の選択肢について
ユーザーの同意を許可しない
アプリに同意を付与する権限を含むディレクトリロールを持つユーザーだけが新しいアプリに同意できます。一般ユーザーは同意画面で先に進めず、管理者の承認が必要となります。
こちらを選択すると、新しい SaaS や Graph 連携ツールを使うたびに管理者対応が必要になりますが、同意フィッシング (illicit consent grant) のリスクを大きく下げられます。
検証済みの発行元からのアプリに対して、選択したアクセス許可についてユーザーの同意を許可する
確認済みの発行元のアプリ、またはこの組織に登録されているアプリに限り、「低影響」と分類されたアクセス許可について、すべてのユーザーが同意できます。
「低影響」と分類するアクセス許可は [アクセス許可の分類] で設定します。
Microsoft による同意設定の管理を許可する (推奨)
Microsoft が管理する同意ポリシーを適用する方式で、どのアクセス許可を危険とみなしてブロックするかを Microsoft が脅威動向に応じて随時更新します。
※ ある程度危険なアクセスはブロックできると想定できますが、ユーザーの組織の基準と一致するとは限らないため、準拠要件がある場合は他の選択肢を検討してください。
- 左ペインにて [管理者の同意設定] を選択します
- [管理者の同意要求] で「いいえ」を選択し、[保存] をクリックします
- はい: ユーザーは同意画面から承認を要求でき、管理者がレビューします ※ レビュー担当者 (ユーザー・グループ・ロール) の指定も必要になります
- いいえ: ユーザーは「管理者の承認が必要です」と表示されて止まります
今回は検証のため、管理者の同意要求は「いいえ」とします。本番環境などでユーザーの同意を止める場合は、ユーザーが管理者に承認を要求できるよう「はい」にしておくなどもご検討ください (止めるだけでは、業務が止まる、シャドー IT に流れるなどの原因になります)
アプリケーションの登録
次に検証に使うアプリケーションを登録します。
-
Azure portal にサインインし、[Microsoft Entra ID] を選択します
-
左ペインにて [管理] - [アプリの登録] を選択します
-
[名前] に任意の名前を入力します ※ ここでは agent-api
-
[サポートされているアカウントの種類] では今回は「シングルテナントのみ - 既定のディレクトリ」を選択しました
API の公開
アプリケーションを登録したら、このアプリケーションを API (リソース) として公開するための設定を行います。具体的には、アプリケーション ID URI と、クライアントが要求するスコープ (委任されたアクセス許可) を定義します。
- [Microsoft Entra ID] - [管理] - [アプリの登録] - [すべてのアプリケーション] タブから、作成した「agent-api」を選択します
- 左ペインにて [概要] を選択し、[アプリケーション (クライアント) ID] を控えておきます
- 左ペインにて [管理] - [API の公開] を選択します
- [アプリケーション ID の URI] には
api://<手順 2 で控えた ID>がデフォルトで入力されています。[保存してから続ける] をクリックします
※ この手順は初回のみです - [Scope の追加] をクリックします
- [スコープ名] に任意の名称を入力します ※ ここでは access_as_user
- [同意できるのは誰ですか] では以下のうちいずれかを選択します ※ ここでは「管理者のみ」
- 管理者とユーザー: ユーザーが同意できるかどうかをテナントの同意設定に従います
- 管理者のみ: テナントの設定に関係なく、このスコープは常に管理者の同意が必要です
- [管理者の同意の表示名]、および [管理者の同意の説明] に任意の表示名、説明を入力し、[状態] で「有効」を選びます
- [スコープの追加] をクリックします
管理者の同意の表示名・説明について
- 管理者の同意の表示名: 管理者がこのスコープに同意すると、スコープは同意画面でこのように呼ばれます
- 管理者の同意の説明: テナント管理者が同意画面でスコープを展開するときに表示される、スコープに関する詳細な説明です
承認済みクライアントアプリケーションの追加
今回の検証では Microsoft Azure CLI をクライアントとして使用してアクセストークンを取得します。そのため、作成した agent-api に Azure CLI を承認済みクライアントアプリケーションとして追加します。承認済みクライアントとして登録すると、Azure CLI がこのスコープのトークンを要求したときにユーザーへの同意画面が表示されなくなります。
Microsoft Azure CLI のクライアント ID は「04b07795-8ddb-461a-bbee-02f9e1bf7b46」です。
- agent-api の [管理] - [API の公開] を開きます
- [承認済みクライアントアプリケーション] セクションで [クライアントアプリケーションの追加] をクリックします
- [クライアント ID] に「04b07795-8ddb-461a-bbee-02f9e1bf7b46」を入力し、[承認済みのスコープ] で作成したスコープを選択します
- [アプリケーションの追加] をクリックします
Microsoft Graph の委任されたアクセス許可
次に、agent-api がユーザーの代理で Microsoft Graph を呼び出せるよう、委任されたアクセス許可を追加します。OBO ではトークン交換の途中で同意画面を表示できないため、事前に管理者の同意を与えておく必要があります。
- agent-api の [管理] - [API のアクセス許可] を開きます
- デフォルトで Microsoft Graph の「User.Read」が追加されています。ない場合は [アクセス許可の追加] をクリックし、[Microsoft Graph] - [委任されたアクセス許可] で「User.Read」にチェックを入れ、[アクセス許可の追加] をクリックします
- [
<テナント名>に管理者の同意を与えます] をクリックし、[はい] をクリックします
クライアントシークレットの作成
最後に、agent-api が自分自身を証明するための資格情報を作成します。(その2)ではフェデレーション資格情報(FIC)を設定しましたが、FIC は Azure のマネージド ID など、信頼した発行元のトークンが必要です。ローカル PC からはこのトークンを取得できないため、今回の検証ではクライアントシークレットを使用します。
- agent-api の [管理] - [証明書とシークレット] を開きます
- [クライアント シークレット] タブで [新しいクライアント シークレット] をクリックします
- [説明] に用途が分かる名前を入力します ※ ここでは obo-test
※ 空欄のままにすると「Password uploaded on <日付>」という名前になり、後から何のためのシークレットか分からなくなります - [有効期限] で「カスタム」を選択し、検証期間に合わせて短い期間を設定します
- [追加] をクリックします
- 一覧の「値」列に表示された文字列をコピーします
※ 値は作成直後にしか表示されません。隣の「シークレット ID」ではなく「値」をコピーしてください
本番環境ではシークレットを使わず、FIC や証明書を使用してください。検証が終わったら、作成したシークレットは必ず削除してください。
3-2: 検証
では、どのようにユーザーが取得したトークンを AI エージェントが使用するのか検証していきます。

-
PowerShell を起動します
-
変数をセットします
$CLIENT_ID = "xxx" $TENANT_ID = "xxx"※ [Microsoft Entra ID] - [管理] - [アプリの登録] - [agent-api] - [概要] で確認します
-
ログインします
az login --tenant $TENANT_ID --allow-no-subscriptions -
ログインしたユーザーを確認するには以下を実行します
az ad signed-in-user show --query "{upn:userPrincipalName, id:id, name:displayName, type:userType}" -
ログインしたユーザーとして、agent-api 宛てのトークン(トークン A)を取得します
$TOKEN_A = az account get-access-token --scope "api://$CLIENT_ID/access_as_user" --query accessToken -o tsv -
agent-api のシークレットを入力します。シークレットはコマンドに直接書かず、Read-Host で入力します(直書きすると、コマンド履歴やスクリーンショットに残るため)
$SECRET = Read-Host "シークレットの値" -AsSecureString | ForEach-Object { [System.Net.NetworkCredential]::new("", $_).Password }「シークレットの値:」と表示されたら、3-1 の最後の手順でコピーした値を貼り付けます
-
OBO のトークン交換リクエストを作成します
$body = @{ grant_type = "urn:ietf:params:oauth:grant-type:jwt-bearer" client_id = $CLIENT_ID client_secret = $SECRET assertion = $TOKEN_A scope = "https://graph.microsoft.com/User.Read" requested_token_use = "on_behalf_of" }パラメーター 意味 grant_type 手元の JWT を別のトークンに交換する申請であること requested_token_use 交換の目的が「ユーザーの代理」であること。これで OBO になります assertion 交換の元になるユーザーのトークン(手順 5 のトークン A) client_id / client_secret 申請者が agent-api 本人であることの証明 scope 交換後に欲しい権限(Graph の User.Read) -
Entra ID のトークンエンドポイントにリクエストを送り、Graph 用のトークン(トークン B)を受け取ります
$res = Invoke-RestMethod -Method Post -Uri "https://login.microsoftonline.com/$TENANT_ID/oauth2/v2.0/token" -Body $body $TOKEN_B = $res.access_token※ 結果は $res に入るため、2 行目でトークン部分を $TOKEN_B に取り出します。この行を忘れると、次の手順で 401 エラーになります
-
トークン B を使って Graph を呼び出します
Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/me" -Headers @{ Authorization = "Bearer $TOKEN_B" }手順 3 でログインしたユーザーの情報が返れば成功です。agent-api が、ユーザー本人として Graph にアクセスできたことになります。
4. OBO 交換の記録
Entra 管理センターのサインインログ([ユーザーのサインイン (非対話型)] タブ)には OBO 交換の記録が残ります。ユーザーは自分、アプリケーションが登録アプリケーション (ここでは agent-api)、そして使用したリソース (ここでは Microsoft Graph) が記録されます。
アクティビティがユーザー本人によるものか、エージェント経由かを判断するには、このログのアプリケーションを確認します。
5. OBO の落とし穴と対策
今回の検証で、OBO の動作を確認しました。
OBO は「誰の権限で動くか」を保ちますが、それだけでは守れない穴があります。OBO の落とし穴と対策を以下にまとめます。
| # | 落とし穴 | 発生し得るリスク | 主な対策 |
|---|---|---|---|
| 1 | ユーザーの権限を背負う | たとえば User.ReadWrite.All を持つエージェントは、一般ユーザーなら自分のプロフィール、管理者なら全ユーザーを変更できる | スコープを最小限にする / 特権アカウントではエージェントを使わない |
| 2 | ユーザーが自分で同意できてしまう | 設定次第で一般ユーザーが委任スコープに同意できる (同意フィッシングの温床となる) | [エンタープライズアプリケーション] - [同意とアクセス許可] でユーザー同意を制限し、管理者同意のワークフローを使う |
| 3 | 範囲は守れても、意図は守れない | 正当な権限の範囲内で、本人が望まない操作が実行される (プロンプトインジェクション) | 送信系スコープ (Mail.Send など) は必要なときだけに制限。送信・削除の前に人間の承認。Prompt Shields で検出 |
| 4 | 監査ログで「本人がやった」ように見える | oid は本人なので操作もユーザー名義で残り、本人かエージェントかの切り分けが難しい | サインインログやリソースのアクティビティログ (この検証では Microsoft Graph) などでユーザーだけでなく呼び出し元のアプリ ID まで確認する |


