mcpField
I
indykite-agent-gateway

indykite-agent-gateway

github.com/indykiteセキュリティ466 回インストール3 日前に更新
リポジトリ

indykite-agent-gateway について

A2A エージェントまたは MCP サーバーへの要求に対し、ID、ワークフロー認可、委任チェーンを検証する IndyKite Agent Gateway の設定スキルです。単一ホップと複数ホップの委任、設定、デプロイを扱います。

主な機能

  1. 01単一の A2A エージェントまたは MCP サーバーを保護
  2. 02呼び出し元の ID とワークフローアクセスを検証
  3. 03モデル化された委任チェーンを確認
  4. 04IdP または Token Service のトークン交換を設定
  5. 05ゲートウェイのデプロイと診断

活用シーン

  1. 01MCP サーバーの前段で認可を適用
  2. 02A2A ワークフロー内のエージェントを保護
  3. 03複数ホップ委任の設定
  4. 04ゲートウェイの認可失敗の調査

MCP 対応

`mcp` モードでは、IAG は MCP Streamable HTTP トラフィックを保護対象の MCP サーバーへプロキシし、A2A と同じ ID、認可、委任の検証を行います。指定された MCP プロトコルリビジョンのみを転送します。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/indykite/skills --skill indykite-agent-gateway

インストール後、Claude Code で/indykite-agent-gatewayを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

assets/
config-template.yaml
token-service-config-template.yaml
references/
architecture.md
configuration.md
token-service.md
troubleshooting.md

詳細

IndyKite Agent Gateway

Indykite Agent Gateway(IAG)は、下流の A2A エージェントまたは MCP サーバーのいずれか1つだけを保護するスタンドアロンサービスです。保護対象の下流ごとにIAGを1つ実行してください。呼び出し元から見るとIAGはターゲットとして振る舞い、保護対象の下流から見るとソースとして振る舞います。IAGは汎用的なリバースプロキシではありません。デフォルト(protocol: a2a)では A2Aプロトコルを使用し、A2Aセッションを追跡してJSON-RPCストリームが正しく流れるようにします。protocol: mcpの場合は MCP Streamable HTTPトラフィックをプロキシし(Mcp-Session-Idを転送し、SSEレスポンスをストリーミングします)、MCPプロトコルのリビジョン2025-06-18、2025-11-25、2026-07-28のみを転送します。いずれの場合も、同じ認可処理が前段で実行されます。

IAGはリクエストごとに、次の3点を検証します。

  1. 呼び出し元(IdPでのトークンイントロスペクション)。
  2. ワークフロー(AuthZEN/KBACによるサブジェクトのCAN_TRIGGERチェック)。Gateway 2.82.0以降、サブジェクトは呼び出し元のトークンを使ったContX IQ GET /contx-iq/v1/whoamiから取得されます。その型は、トークンを検証するプロジェクトのToken Introspect設定にあるikg_node_typeであり、そのIDはトークンのサブジェクト(sub、またはその設定で指定されたsub_claimという名前のクレーム)です。
  3. 委任チェーン(リクエストのactチェーンがIKGでモデル化されたチェーンと一致すること)。

actチェーンを含む委任トークンは、IdP(RFC 8693トークン交換)によって発行されるか、任意のtoken_serviceセクションを設定した場合は、セルフホスト可能な **IndyKite Token Service(ITS)**によって発行されます。ITSを使う場合、呼び出し元自身のアクセストークンはAuthorization内でそのまま渡され、委任トークンはX-IK-Tokenに添えて渡されます。また、X-IK-Token付きで届いたリクエストは後続のホップを表し、そのチェーンが次のトークンにネストされます。これにより、1ホップを超える長さのワークフローが可能になります。

使用する場面

次のような場合に、このスキルを有効にしてください。

  • エージェント間(A2A)ワークフローを構築しており、各エージェントの前段でポリシーを適用したい場合。
  • MCPサーバーの前段に適用ポイント(protocol: mcp)を設置し、MCPトラフィックにもA2Aと同じイントロスペクション、AuthZENチェック、監査を適用したい場合。
  • OAuthトークン交換とactチェーンによる、追跡可能なユーザーからエージェントへの委任が必要な場合。これには、IndyKite Token ServiceとX-IK-Tokenヘッダーを必要とするマルチホップチェーンも含まれます。
  • Token Service自体(発行者のbase_url、署名キー、オーディエンス、token_introspection設定)を構成している場合。
  • IndyKite Graph(IKG)でWorkflowノードとAgentノードをINVOKES関係とともにモデル化している場合。
  • 1つ以上のIAGインスタンス向けに、JARVIS_*環境変数またはconfig.yaml(token_service、healthcheck_port、キャッシュ調整、監査配信を含む)を設定している場合。
  • IAGまたはToken Serviceの監査レコード(AUTHORIZED / NOT_AUTHORIZED、TOKEN_EXCHANGED / EXCHANGE_REFUSED、INTROSPECTED*)を確認し、401または403の原因を調べている場合。
  • iag-mcp-demo(A2A + MCP)またはiag-token-exchange(Token Service)のリファレンスアプリケーションを再現または拡張している場合。

次のような場合は、このスキルを有効にしないでください。

  • 汎用HTTPリバースプロキシまたはサービスメッシュが必要な場合。IAGが対応するのはA2AまたはMCPのみで、任意のHTTPには対応していません。
  • エージェントのゲーティングと無関係なIndyKiteの機能について質問している場合(ゲートウェイの呼び出し元に必要なもの以外のToken Introspect設定、一般的なAuthZENポリシー、エージェントのゲーティング以外のContX IQクエリ)。
  • ゲートウェイではなく、保護対象のエージェント自体をデバッグしている場合。

前提条件

以下の手順が成功するには、あらかじめ次のものが必要です。

  • AuthZEN/KBAC と ContX IQ が有効になっており、Workflow ノードと Agent ノードがすでにモデル化されている(またはモデル化する予定がある。手順 1 を参照)IndyKite プロジェクト。
  • introspect、client-credentials、token-exchange エンドポイントを備えた OAuth2 準拠の IdP。対象環境の IdP ベース URL を IDP_BASE_URL に設定してください。Token Service を使う場合も IdP は必須です。IdP は呼び出し元のアクセストークンを introspect し、保護されたエージェントを認証します。
  • 保護されたダウンストリーム(A2A エージェントまたは MCP サーバー)ごとに 1 組の client_id/client_secret。IdP に登録してください。
  • 保護されたダウンストリームごとに (workflow, agent_list) ペアを返す ContX IQ クエリ。その query_id を IAG の設定に指定します。
  • MCP ダウンストリーム(protocol: mcp)の場合:MCP サーバーのオリジンとエンドポイントパス、およびゲートウェイイメージ indykite/agent-gateway ≥ 2.0.1(古いイメージはプロトコルを無視し、A2A プロキシとして動作します)。MCP クライアントは、Token Introspect 設定の対象となる introspect 可能な呼び出し元で(ゲートウェイ 2.82.0 以降。次の項目を参照)、AuthZEN チェックに合格する必要があります。
  • ゲートウェイ 2.82.0 以降では、ゲートウェイを呼び出すすべての呼び出し元に対する Token Introspect 設定が必要です。その ikg_node_type はトリガーポリシーで指定するサブジェクトタイプです。サブジェクトの手順を参照してください(2.82.0 より前は authzen.subject_types)。
  • 1 ホップを超えるワークフロー(エージェント → エージェント → エージェント)の場合、または保護されたエージェントが呼び出し元の元のアクセストークンを参照する必要がある場合:https の issuer base_url、少なくとも 1 つの署名キー、すべての保護されたエージェントの audience、およびゲートウェイ用の client_auth クライアントを備えた、稼働中の IndyKite Token Service(indykite/token-service)。references/token-service.mdを参照してください。これがない場合、ゲートウェイは各ホップで IdP にトークンを交換し、チェーンは 1 ホップを超えて伸びません。
  • iag-mcp-demo のリファレンスアプリを実行するための Docker(および Docker Compose)。

これらのいずれかが欠けている場合は、そこで作業を中止してユーザーに伝えてください。IAG はこれらがなければ実行できません。

手順

1. IKG でワークフローをモデル化する

external_id で識別される Workflow ノードを 1 つ作成し、保護するエージェントごとに Agent ノードを 1 つ作成して、エージェント間に INVOKES 関係を作成します。すべての INVOKES 関係には、値が Workflow.external_id と一致する workflow_name プロパティを必ず設定してください。手順 3 の ContX IQ クエリは、このプロパティがないチェーンを通知なく除外します。

例の形(デモの標準的な wf1 ワークフロー):

(Workflow {external_id: "wf1"})
(Agent {external_id: "orchestrator"})
  -[INVOKES {workflow_name: "wf1"}]-> (Agent {external_id: "retriever"})
(Agent {external_id: "orchestrator"})
  -[INVOKES {workflow_name: "wf1"}]-> (Agent {external_id: "weather"})

このデータは Capture API(POST /capture/v1/nodes、POST /capture/v1/relationships)、IndyKite Hub UI、または既存の Terraform/ID 管理パイプラインのうち、プロジェクトですでに使用している方法で取り込みます。

2. サブジェクトをワークフローに接続する

ワークフローのトリガーが許可されている各サブジェクトについて、エッジ (:User)-[:CAN_TRIGGER]->(:Workflow)(または同等の AuthZEN リレーション)を作成します。このエッジがないと、チェーンが正しくても IAG は AuthZEN チェックで 403 を返します。

3. ContX IQ クエリを作成する

このクエリは、保護されたエージェント識別子を指定すると (workflow, agent_list) ペアを返す必要があります。agent_list は、リクエストが通過する必要のあるエージェントの順序付きチェーンです。query_id を保存してください。IAG は JARVIS_CONTX_IQ_QUERY_ID(または contx_iq.query_id)を介してこれを参照します。

CAN_TRIGGER の背後にある KBAC ポリシーが委任トークンを読み取る場合は、ゲートウェイが実際に転送するトークンを参照する必要があります。IdP が発行する場合は $token(Authorization を置き換えます)、Token Service が発行する場合は $ik_token(X-IK-Token で転送されます)です。送信されていないトークンを参照すると、何も解決されず、判定は拒否になります。

4. 各 IAG インスタンスを設定する

次の2種類の設定方法から選択します。

  • YAML 設定ファイル - --config=/app/config.yaml を指定します。設定管理が厳格な本番環境に適しています。このスキルの assets/config-template.yaml を参照してください。
  • 環境変数 - キーには JARVIS_ プレフィックスとアンダースコアを使用します(例:JARVIS_SERVICE_NAME)。複数の IAG インスタンスでベースイメージを共有し(iag-mcp-demo のように)、エージェントごとのフィールドのみを上書きする場合に適しています。

セクション一式は service、identity_provider、token_service(省略可)、protected_agent、authzen、contx_iq、audit です。各フィールドとそのデフォルト値については、references/configuration.md を参照してください。

protected_agent.protocol(環境変数 JARVIS_PROTECTED_AGENT_PROTOCOL)で下流プロトコルを選択します。A2A エージェントの場合は a2a(デフォルト)、MCP サーバーの場合は mcp を指定します。それ以外の値を指定すると、起動時に invalid protected_agent protocol エラーが発生します。mcp モードでは、protected_agent.base_url には MCP サーバーの オリジンのみ を指定します。IAG が受信リクエストのパスを付加します。認可の手順は変わらず、転送されるプロトコルのみが異なります。mcp モードでは、ゲートウェイは MCP プロトコルのリビジョンも強制します。転送されるのは 2025-06-18、2025-11-25、2026-07-28 のみです。initialize 以外のすべてのリクエストには、これらのいずれかを指定した Mcp-Protocol-Version が必要です。また、JSON-RPC バッチ、エンコードされたボディ、4 MiB を超えるボディは、認可前に JSON-RPC エラーを返して拒否されます。ゲートウェイの背後にある MCP サーバーは、これら3つのリビジョンのうち少なくとも1つに対応している必要があります。references/configuration.md の Protecting an MCP server セクションと、references/architecture.md の MCP protocol revisions セクションを参照してください。

委任トークンの取得元は、省略可能な token_service セクション(base_url、exchange_endpoint、introspect_endpoint、client_auth.type: client_secret_basic、client_auth.client_id、client_auth.client_secret。環境変数は JARVIS_TOKEN_SERVICE_*)で選択します。省略すると、IdP がトークンを交換します。設定すると、Token Service が委任トークンを発行し、リクエストは Authorization と X-IK-Token の両方を付けて転送されます。また、受信した X-IK-Token は Token Service で検証され、次回の交換のサブジェクトになります。設定する場合は、ゲートウェイが要求するオーディエンスも protected_agent.authentication.audiences に列挙してください。いずれも Token Service の idp.audiences に含まれている必要があり、含まれていない場合、交換は invalid_target で拒否されます。

IAG インスタンスごとに異なる値にしなければならない項目は次のとおりです。

  • service.name / JARVIS_SERVICE_NAME
  • service.port / JARVIS_SERVICE_PORT
  • service.healthcheck_port / JARVIS_SERVICE_HEALTHCHECK_PORT(複数のインスタンスで同じネットワーク名前空間を共有する場合のみ。デフォルトは 9080)
  • protected_agent.base_url / JARVIS_PROTECTED_AGENT_BASE_URL
  • protected_agent.protocol / JARVIS_PROTECTED_AGENT_PROTOCOL(いずれかのインスタンスが MCP サーバーを保護する場合)
  • protected_agent.authentication.client_id および client_secret
  • protected_agent.authentication.audiences(Token Service を使用する場合、そのインスタンスの保護対象エージェントのオーディエンス)

token_service セクション自体は、すべてのインスタンスで同じです。

5. IAG インスタンス(および使用する場合は Token Service)をデプロイする

Docker Compose では、iag-mcp-demo のパターンに従います。共有の iag-base-docker.yaml を 1 つ用意し、保護対象のエージェントごとにサービスを 1 つずつ用意して、上記のインスタンスごとのフィールドのみを上書きします。Kubernetes では、独立したスケーリングを可能にするために各 IAG をスタンドアロン Pod としてデプロイするか、より緊密に連携させるために保護対象のエージェントのサイドカーとしてデプロイします。

各ゲートウェイは service.healthcheck_port(デフォルトは 9080)で /healthz、/readyz、/startupz を提供し、コンテナイメージの HEALTHCHECK は http://localhost:9080/healthz をプローブします。古いイメージではこのエンドポイントが提供されず、稼働中ずっと unhealthy と報告されていました。コンテナのヘルス状態に基づくオーケストレーションが一度も起動しない場合は、現在のイメージを取得してください。

Token Service はすべてのゲートウェイで共有するデプロイを 1 つ用意します。indykite/token-service を実行し(latest は使用せず、1.0.0 などの具体的なタグを指定してください)、--config=<file> を指定します。本番環境では、シークレット(署名鍵、client_auth)を別ファイルとしてマウントし、機密情報を含まない定義にマージできるよう、--config-dir=<dir> を指定します。service.base_url(署名するすべてのトークンの iss)は必須で、デフォルト値はなく、https でなければなりません。詳細は references/token-service.md を参照してください。

IndyKite プラットフォームでは、ITS が署名するトークンを信頼するように設定する必要があります。設定しない場合、X-IK-Token を含むリクエストが AuthZEN、ContX IQ、または MCP サーバーに到達するたびに、401 Invalid token in X-IK-Token header で拒否されます。委任トークンが持つ可能性のあるオーディエンスごとに、Token Introspect 設定を 1 つ作成します(POST /configs/v1/token-introspects、Service Account トークンを使用)。設定値は、jwt_matcher.issuer = ITS の base_url、jwt_matcher.audience = 保護対象エージェントのオーディエンス、offline_validation.public_jwks = 署名鍵の公開鍵です。正確なペイロードについては、references/token-service.md の Making the platform trust ITS tokens セクションを参照してください。

各 IAG から IdP、AuthZEN、ContX IQ、Token Service(設定している場合)、および保護対象のエージェントに到達できることを確認してください。デプロイ時によくある障害は、IAG 自体ではなくネットワークレベルで発生します。

6. ランタイムパスを検証する

ゲートウェイ経由でリクエストを送信し、9 段階のパスがエンドツーエンドで実行されることを確認します。想定される HTTP レスポンスは次のとおりです。

  • 200 - リクエストが認可され、転送されました。
  • 400 - 不正なリクエストです。mcp モードでは、JSON-RPC エラーボディが返されます。-32020(Mcp-Protocol-Version ヘッダーがない場合、または 2026-07-28 時点で Mcp-Method / Mcp-Name ヘッダーがボディと異なる場合)、-32022(未サポートのリビジョン。error.data.supported に 3 つのリビジョンが列挙されます)、-32600(JSON-RPC バッチ、JSON-RPC 2.0 メッセージではない、あいまいなキー、または制御文字を含むメソッド / ツール名 / URI)、-32602(存在しないツールを指定する tools/call、または存在しないリソース URI を指定する resources/read、resources/subscribe、resources/unsubscribe)、または -32700(ボディを読み取れない、有効な UTF-8 ではない、または JSON 値がちょうど 1 つではない)。ゲートウェイは、リクエストで指定されたツールまたはリソースを毎回読み取り、明確に読み取れないものを拒否します — MCP リクエストの分類。
  • 401 - 呼び出し元のトークンがない、または無効です(Missing bearer token、Invalid token, missing subject)。2.82.0 以降では、プロジェクトの Token Introspect 設定で受け入れられないトークン({"message":"Unauthorized","errors":["ContX IQ whoami failed"]}、監査理由 cannot resolve the subject of the access token)、または使用できない受信 X-IK-Token(Invalid delegated token, subject mismatch / missing subject)も該当します。
  • 403 - 呼び出し元は認証されていますが、許可されていません(サブジェクト、チェーン、またはその両方)- Authorization check failed。理由は監査レコードにのみ記録されます。no workflow matches the actors chain(ホップがスキップされた場合、または委任トークンが別のチェーンで再利用された場合)、または subject <type>/<id> is not authorized to trigger any of the workflows <ids>(チェーンは一致するものの、ユーザーが CAN_TRIGGER を持たない場合。2.82.0 より前は <type>/<id> を含みません)- チェーンによる拒否。
  • 413 / 415 - mcp モードのみ:ボディが 4 MiB を超える場合、または Content-Encoding が identity 以外の場合。JSON-RPC エラー -32600。
  • 500 - 内部エラーです。
  • 502 - IdP または Token Service に到達できない、あるいは読み取り不能な応答が返される場合を含む、上流側 / ゲートウェイ側の処理エラーです。プロバイダーの停止は障害として報告され、拒否としてカウントされることはありません。

サービスログ(標準出力への JSON)と監査レコードを併せて確認します。サービスログは IAG が何をしたか を説明し、監査レコードは IAG が何を判断したか を説明します。IdP または Token Service への呼び出しが拒否された場合、エンドポイント、ステータス、サニタイズされたレスポンスボディのプレビューがログに記録されるため、誤ったクライアントシークレットとエンドポイントの障害を区別できます。

7. 監査証跡を確認する

監査レコードはサービスログとは別のストリームに出力されます。配信方法は次のいずれかに設定します。

  • Webhook - audit.delivery: webhook、audit.http.url、audit.http.method(post または put)、認証 type は no-auth、api-key、mTLS のいずれかです。
  • ファイル - audit.delivery: file、audit.file.storage_path、audit.file.format(csv、json、txt)、audit.file.rotation_strategy(size、time、size-and-time)。

どちらの方法も audit.async.buffer_size(デフォルトは 512)でバッファリングできます。バッファ内のレコードはシャットダウン時に排出され、キューが満杯の場合はレコードが破棄され、サービスログに警告が記録されます。

各ゲートウェイレコードには、decision(AUTHORIZED、NOT_AUTHORIZED、またはリクエストの判断ができなかった場合の ERROR)、reason、subject、actor、actorsChain、action、service、timestamp、traceID が含まれます。traceID は、保護対象のエージェントのログおよび上流のクライアントと照合するために使用します。Token Service は、すべての交換およびイントロスペクションについて同じ形式のレコードを記録します。判断は TOKEN_EXCHANGED / EXCHANGE_REFUSED、INTROSPECTED / INTROSPECTED_INACTIVE / INTROSPECTION_REFUSED、および ERROR で、さらに tokenID(トークンの jti)も記録されます。

8. 拒否パスを意図的にテストする

IAG が期待どおりに適用されていることを確認するため、意図的に NOT_AUTHORIZED の結果を発生させます。

  • チェーン内のエージェントをスキップする(例:act でオーケストレーターを介さず、retriever-iag を直接呼び出す)。
  • 1 つの INVOKES リレーションシップから workflow_name を削除する - ContX IQ はそのチェーンを返さなくなります。
  • 対象とワークフロー間の CAN_TRIGGER エッジを削除する - AuthZEN は拒否します。
  • Token Introspect の設定で、ikg_node_type にトリガーポリシー名がないトークンを使って呼び出す - ポリシーに一致せず、403 になります(2.82.0 より前では、JARVIS_AUTHZEN_SUBJECT_TYPES に対象のタイプがありません)。
  • Token Service を使用している場合:別のユーザーのアクセストークンで X-IK-Token をリプレイする - 401 Invalid delegated token, subject mismatch になります。
  • mcp インスタンスで:Mcp-Protocol-Version ヘッダーなしで tools/list を送信する - JSON-RPC エラー -32020 を含む 400 になり、理由 MCP request refused: Header mismatch: Mcp-Protocol-Version header is missing を伴う NOT_AUTHORIZED として監査されます。
  • mcp インスタンスで:params に name がない tools/call を送信する - JSON-RPC エラー -32602 を含む 400 になり、理由 MCP request refused: Invalid params: tools/call names no tool を伴う NOT_AUTHORIZED として監査されます。サーバーには到達しません。

それぞれ 403 Forbidden(トークンの組み合わせでは 401、MCP のリビジョンと分類のチェックでは 400)を返し、有用な reason を含む NOT_AUTHORIZED の監査レコードを生成する必要があります。

結果

このスキルが正常に適用されると、次の状態になります。

  • Workflow ノード、該当する Agent ノード、および INVOKES エッジ(workflow_name を含む)が IKG に存在します。
  • ContX IQ のクエリは、保護対象の各エージェントについて正しい (workflow, agent_list) のペアを返します。
  • 保護対象の各エージェントの前で IAG インスタンスが 1 つずつ実行され、インスタンスごとの適切な設定が適用され、/healthz が正常な状態を報告します。
  • ゲートウェイが 2.82.0 以降の場合、indykite-ciq-whoami スキルは、ゲートウェイのすべての呼び出し元をトリガーポリシーで指定された対象タイプに解決します。
  • ワークフローに複数のホップがある場合、Token Service が実行され、すべてのゲートウェイがそれを参照し、プロジェクトには ITS が発行する各オーディエンス向けの Token Introspect 設定があり、転送されるリクエストには Authorization と X-IK-Token が含まれ、チェーンはホップごとに伸長します。
  • 正常に実行される標準的なプロンプトはゲートウェイチェーンを通過し、経由したすべての IAG で AUTHORIZED の監査レコードを生成します(Token Service では TOKEN_EXCHANGED レコードも生成します)。
  • 標準的な拒否パスでは 403 Forbidden が返され、人が読める reason を含む NOT_AUTHORIZED の監査レコードが生成されます。

このスキルのファイル

  • references/architecture.md - IAG リクエストパスの 9 つのステップ、委任トークンの受け渡し($token と $ik_token)、マルチホップチェーン、ゲートウェイが転送する MCP プロトコルのリビジョン、IKG のデータ構造。
  • references/configuration.md - token_service、ヘルスポート、キャッシュルール、監査ログの配信を含む、IAG のすべての設定セクション、フィールド、デフォルト値。
  • references/token-service.md - IndyKite Token Service:エンドポイント、設定(service.base_url、idp、token_introspection)、設定ディレクトリのマージ、監査判断、デプロイに関する注意事項。
  • references/troubleshooting.md - 一般的な障害モードと対応する修正方法。
  • assets/config-template.yaml - コピーして調整できる、ゲートウェイ用のスターター config.yaml。
  • assets/token-service-config-template.yaml - Token Service 用のスターター config.yaml。

エージェント固有の注意事項

このスキルでは汎用的な Markdown の手順を使用しており、README に記載されているすべてのエージェントで動作します。Claude Code のフック、Cursor の @メンション、Copilot のワークスペースコンテキスト、その他エージェント固有の機能は必要ありません。タスク中にエージェントが IndyKite API を直接呼び出す場合にのみネットワークアクセス(curl、エージェントのウェブツール、または MCP)が必要です。セットアップのみの作業では、特別なツールは不要です。

参考資料

コメント