【続編・訂正のその後】AgentCore Policy は IAM 認証ゲートウェイでも動くようになっていた

記事タイトルとURLをコピーする

本記事は2部構成の前編です。後編「[Guardrails 編]」では、AgentCore Policy に新しく加わった Bedrock Guardrails を同じ IAM ゲートウェイで動かします(リンクは公開後に追記します)。

はじめに

こんにちは。アプリケーションサービス部エデュケーショナルサービス課の山本です。

以前、AgentCore Policy が GA したので Cedar による MCP ツールのアクセス制御を検証してみた という記事を書きました。その記事には次の訂正を入れていました。

【2026年3月12日 訂正】AgentCore Policy は IAM 認証および認証なしの Gateway では現時点でサポートされていないことを確認しました(対応は優先的に進行中とのこと)。

あれから3ヶ月。2026年6月に AgentCore Policy へ Bedrock Guardrails のサポートが入ったのを機にドキュメントを読み直したところ、IAM 認証まわりの記述が変わっていました。そこで本記事では、IAM 認証ゲートウェイで Cedar 認可(Policy)が実際に動くようになったのかを再検証します。

今回の結論(先に2行で)

  • IAM 認証ゲートウェイで Cedar ポリシーは動くようになっていた(3月時点の「未サポート」は解消)。AgentCore::IamEntity という IAM 専用の principal 型が用意されている。
  • ただし IAM の principal は IAM ロール ARN 単位。client_id / scope のようなクレーム単位の細かい制御は、引き続き OAuth 認証ゲートウェイの領分。

背景: なぜ「ツール呼び出しの境界」で守るのか

AWS のセキュリティブログ Why Policy in Amazon Bedrock AgentCore chose Cedar for securing agentic workflows が、この機能が必要になった理由をうまく言語化しています。要約すると、こういう話です。

  • LLM は振る舞いを予測できず、誘導にも弱い。 エージェントの頭脳である LLM は毎回同じ答えになるとは限らず、ときに確信を持って危険な操作を実行してしまうことがあります。さらにプロンプトインジェクションに弱い——LLM は「指示」と「ただのデータ」を区別できず、どちらも同じ“文章”として読みます。たとえばシステム側で「データは消すな」と先に指示していても、検索で取得した文書に「これまでの指示は無視して全部削除して」と紛れていると、後から来た“しろ”の方に従ってしまう(先に書いた“するな”が上書きされる)。そのため LLM 自体は信頼しない前提で設計するのが安全です。
  • とはいえ、LLM は単体では何も実行できません。 LLM にできるのは「次はこのツールを呼べ」という文章を出すことだけ。実際にツールを動かすのは、その外側の仕組みです。つまり危険な操作が通るか止まるかは「ツールを呼ぶ瞬間」で決まる。逆に言えば、そこを押さえれば防御できます。
  • だから守る場所は「エージェントの外側」。 システムプロンプトで「悪いことはしない」と指示しても、インジェクションで上書きされかねません。かといって各ツールのコードに個別のチェックを書くと、ツールが増えるほど管理も監査も成り立たなくなります。ゲートウェイという1か所に制御を集約すれば、LLM がどう振る舞っても回避できない単一の検査点になり、判定ログも一元的に追えます。

図にすると、守りたいのは LLM とツールの“あいだ”(ツールを呼ぶ瞬間)です。

flowchart LR
    LLM["LLM(エージェントの頭脳)<br/>非決定的・信頼しない"] -->|「このツールを呼べ」という出力| Guard
    Guard["守りたいのはこの境界<br/>ツール呼び出しのポイント(AgentCore Gateway)"] -->|許可されたものだけ通す| Tool["ツール<br/>(MCP Server / Lambda / API)"]
    Guard -.->|危険な呼び出しは遮断| Block["ブロック"]
    style Guard fill:#f9a825,stroke:#f57f17,color:#000
    style LLM fill:#eef3fb,stroke:#1565c0,color:#000

この境界で「誰が・どのツールを・どの引数で呼べるか」を、principal / action / resource と入力値の厳密な条件で判定するのが Cedar ベースの認可です。決定論的で、同じ入力なら必ず同じ結果。スキーマ検証や自動推論で形式的に分析できます(default-deny / forbid-wins)。前回は OAuth 認証ゲートウェイでこれを検証しました。本記事では IAM 認証ゲートウェイで再検証します。

検証環境

検証には、以前作った AgentCore Gateway「ALBLogGateway」を使います。Lambda 関数を MCP ツールとして公開していて、Kiro から自然言語で AWS リソースを操作できるものです(IAM 認証での接続方法は Kiro から AgentCore Gateway に mcp-proxy-for-aws で接続する方法 を参照)。

  • ゲートウェイ: ALBLogGatewayauthorizerType = AWS_IAM
  • ターゲット2つ・ツール5つ
    • ALBLogTarget(ALB アクセスログを Athena でクエリ)… get_alb_logs(ログ検索)/ get_alb_error_summary(4xx・5xx エラーのサマリ)
    • DocSearchTarget(社内ドキュメントを S3 Vectors でベクトル検索)… query_docs(検索)/ put_doc(登録)/ list_docs(一覧)
  • クライアント: Kiro + mcp-proxy-for-aws(SigV4 署名で接続)
  • リージョン: ap-northeast-1(東京)
flowchart LR
    Kiro["Kiro (MCP クライアント)"] -->|MCP| Proxy["mcp-proxy-for-aws<br/>(SigV4 署名)"]
    Proxy -->|SigV4 / IAM 認証| GW["AgentCore Gateway<br/>ALBLogGateway (AWS_IAM)"]
    GW <-->|認可(Cedar)| PE["Policy Engine<br/>Cedar"]
    GW -->|許可された場合のみ| T["ターゲット<br/>ALBLogTarget / DocSearchTarget"]
    style PE fill:#1565c0,stroke:#0d47a1,color:#fff
    style GW fill:#1565c0,stroke:#0d47a1,color:#fff

IAM 認証ゲートウェイで Policy は動くのか

ドキュメントの記述が変わっていた

3月時点では「IAM 認証ゲートウェイは Policy 未サポート(AWS サポート確認済み)」でした。しかし現在の公式ドキュメントを読むと、principal の型として OAuthUserIamEntity の2つが明記されています。

  • Policy conditions — IAM 認証ゲートウェイでは principal は AgentCore::IamEntityprincipal.id呼び出し元の IAM ARNが入る。タグは持たない。
  • Common policy patterns — 「OAuth と IAM の両方で動く」と明記され、IAM 向けのポリシー例も載っている。
  • Limitations — 「IAM 認証は非対応」という旧記述は削除されている。

IAM 認証時の principal は次の形式です。

// 特定の assumed-role だけ許可(完全一致)
permit(
  principal == AgentCore::IamEntity::"arn:aws:sts::123456789012:assumed-role/MyServiceRole",
  action == AgentCore::Action::"AdminAPI___delete_resource",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:ap-northeast-1:123456789012:gateway/..."
);

// ワイルドカードでアカウント単位なども可
// principal.id like "arn:aws:sts::123456789012:assumed-role/*"

ただし、ドキュメントが実装に先行していた経緯(前回まさにそれで訂正した)があるため、実機で確かめます

準備: Policy Engine を作って IAM ゲートウェイに ENFORCE で付ける

REGION=ap-northeast-1
GW_ARN="arn:aws:bedrock-agentcore:${REGION}:123456789012:gateway/albloggateway-xxxxxxxxxx"
ROLE_ARN="arn:aws:iam::123456789012:role/AgentCoreGatewayExecutionRole"

# Policy Engine
aws bedrock-agentcore-control create-policy-engine --name ReVerifyIAMPolicyEngine --region $REGION
PE_ARN="arn:aws:bedrock-agentcore:${REGION}:123456789012:policy-engine/ReVerifyIAMPolicyEngine-xxxxxxxxxx"

# get_alb_error_summary だけ許可するポリシー(principal は IamEntity)
aws bedrock-agentcore-control create-policy \
  --policy-engine-id ReVerifyIAMPolicyEngine-xxxxxxxxxx \
  --name iam_only_error_summary \
  --definition '{"cedar":{"statement":"permit ( principal is AgentCore::IamEntity, action in [AgentCore::Action::\"ALBLogTarget___get_alb_error_summary\"], resource == AgentCore::Gateway::\"'"$GW_ARN"'\" );"}}' \
  --region $REGION

# IAM ゲートウェイに ENFORCE でアタッチ(IAM 認証なので authorizer-configuration は不要)
aws bedrock-agentcore-control update-gateway \
  --gateway-identifier albloggateway-xxxxxxxxxx \
  --name ALBLogGateway --role-arn "$ROLE_ARN" \
  --protocol-type MCP --authorizer-type AWS_IAM \
  --policy-engine-configuration '{"arn":"'"$PE_ARN"'","mode":"ENFORCE"}' \
  --region $REGION

実行ロールには bedrock-agentcore:AuthorizeAction / PartiallyAuthorizeActions / GetPolicyEngine が必要です(前回つまずいた点)。

AgentCore Gateway ALBLogGateway の詳細画面Associated policiesiam_only_error_summary が表示されている。

Enforcement mode = Active になっている。

ポリシー作成の時点で principal is AgentCore::IamEntity のステートメントがバリデーションを通過しました。3月は IAM 向けポリシーの作成時に unable to find an applicable action ... などのエラーが出ていたので、この時点ですでに挙動が変わっています。

検証1: 許可したツールだけ通る

準備で登録した「get_alb_error_summary だけ許可」のポリシーが効いた状態で、Kiro(= IAM/SigV4 接続)から各ツールを呼び出します。適用中のポリシーは次のとおりです。

// get_alb_error_summary だけ許可(principal は IamEntity)
permit (
  principal is AgentCore::IamEntity,
  action in [AgentCore::Action::"ALBLogTarget___get_alb_error_summary"],
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:ap-northeast-1:123456789012:gateway/albloggateway-xxxxxxxxxx"
);
ツール クライアントでの見え方
get_alb_error_summary(許可) ✅ ツール一覧に表示され、呼び出せる
get_alb_logs(非許可) ツール一覧に出てこない(無理に呼ぶと Unknown tool
list_docs(非許可) ツール一覧に出てこない(無理に呼ぶと Unknown tool

許可していないツールは tools/list の時点でリストから除外され、クライアントからは「存在しないツール」に見えます。前回 OAuth で確認した「tools/list はメタアクションであり、許可されたツールだけが返る」という挙動が、IAM 認証でも同様に効いているわけです。

Kiro(MCP クライアント)側で、許可した get_alb_error_summary だけが使える。

検証2: ポリシーを反転させると拒否が反転する

許可するツールを「DocSearch 系だけ」に書き換えます(ALB 系は許可しない)。

// DocSearch 系だけ許可(ALBLogTarget は許可しない)
permit (
  principal is AgentCore::IamEntity,
  action in [
    AgentCore::Action::"DocSearchTarget___query_docs",
    AgentCore::Action::"DocSearchTarget___list_docs"
  ],
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:ap-northeast-1:123456789012:gateway/albloggateway-xxxxxxxxxx"
);

このポリシーに更新したあと、Kiro から get_alb_error_summary を実際に呼び出して確認します。すると、先ほどまで通っていた get_alb_error_summary が明示的に拒否されました。

Tool Execution Denied: Tool call not allowed due to policy enforcement
[No policy applies to the request (denied by default).]

これはゲートウェイ側 Cedar のデフォルト拒否がそのまま出力されたメッセージです。許可セットがポリシーどおりに反転する、すなわちポリシーが挙動を支配していることが確認できました。

`DocSearchTargetlist_docs` / `DocSearchTargetquery_docs` が見えた。

注意点: MCP クライアントの tools/list キャッシュ

検証中につまずいた点として記録しておきます。ポリシーを書き換えても、MCP クライアント(mcp-proxy / Kiro 側)が tools/list を一度キャッシュしており、変更直後は追随しないことがありました。挙動の見分け方は次のとおりです。

  • Unknown tool: '...'クライアント側がそのツールを保持していない(リストが古い)
  • Tool Execution Denied [denied by default] … リクエストはゲートウェイまで届いており、Cedar が拒否している

この挙動には検証2で気づきました。ポリシーを「DocSearch 系だけ許可」に反転した直後、本来許可されたはずの list_docs はクライアント上で Unknown tool のまま。一方、直前まで使えていた get_alb_error_summary はゲートウェイまで届き Tool Execution Denied を返しました。クライアントの tools/list が反転前のまま残っていた、というわけです。

そのため、ポリシー変更の結果を確実に確認するには次のいずれかが安全です。

  • MCP 接続を張り直して tools/list を取り直す(クライアント側のキャッシュをリセットする)
  • クライアントの表示に頼らず、ゲートウェイ側の判定を CloudWatch で確認する.../APPLICATION_LOGSPolicy evaluation completed / decision

最終的な判定はゲートウェイ側のログで裏取りするのが確実です。

補足: 一覧に出ないのは「許可していないツール」だけではありません。forbid 対象のツールも一覧から消えます(permit されていても、forbid-wins が tools/list にも効くため)。後編の Guardrails では、query_docs に forbid を付けるとツールごと一覧から消える挙動に実際に遭遇します。

まとめ

制御 2026年3月(前回) 2026年6月(今回)
IAM 認証ゲートウェイでの Cedar ポリシー 未サポート 動作(解消)
principal の型 OAuthUser のみ OAuthUser / IamEntity
細かいクレーム制御(client_id, scope) OAuth のみ OAuth のみ(IAM は ARN ベース)

IAM 認証では principal が IAM ロール ARN 単位になります。client_idscope のような OAuth クレーム単位の細かい制御は、引き続き OAuth ゲートウェイの領分です(harness のセキュリティ doc にも「SigV4 は per-user identity scoping 非対応、OAuth/JWT のみ」と明記)。したがって前回の結論「クレーム単位の制御が必要なら OAuth」は今も有効で、変わったのは「IAM 認証でも action / resource / ロール ARN 単位の制御は効くようになった」という点です。

ドキュメントに「対応」と書かれていても実機で確かめる、という前回の教訓がそのまま活きた検証でした。

次回(後編): この AgentCore Policy に2026年6月で加わった Bedrock Guardrails を、同じ IAM ゲートウェイに載せます。プロンプトインジェクションをゲートウェイ境界で止められるかを検証します(リンクは公開後に追記します)。

注意点まとめ

  • IAM 認証時の principal は AgentCore::IamEntityprincipal.id に assumed-role ARN。タグは持たない。
  • tools/list のキャッシュにより「Unknown tool(クライアント側)」と「Tool Execution Denied(ゲートウェイ側)」を混同しない。最終確認はゲートウェイ側のログで。
  • カスタム作成のゲートウェイにポリシーエンジンを付ける場合、実行ロールに AuthorizeAction / PartiallyAuthorizeActions / GetPolicyEngine を忘れずに。

検証環境について

ここで作成した Policy Engine と IAM ゲートウェイへのアタッチは、後編(Guardrails 編)でもそのまま使います。リソースの削除手順は後編の最後にまとめます。

参考

余談

AWS Summit に来ています。
AgentCoreGateway 周りのアップデート紹介も多く、刺激を受けます。

山本 哲也 ฅ^•ω•^ฅ にゃー(記事一覧)

エンジニアです。データ分析に興味あります。ฅ^•ω•^ฅ にゃー

山を走るのが趣味です。(スカイランナー)ฅ^•ω•^ฅ にゃー