株式会社 日立製作所 Hitachi OSPO
[Bedrock AgentCore Gateway × Keycloak]MCP 2025-11-25 認可仕様に準拠したKeycloakでCIMDと認可コードフローを利用したMCP認可を試してみた
はじめに
こんにちは、最近実家の近くにラ・ムーができた株式会社 日立製作所の三本康貴です。
近年、AI Agent、Model Context Protocol(MCP)の普及に伴い、MCP Serverの開発、公開も増える一方で、既存のMCP Serverを統合したり、REST APIをMCP Serverとして管理するゲートウェイ機能の需要や認証認可の重要性が高まっています。
本記事では、MCPゲートウェイサービスである「Amazon Bedrock AgentCore Gateway」と認証認可サーバの「Keycloak」を組み合わせて、最新(2026年6月現在)のMCP 2025-11-25 認可仕様に準拠したMCP認可を検証していきます。
Amazon Bedrock AgentCore Gatewayとは
Amazon Bedrock AgentCore Gateway(以下、AgentCore Gateway) は、AWSが提供するAI Agent が外部ツールや既存システムへ安全に接続するためのマネージドなゲートウェイサービスです。
本検証では、次の機能を利用します。
- ツール統合
REST API、MCP Server、Lambda、API Gateway などの既存のサービスを単一のMCPエンドポイントに統合 - 包括的な認可
AI AgentやMCP Clientの身元確認や外部ツールへの接続を管理
AgentCore Gatewayの認可機能によって、AI AgentやMCP ClientなどがAgentCore Gatewayを呼び出す際に付与されるJWT、IAM identityを利用して呼び出し元が正当な利用者またはアプリケーションであることを検証することができます。JWT検証では、クレーム、スコープを検証します。AgentCore Gatewayと連携する認証認可サーバは、Amazon Cognito等の特定の認証認可サーバに依存せず、OAuth対応であれば連携可能です。
参考:
- Amazon Bedrock AgentCore Gateway: Securely connect tools and other resources to your Gateway
- Set up inbound authorization for your gateway
KeycloakとMCP認可
Keycloakは、OAuth 2.1 準拠の認証認可サーバのOSSであり、MCP認可サーバとして使用することが可能です。
MCP仕様では、認可サーバに対して複数のOAuth関連標準への対応が要求されています。Keycloakの対応バージョンと対応状況は、次の通りです。
| MCPバージョン | Keycloak対応状況 |
|---|---|
| 2025-03-26 | 対応 |
| 2025-06-18 | RFC 8707 Resource Indicators未対応のため部分対応 ※ |
| 2025-11-25 | RFC 8707 Resource Indicators未対応のため部分対応 ※ |
| 標準仕様 | MCP側の要求(2025-11-25) | Keycloak対応 |
|---|---|---|
| OAuth 2.1 Authorization Framework | MUST | 対応 |
| OAuth 2.0 Authorization Server Metadata / RFC 8414 | MUST | 対応 |
| OAuth 2.0 Resource Indicators / RFC 8707 | MUST | 未対応 |
| OAuth 2.0 Dynamic Client Registration / RFC 7591 | MAY | 対応 |
| OAuth Client ID Metadata Document / CIMD | SHOULD | 対応(ただし実験的) |
Keycloakは、OAuth 2.1 に準拠するほか、最新バージョン26.6(2026年6月現在)ではCIMDを実験的にサポートしています。
※ 公式リリースでは未対応になっているRFC 8707 Resource Indicatorsについても、OAuth 2.0の scope を利用したワークアラウンドが示されています。また、初期実装のPR(Initial experimental support for Resource Indicators#46763)は既に取り込まれており、まもなく対応されることが期待されます。
参考:
- Authorization - Model Context Protocol
- Integrating with Model Context Protocol (MCP)
- Keycloak 26.6.0 release
OAuth 2.1と認可コードフロー
OAuth 2.1については、弊社の黒坂さんが執筆した「OAuth 2.1」の認可コードフローを「Keycloak」で実装しようの説明が分かりやすいので引用します。
(引用開始)---
「OAuth 2.1」は、業界標準の認可プロトコルである「OAuth 2.0」の後継として提案されている仕様です。OAuth 2.0は柔軟性が高い反面、不適切な実装が生じる可能性がありました。OAuth 2.1は、10年以上に及ぶOAuth 2.0の運用から得たセキュリティのベストプラクティスを統合し、開発者が安全な実装をしやすくする目的で提案されています。
OAuth 2.1における主な変更点を以下にまとめます。
- 認可コードフローにおけるPKCE(Proof Key for Code Exchange)の必須化
- リダイレクトURIの完全一致の必須化
- Implicit Grantの廃止
- Resource Owner Password Credentials Grantの廃止
- URIのクエリでのBearerトークンの送信の禁止
- パブリッククライアントに向けたリフレッシュトークンは、送信者制約またはワンタイム使用にすることを必須化
OAuth 2.1はOAuth 2.0のセキュリティを強化したサブセットであり、これにより開発者は安全な実装が可能になります。
(引用終了)---
認可コードフローは、次の流れでAccess Tokenを取得します。
- クライアントが
code_verifierを生成し、そこからcode_challengeを作ります。 - クライアントはユーザエージェント、通常はブラウザを認可エンドポイントへリダイレクトします。
- 認可リクエストには
response_type=code、client_id、redirect_uri、scope、state、code_challenge、code_challenge_methodを含めます。 - 認可サーバはユーザを認証し、同意・認可判断を行います。
- 認可されると、認可サーバは
redirect_uriにcodeとstateを付けてリダイレクトします。 - クライアントはトークンエンドポイントに
grant_type=authorization_code、code、code_verifierを送ります。 - 認可サーバは認可コード、クライアント、
code_verifierを検証し、問題なければAccess Tokenを返します。
参考:
CIMDとは
CIMDは、OAuthのクライアント登録方法の1つで、クライアントとサーバの間に事前の関係がない、つまりAI AgentなどのクライアントをMCP認可サーバに事前登録していない場合でも、OAuthのフローを開始できるようになります。
MCPは、OAuthのクライアント登録方法について次の3つをサポートします。
- CIMD
クライアントとサーバの間に事前の関係がない場合。 - Pre-registration / 事前登録
クライアントとサーバの間に既存の関係がある場合。 - DCR(Dynamic Client Registration)/ 動的クライアント登録
後方互換性、または特定要件のために使用します。
CIMDは client_id 自体を HTTPS URL にして、そのURLで公開されるJSONメタデータを認可サーバが取得してクライアント情報として扱う方式です。
インフォメーション
本記事では、CIMDについてdraft-ietf-oauth-client-id-metadata-document-01 を前提に説明します。CIMDはInternet-Draft段階の仕様であり、今後の改訂により内容が変更される可能性があります。
クライアント登録を踏まえたMCPの認可コードフローのシーケンス図を示します。
※ シーケンス図はAuthorization Flow Stepsより引用
参考:Authorization - Model Context Protocol
改めて、本記事では、AgentCore GatewayとKeycloakを組み合わせて、
- CIMDを利用してクライアントを事前登録することなくOAuth 2.1 準拠の認可コードフローでKeycloakからAccess Tokenを取得できること
- 取得したAccess TokenでAgentCore Gatewayにアクセスできること
を検証します。
検証構成
AWS構成
今回の検証の主なAWS構成を示します。
👁 aws-system-architecture.drawio.png
※1 Keycloak、CIMD metadata、MCP Serverを同一EC2にホストし、同一internal ALBでルーティングします。可読性を考慮して構成図は分けて図示しています。
※2 Public subnet, Elastic IP, Nat GatewayはEC2のセットアップ時に利用しますが、検証の通信には利用しないため図を省略しています。
AWSサービス一覧
| 分類 | AWSサービス | 用途 |
|---|---|---|
| DNS | Route 53 Public Hosted Zone | ACM public certificateのDNS検証 |
| DNS | Route 53 Private Hosted Zone | VPC内でKeycloak、cimd、mcp-serverのドメイン名解決 |
| TLS | AWS Certificate Manager | internal ALBにpublic certificateを設定 |
| Network | VPC / Private Subnet | EC2、ALB、VPC Endpointを配置 |
| Network | Internal Application Load Balancer | Keycloak、CIMD、MCP ServerのHTTPS入口 |
| Network | SSM用VPC Endpoint | EC2にSSM経由でログイン、ポートフォワードでRDP接続 |
| Network | AgentCore Gateway用VPC Endpoint | VPC内のMCP InspectorからAgentCore Gatewayにアクセス |
| Compute | EC2 Linux | Keycloak、CIMD nginx、MCP Serverをホスト |
| Compute | EC2 Windows | MCP Inspectorを実行する踏み台 |
| Access | Systems Manager Session Manager | EC2への接続、RDPポートフォワード |
| MCP Gateway | AgentCore Gateway | MCP Client向け入口、JWT検証、Target集約 |
ドメイン設定
今回は次のドメインを登録して使用しました。別のドメインで検証する場合は、置き換えて読み進めてください。
agentcore-keycloak-example.com
サブドメインは次のように使います。
auth.agentcore-keycloak-example.com(Keycloak用)
cimd.agentcore-keycloak-example.com(CIMD用)
mcp-server.agentcore-keycloak-example.com(MCPサーバ用)
ACM public certificateは、次のようなワイルドカード証明書を利用します。
*.agentcore-keycloak-example.com
KeycloakはVPC内private resourceですが、AgentCore IdentityがOIDC Discovery URLをHTTPSで検証する必要があるため、internal ALBにpublic ACM certificateを付与します。
参考: AgentCore Identity private IdP
登場人物
| OAuth / MCPのロール | 今回の実体 | 説明 |
|---|---|---|
| Resource Owner | エンドユーザ | Keycloakにログインし、MCP Clientにアクセスを許可する |
| OAuth Client / MCP Client | MCP Inspector | KeycloakからAccess Tokenを取得し、AgentCore Gatewayを呼び出す |
| Authorization Server | Keycloak | 認可コードフローを担当する |
| Protected MCP Server / Resource Server | AgentCore Gateway | Keycloak JWTを検証し、MCPエンドポイントを提供する |
| Gateway Target | ALB + EC2上のMCP Server | 実際のMCP toolsを提供する |
検証
前提条件
ローカルPCに次のソフトウェアをインストールします。
- AWS CLI
- Session Manager Plugin
IAMの権限は必要に応じて付与してください。筆者はAdministratorAccess相当の権限で検証しています。
参考:
事前準備
次の事前準備を行います。自分で検証される方は必要に応じて参考にしてください。
- ドメイン登録とパブリックホストゾーン作成
- Windows踏み台EC2のkey-pair作成
- CloudFormationで検証環境を作成(AgentCore Gatewayを除く)
- EC2上でKeycloak、CIMD nginx、MCP Serverを起動
- Windows踏み台EC2にNode.jsをインストール
Keycloak設定
${ProjectName}-${EnvironmentName}-win-bastion-mcp-client-ec2にSSM経由でRDP接続します。
1. Realm作成
ブラウザからhttps://auth.agentcore-keycloak-example.com/adminでKeycloak管理コンソールにアクセスします。
User name:
admin
Password:
admin
Realmを作成します。
Realm name:
mcp-demo
Issuer URLは次です。
https://auth.agentcore-keycloak-example.com/realms/mcp-demo
Discovery URLは次です。
https://auth.agentcore-keycloak-example.com/realms/mcp-demo/.well-known/openid-configuration
このURLをAgentCore GatewayのInbound Identity detailsに設定します。
2. 検証ユーザ作成
「Users」から、Userを作成します。
Username:
alice
ユーザ作成後に上タブの「Credentials」からパスワードを設定します。
Password:
alice
Temporary:
OFF
3. Client Scope mcp:tools 作成
「Client scopes」からclient scopeを作成します。
Name:
mcp:tools
Protocol:
OpenID Connect
Client scope type:
Optional
👁 keycloak-client-scopes-3.png
作成後、Include in token scopeをONにします。これをONにしないと、Access Tokenのscope claimにmcp:toolsが入りません。
4. Audience mapper作成
MCP仕様では、Access Tokenが特定のMCPサーバ向けに発行されたものであることを保証するため、Audience Binding が求められます。
MCP側の要求は次の通りです。
- MCPクライアントは、認可リクエストおよびトークンリクエストで RFC 8707 の
resourceパラメータ を含める必要がある -
resourceの値は、そのトークンを使う対象のMCP Serverを識別する必要がある - MCP Serverは、提示されたトークンが自分自身のために発行されたものか検証する必要がある
ただし、Keycloakは現時点で resource パラメータを認識できません。そのため、Keycloakで同等の効果を得る暫定策として、resource の代わりにOAuth 2.0の scope を利用し、スコープに紐づくAudience MapperでAccess Tokenの aud クレームを設定します。
参考:Token Audience Binding and Validation
「Client scopes」→「mcp:tools」→「Mappers」から「Configure a new mapper」を押下します。
👁 keycloak-client-scopes-mapper-1.png
「Audience」を選択します。
👁 keycloak-client-scopes-mapper-2.png
設定例:
Name:
aud-agentcore-gateway
Included Custom Audience:
mcp-gateway-demo
Add to access token:
ON
Add to token introspection:
ON
👁 keycloak-client-scopes-mapper-3.png
「mcp:tools」スコープが要求された時に、MCP Serverの識別子としてaudクレーム「mcp-gateway-demo」を付与します。
Included Custom Audienceの値は、AgentCore Gateway側のAllowed audiencesの設定と一致させます。
5. CIMD Client Policy / Profile作成
Keycloakを--features=cimd付きで起動している前提です。
「Realm settings」→「Client Policies」→「Profiles」からCIMD用のClient Profileを作成します。この Client Policy / Profileを作成することでCIMDを利用することができます。
👁 keycloak-client-profile-2.png
Client Profileを作成後、client-id-metadata-document executorを追加します。
Executor:
client-id-metadata-document
👁 keycloak-client-profile-3.png
設定項目の内容は次の通りです。
| 設定 | 意味 |
|---|---|
| Allow http scheme | ONの場合、Client ID URLやメタデータ中のURLでHTTPを許可する。開発環境のみONにすべきで、本番ではOFF |
| Trusted domains | Client ID URLやメタデータURLとして許可するドメインパターン |
| Restrict same domain | ONの場合、Client ID URL、Redirect URI、メタデータ内URLが同じ信頼ドメイン配下にあることを確認する |
| Required properties | Client ID Metadata Documentに必須とするメタデータ項目 |
| Only Allow Confidential Client | ONの場合、confidential clientのみ許可する。その場合、jwks または jwks_uri が必要で、認証方式は private_key_jwt または tls_client_auth が必要 |
設定例:
Allow http scheme:
OFF
Trusted domains:
cimd.agentcore-keycloak-example.com
localhost
Restrict same domain:
OFF
Only Allow Confidential Client:
OFF
Required properties:
client_id
client_name
redirect_uris
👁 keycloak-client-profile-4.png
「Realm settings」→「Client Policies」→「Policies」からClient Policyを作成します。
Client Policyを作成し、client-id-uri conditionを追加します。このconditionでは、認可リクエストの client_id が、指定したURIスキームや信頼ドメインに一致するかを判定します。
| 設定 | 意味 |
|---|---|
| URI scheme |
client_id に許可するURIスキーム。本番では通常 https のみ |
| Trusted domains |
client_id URLのホスト部として許可するドメイン |
設定例:
Condition:
client-id-uri
URI scheme:
https
Trusted domains:
cimd.agentcore-keycloak-example.com
👁 keycloak-client-policies-2.png
Client Policyを作成後、Client Profileに追加します。
👁 keycloak-client-policies-3.png
6. OAuth 2.1 Client Policy / Profile作成
「Realm settings」→「Client Policies」→「Profiles」から OAuth 2.1 用のClient Profileを作成します。このClient Policy / Profileを作成することで OAuth 2.1 準拠の認可コードフローを強制します。
Client Profileを作成後、各Executorを追加します。
ビルトインのoauth-2-1-for-public-clientプロファイルをベースにoauth-2-1-for-public-client-no-dpopを作成します。OAuth 2.1 ではDPoP(Demonstration of Proof-of-Possession)は推奨ですが、本検証では利用しないため削除します。
Executor:
pkce-enforcer
reject-implicit-grant
reject-ropc-grant
secure-redirect-uris-enforcer
👁 keycloak-client-profile-oauth-1.png
secure-redirect-uris-enforcerExecutorは、検証のためloopback addressやhttpを許可します。
他のExecutorの設定は、oauth-2-1-for-public-clientプロファイルと同様なので省略します。
設定例:
Allow IPv4 loopback address:
ON
Allow IPv6 loopback address:
ON
Allow private use URI:
ON
Allow http scheme:
ON
Allow wildcard in context-path:
OFF
OAuth 2.1 Compliant:
ON
Allow open redirect:
OFF
👁 keycloak-client-profile-oauth-2.png
続いて、Client Policyを作成し、client-access-type conditionを追加します。このconditionでは、クライアントのアクセス種別がpublic clientかどうかを判定します。
設定例:
Condition:
client-access-type
Client Access Type:
public
👁 keycloak-client-policy-oauth-2.png
Client Profileにoauth-2-1-for-public-client-no-dpopを追加します。
👁 keycloak-client-policy-oauth-1.png
インフォメーション
OAuth 2.1 用のClient Profileで全てのExecutorが有効になることが正常な動きですが、検証してみたところsecure-redirect-uris-enforcerが有効化されないようです(2026年6月時点)。回避策として暫定的にCIMD用のClient Policyに OAuth 2.1用のClient Profileを追加することで、secure-redirect-uris-enforcerが有効化され、CIMDの無効なリダイレクトURIがバリデーションエラーになることが確認できたので、この対応方法で検証を進めています。本件については、KeycloakのGithub Issue作成含めkeycloakコミュニティーへのフィードバックを実施済みです。
[CIMD] secure-redirect-uris-enforcer is not enforced for CIMD public clients during authorization requests
#49456
Bedrock AgentCore Gateway設定
AWSマネジメントコンソールからBedrock AgentCore Gatewayの作成、設定を行います。
1. Gatewayを作成
AgentCore Gatewayを作成します。
Define gateway details:
Gateway name:
mcp-gateway-keycloak-demo
IAM permissions:
Create default role
JWT Authorization Configurationでaudとscopeで検証するよう設定します。
Inbound Identity details:
Inbound Auth type:
Use JSON Web Tokens (JWT)
JWT schema configuration:
Use existing Identity provider configurations
Discovery URL:
https://auth.agentcore-keycloak-example.com/realms/mcp-demo/.well-known/openid-configuration
JWT Authorization Configuration:
Allowed audiences:
mcp-gateway-demo
Allowed scopes:
mcp:tools
Allowed clients:
none
Custom claims:
none
VPC SecurityでAgentCore GatewayがKeycloak(Private Idp)が配置されるVPCにアクセスできるよう設定します。
ここで指定するSecurity GroupはKeycloakへのアクセスが許可されているものとします(CloudFormationで既に作成済み)。
VPC Security:
Managed
VPC:
${ProjectName}-${EnvironmentName}-vpc
Subnets:
${ProjectName}-${EnvironmentName}-private-b-alb-only
Security Group:
${ProjectName}-${EnvironmentName}-AgentCorePrivateIdpSecurityGroup
2. MCP Server Targetを作成
Select a target protocol:
MCP target
Target name:
my-mcp-server
Target type:
MCP server
MCP endpoint:
https://mcp-server.agentcore-keycloak-example.com/mcp
MCP listing mode:
Default
Outbound Auth configurations:
No auth
VPC SecurityでAgentCore GatewayがMCP Serverが配置されるVPCにアクセスできるよう設定します。
ここで指定するSecurity GroupはMCP Serverへのアクセスが許可されているものとします(CloudFormationで既に作成済み)。
Additional configurations:
VPC Security:
Managed
VPC:
${ProjectName}-${EnvironmentName}-vpc
Subnets:
${ProjectName}-${EnvironmentName}-private-b-alb-only
Security Group:
${ProjectName}-${EnvironmentName}-AgentCoreGatewayMcpServerEgressSecurityGroup
Endpoint IP address type:
IPv4
マネジメントコンソールでは、Gateway作成時にTargetも指定する画面フローになります。Gateway本体がまだCreatingの間にTarget作成が走り、次のようなエラーになることがあります。
Gateway ... is in Creating state, there was an error in creating the target
その場合、GatewayのステータスがReadyになった後、Targetを再作成してください。
Resource-based policyの設定(Option)
指定したVPC Endpoint以外からInvokeGatewayを拒否するResource-based policyの設定をします。
{"Version":"2012-10-17","Statement":[{"Sid":"AllowInvokeGatewayOnlyFromVpce","Effect":"Allow","Principal":"*","Action":"bedrock-agentcore:InvokeGateway","Resource":"arn:aws:bedrock-agentcore:ap-northeast-1:<account-id>:gateway/<gateway-id>","Condition":{"StringEquals":{"aws:SourceVpce":"<vpce-id>"}}},{"Sid":"DenyInvokeGatewayNotFromVpce","Effect":"Deny","Principal":"*","Action":"bedrock-agentcore:InvokeGateway","Resource":"arn:aws:bedrock-agentcore:ap-northeast-1:<account-id>:gateway/<gateway-id>","Condition":{"StringNotEquals":{"aws:SourceVpce":"<vpce-id>"}}}]}動作確認
${ProjectName}-${EnvironmentName}-win-bastion-mcp-client-ec2にSSM経由でRDP接続します。
参考:踏み台ホストを使用せずに、Systems Manager Session Manager のポート転送を使用して RDP 経由で EC2 インスタンスに接続する方法を教えてください
1. MCP Inspectorを起動
事前準備でNode.jsがインストールされている前提です。
powershellでホストと許可オリジンを指定してMCP Inspectorを起動します。
ホストを指定するのは Keycloak の OAuth 2.1 Client Policy / Profile によってlocalhostが拒否されるためです。
# コマンド例$env:HOST="127.0.0.1"$env:ALLOWED_ORIGINS="http://127.0.0.1:6274"npx-y@modelcontextprotocol/inspector@0.21.2参考:
2. MCP InspectorのOAuth設定
MCP Inspectorの接続先をAgentCore Gatewayにします。接続先はGateway resource URLを指定します。
Transport Type:
Streamable HTTP
URL:
https://<gateway-endpoint>/mcp
MCP InspectorのOAuth設定で、CIMD URLをClient IDとして指定します。
Client ID:
https://cimd.agentcore-keycloak-example.com/oauth/client-metadata.json
Scope:
mcp:tools
Connectionを押下して、MCP Serverへ接続を試みると、Keycloakのログイン画面に遷移します。
👁 mcp-inspector-alice-login.png
UsernameとPasswordを入力してログインすると、CIMDによってクライアント登録することを確認されます。
👁 mcp-inspector-cimd-access.png
Keycloakログイン後、MCP Inspectorの上タブのAuthからAccess Tokenを取得、デコードして以下が含まれることを確認します。
{"iss":"https://auth.agentcore-keycloak-example.com/realms/mcp-demo","aud":["mcp-gateway-demo"],"scope":"openid profile email mcp:tools"}3. MCP InspectorからAgentCore Gatewayへ接続(正常系)
OAuthで取得したAccess Tokenが付与された状態で接続します。
期待するtools:
add_numbers
multiply_numbers
greet_user
tools/callで次を実行します。
{"a":2,"b":3}add_numbersなら5、multiply_numbersなら6が返れば成功です。
4. MCP InspectorからAgentCore Gatewayへ接続(異常系)
誤ったスコープを指定して、再度MCP Serverに接続します。
Client ID:
https://cimd.agentcore-keycloak-example.com/oauth/client-metadata.json
Scope:
mcp:fail
👁 mcp-inspector-tools-fail-1.png
予期しないスコープのためアクセスが拒否されることを確認します。
👁 mcp-inspector-tools-fail-2.png
まとめ
本記事では、AgentCore GatewayとKeycloakを組み合わせて、
- CIMDを利用してクライアントを事前登録することなくOAuth 2.1 準拠の認可コードフローでKeycloakからAccess Tokenを取得できること
- 取得したAccess TokenでAgentCore Gatewayにアクセスできること
を検証しました。また機会があれば、AgentCore Gatewayから外部ツールへの接続(Outbound Authorization)や詳細なアクセス制御の検証を行っていきたいと思います。
Register as a new user and use Qiita more conveniently
- You get articles that match your needs
- You can efficiently read back useful information
- You can use dark theme
