Agent Runtime から外部 MCP への Agent Gateway 下り(外向き)

1. はじめに

この Codelab では、Google Cloud の外部でホストされている外部 Model Context Protocol(MCP)サーバーにアクセスする AI エージェントの Agent Gateway 下り(外向き)ガバナンスについて説明します。

スタンドアロンのチャットボットからマルチエージェント ワークフローを備えた自律型システムまで、AI アプリは外部ツールを動的に呼び出すことができます。安全で生産性の高いエージェントを実現するには、データベースのクエリ、ウェブ コンテンツの取得、アクションの実行に対する制御されたアクセスをエージェントに提供することが不可欠です。ただし、エンタープライズ環境では、エージェント ツールの実行を保護することが課題となります。エージェントがネットワークに直接アクセスできる場合、プロンプト インジェクション攻撃やモデルのハルシネーションによって、エージェントがセンシティブ データを流出させたり、破壊的なコマンドを実行したりする可能性があります。

自律エージェントを大規模に管理するために、Agent Gateway は Agent Platform アーキテクチャに直接統合された、一元化されたゼロトラストの適用ポイントを提供します。Agent Gateway は、各アプリケーションまたはエージェント コードに固有のカスタム実装に依存するのではなく、プラットフォーム レベルで適用されるネットワーク ルーティング、エージェント ガバナンス、ランタイム セキュリティを提供します。

Agent Gateway が下り(外向き)(agent-to-anywhere)モードで動作している場合、ゲートウェイを使用するように構成されたエージェントからのすべての送信リクエストをプロキシします。各エージェント ワークロード リクエストは、一意のエージェント ID を使用して認証され、Identity-Aware Proxy(IAP)ポリシーを使用して認可されます。MCP ツールの呼び出しは動的にデコードされ、ポリシーの適用について検査されます。セキュリティ管理者は、きめ細かい権限を一元的に適用して、エージェントが承認済みのエンドポイントとメソッドのみを呼び出せるようにすることができます。

構築内容

  • 下り(外向き)モード(エージェントから任意の宛先へ)の Agent Gateway
  • Identity-Aware Proxy(IAP)認可拡張機能
  • Agent Runtime ADK エージェント(エージェント ID 付き)
  • Google API と MCP エンドポイントを含む Agent Registry
  • データコモンズの公開データセットへの外部 MCP ツールの接続
  • IAM アクセス制御による認可ポリシー

figure1

図 1. Codelab アーキテクチャ

学習内容

  • 構造化された構成シーケンスで Agent Gateway をデプロイする方法
  • 認可ポリシーをドライラン モードから適用モードに移行する方法
  • Google API エンドポイントと MCP サーバーを Agent Registry に登録する方法
  • MCP プロトコル属性に基づく条件付き認証ポリシーの使用方法
  • Agent Gateway のログを監査して下り(外向き)ガバナンスを検証する方法

必要なもの

  • 課金を有効にした Google Cloud プロジェクト
  • ネットワーキング サービスと Agent Platform リソースをプロビジョニングするための IAM 権限
  • Google Cloud CLI(gcloud コンポーネントと bq コンポーネント)がインストールされた POSIX 互換シェル(bash または zsh
  • コマンドライン ツール: gitcurljq(JSON プロセッサ)、Python 3、uv(Python パッケージ マネージャー)
  • クエリ テスト データセットにアクセスするための無料の Data Commons API キー

2. コンセプト

デプロイ シーケンス

この Codelab では、構造化された構成シーケンスに従って、エージェントが初期化時に必要なリソースにアクセスできるようにし、強制アクセス ポリシーを適用する前に接続を確認できるようにします。

この Codelab では、次のデプロイ シーケンスを使用します。

  1. DRY_RUNモードで開始: エージェント リクエストがゲートウェイに正常に到達し、通過していることを確認します(監査専用モード)。
  2. すべてのサービスを登録する: エージェント レジストリにすべてのエージェント コンポーネントを登録し、エージェント ツールのアクセス権を確認します。
  3. 認可ポリシーを作成する: エージェントから MCP サーバーとエンドポイントへの下り(外向き)トラフィックを許可する認可ポリシーを作成して適用します。
  4. ENFORCEDモードに切り替えます: 認証拡張機能ポリシーを更新して、ポリシーを適用し、承認されていない下り(外向き)トラフィックをブロックします。

figure2

図 2. デプロイ シーケンス

下り(外向き)ルーティング トポロジ

Agent Gateway の下り(外向き)(agent-to-anywhere)は、エージェント ワークロードの一元化されたゼロトラスト アウトバウンド プロキシとして機能します。エージェントが外部ツールまたは API にリクエストを行うと、送信リクエストはエージェント ゲートウェイによってインターセプトされ、ガバナンス ポリシーに対して評価されてから、宛先にルーティングされます。Google Cloud Agent Platform アーキテクチャでは、Agent Gateway は次のものにデータプレーン接続を提供します。

  • プライベート ネットワーク(VPC): プライベート VPC 内でホストされている内部エンタープライズ API、マイクロサービス、データベース、ハイブリッド接続を介してアクセス可能なオンプレミスまたはクロスクラウド ネットワークをターゲットとするアウトバウンド トラフィック。
  • 外部ネットワーク(インターネット): サードパーティのウェブサービス、SaaS API、パブリック エンドポイントをターゲットとするアウトバウンド トラフィック。
  • AI サービスと Agent Platform: マネージド Google Cloud API、基盤モデル、Google MCP エンドポイント(BigQuery など)、プラットフォーム ガバナンス サービス(Agent Registry と IAP ポリシー)を対象とするアウトバウンド トラフィック。

figure3

図 3. Agent Gateway の下り(外向き)ルーティング トポロジ

この Codelab では、インターネット経由でアクセス可能な外部のサードパーティ MCP サーバー エンドポイントをターゲットとする Agent Runtime のカスタム エージェントからのアウトバウンド トラフィックに焦点を当てます。

MCP プロトコルの検査

Agent Gateway の下り(内向き)トラフィック(agent-to-anywhere)は、MCP リクエストの内容を解析し、きめ細かいプロトコル属性に基づいてアクセス ポリシーを評価できます。エージェントから MCP サーバーへの下り(外向き)ポリシーには、Common Expression Language(CEL)で表現された条件を含めることができます。この条件は、すべてのリクエストで実行時に適用されます。

MCP 呼び出しでは通常、JSON-RPC ワイヤー プロトコル形式と HTTP トランスポートが使用されます。呼び出される MCP メソッド(tools/call など)、ターゲット ツール名、引数の詳細は、HTTP 本文の JSON ペイロードに含まれています。

iap.googleapis.com/mcp.toolName 属性は、JSON 本文を解析してリクエストで指定されたツール識別子を見つけることで、Agent Gateway によって抽出されます。

通常、iap.googleapis.com/mcp.tool.isReadOnlymcp.tool.isDestructive などの属性は各リクエストの本文で送信されません。これらは、ツールに関連付けられたアノテーション(メタデータ)です。そのため、Agent Gateway が本文から toolName を抽出すると、toolspec.json コンテンツが登録された Agent Registry からツール定義と関連プロパティが検索されます。

figure4

図 4. Agent Gateway MCP の検査

IAP IAM 条件で使用される CEL 式は、標準形式 api.getAttribute('iap.googleapis.com/ATTRIBUTE_NAME', 'DEFAULT_VALUE')== 'DESIRED_VALUE' を使用します。

次の表に、MCP サーバー リクエストに適用できるエージェント ゲートウェイの下り(外向き)ガバナンス属性を示します。

属性

MCP の方法 / 場所

説明

mcp.toolName

tools/call(本文)

RPC ペイロードでリクエストされたターゲット ツールの識別子(例: "delete_instance"

mcp.tool.isReadOnly

エージェント レジストリ(toolspec.json

ツールが読み取り専用かどうかを示します(環境を変更しない)。

mcp.tool.isDestructive

エージェント レジストリ(toolspec.json

ツールを呼び出すと、元に戻せない変更やデータ損失が発生する可能性があるかどうかを示します。

mcp.tool.isIdempotent

エージェント レジストリ(toolspec.json

同じ引数でツールを繰り返し実行すると、まったく同じ状態になるかどうかを示します

mcp.tool.isOpenWorld

エージェント レジストリ(toolspec.json

ツールが境界内の内部システムから境界のない公共のインターネットにアクセスするかどうかを示します

これでコンセプトの説明は終わりです。次は セットアップ セクションに進みます。

3. セットアップ

必要な IAM のロール

この Codelab でリソースを作成するには、次のロールが必要です。

カテゴリ

必要な IAM ロール(ID)

説明

API 管理

roles/serviceusage.serviceUsageAdmin

Google Cloud API サービスを有効にする

ネットワーキングとゲートウェイ

roles/networkservices.admin

Agent Gateway をプロビジョニングする

Service Extensions

roles/serviceextensions.admin

ルーティング拡張機能を構成する

ネットワーク セキュリティ

roles/networksecurity.admin

認可ポリシーをデプロイする

Agent Registry

roles/agentregistry.admin

カタログで許可されたホスト

Vertex AI とエージェント

roles/aiplatform.admin

Agent Runtime ワークロードをデプロイする

外向きポリシー

roles/iap.admin

roles/iap.egressor ポリシーを適用する

Cloud Storage

roles/storage.admin

デプロイ ステージング バケットを管理する

ログと監査

roles/logging.viewer

トレースと監査ログを検査する

または、roles/admin などの広範な基本ロールや、以前のロール roles/owner を使用します。

プロジェクトにアクセスする

この Codelab では、1 つの Google Cloud プロジェクトを使用します。構成手順では、gcloud CLI と Linux シェルコマンドを使用します。

まず、Google Cloud プロジェクトのコマンドラインにアクセスします。

プロジェクト ID を設定する

gcloud config set project SET_YOUR_PROJECT_ID_HERE

セッションを認証する

# login to gcloud cli
gcloud auth login
# login for gcloud api
gcloud auth application-default login

シェル環境変数を設定する

# set custom var for slug (eg, "foo") and region preference
export SLUG="foo"
export REGION="us-central1"
export MREGION="us"
echo ${SLUG}
echo ${REGION}
echo ${MREGION}
# create project vars (automatic)
export PROJ_ID=$(gcloud config list --format="value(core.project)")
export PROJ_NO=$(gcloud projects describe ${PROJ_ID} --format="value(projectNumber)")
export ORG_ID=$(gcloud projects get-ancestors ${PROJ_ID} --format="value(id)" | tail -n 1)
echo ${PROJ_ID}
echo ${PROJ_NO}
echo ${ORG_ID}
# create resource vars (automatic)
export AGW_NAME="agw-${SLUG}-${REGION}-ata"
export AGW_URI="projects/${PROJ_ID}/locations/${REGION}/agentGateways/${AGW_NAME}"
export RE_AGENT_NAME="agent-datacommons"
export RE_AGENT_ID_SET="principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJ_NO}"
export STAGING_BUCKET="agent-staging-${PROJ_NO}"
export MCP_DISPLAY_NAME="api.datacommons.org"
export MCP_RESOURCE_NAME="${REGION}-datacommons-mcp"
export MCP_URL="https://api.datacommons.org/mcp"
echo ${AGW_NAME}
echo ${AGW_URI}
echo ${RE_AGENT_NAME}
echo ${RE_AGENT_ID_SET}
echo ${STAGING_BUCKET}
echo ${MCP_DISPLAY_NAME}
echo ${MCP_RESOURCE_NAME}
echo ${MCP_URL}
# create local dir for config files
mkdir -p cfg

Google Cloud SDK のセルフマネージド インストール(Cloud Shell の外部)を実行している場合は、コンポーネントを最新バージョンに更新します。

# update gcloud cli
gcloud components update

API サービスを有効にする

# enable google apis (agent platform bundle, part 1)
gcloud services enable \
  agentregistry.googleapis.com \
  aiplatform.googleapis.com \
  apphub.googleapis.com \
  apptopology.googleapis.com \
  cloudapiregistry.googleapis.com \
  cloudtrace.googleapis.com \
  compute.googleapis.com \
  dataform.googleapis.com \
  iam.googleapis.com \
  iamconnectors.googleapis.com \
  iap.googleapis.com \
  logging.googleapis.com \
  modelarmor.googleapis.com \
  monitoring.googleapis.com \
  networksecurity.googleapis.com \
  networkservices.googleapis.com \
  notebooks.googleapis.com \
  observability.googleapis.com
# enable google apis (agent platform bundle, part 2)
gcloud services enable \
  securitycenter.googleapis.com \
  saasservicemgmt.googleapis.com \
  storage.googleapis.com \
  telemetry.googleapis.com \
  texttospeech.googleapis.com

これでセットアップ部分は終了です。次は Gateway セクションに進みます。

4. ゲートウェイ

アクセス制御を適用する前に、Agent Gateway をデプロイし、DRY_RUN モードで認可拡張機能を構成します。これにより、監査目的で評価結果をロギングしながら、アウトバウンド ツール呼び出しを成功させることができます。

ここでは、Agent Gateway はリージョン レジストリを使用して、リージョン Agent Runtime リソースをサポートしています。

ゲートウェイを作成

# create agent gateway config file (regional registry)
cat > cfg/${AGW_NAME}.yaml << EOF
name: ${AGW_NAME}
protocols:
  - MCP
googleManaged:
  governedAccessPath: AGENT_TO_ANYWHERE
registries:
  - "//agentregistry.googleapis.com/projects/${PROJ_ID}/locations/${REGION}"
EOF
# import agent gateway config file (create gateway)
gcloud network-services agent-gateways import ${AGW_NAME} \
  --source="cfg/${AGW_NAME}.yaml" \
  --location=${REGION}
# show agent gateway details (verify deployment state)
gcloud network-services agent-gateways describe ${AGW_NAME} \
  --location=${REGION}

これでゲートウェイに関する説明は終わりです。次は認可セクションに進みます。

5. 認可

Identity-Aware Proxy(IAP)のエージェント ゲートウェイ認可拡張機能は、すべてのエージェント プラットフォーム通信の認可決定を委任するために使用されるサービス拡張機能の一種です。

  1. Agent Gateway フロー: エージェントが外部エンドポイントまたは MCP サーバーを呼び出そうとすると、リクエストは Agent Gateway に転送されます。ゲートウェイは、アクセスをローカルで評価する代わりに、認可拡張機能を使用して IAP 評価サービスにコールアウトを送信します。IAP は、エージェント レジストリ内のターゲット リソースの IAM ポリシーに対して、エージェント(SPIFFE ベース)の ID を評価します。IAP は ALLOW または DENY の決定をゲートウェイに返します。ゲートウェイは、トラフィックを転送するか、HTTP 403 Forbidden ステータス コードでブロックします。
  2. 適用モード: DRY_RUN モードでは、IAP はリクエストを評価し、トラフィックをブロックせずに Cloud Logging に決定を記録します。ENFORCE モードでは、未承認のエージェントからのリクエストや、登録されていないターゲットへのリクエストは直ちにブロックされます。
  3. バインディング レイヤ: サービス拡張機能は、REQUEST_AUTHZ プロファイルで構成された認可ポリシーを使用して Agent Gateway に接続されます。

認可拡張機能

認可拡張機能を作成する

# create authz extension config file (dry run mode)
cat > cfg/${AGW_NAME}-svc-ext-authz-iap-dryrun.yaml << EOF
name: ${AGW_NAME}-svc-ext-authz-iap-dryrun
service: iap.googleapis.com
failOpen: true
timeout: 1s
metadata:
  iamEnforcementMode: "DRY_RUN"
  iapPolicyVersion: "V1"
EOF
# import authz extension file (create extension)
gcloud service-extensions authz-extensions import ${AGW_NAME}-svc-ext-authz-iap-dryrun \
  --source=cfg/${AGW_NAME}-svc-ext-authz-iap-dryrun.yaml \
  --location=${REGION}
# show authz extension details (verify extension state)
gcloud service-extensions authz-extensions describe ${AGW_NAME}-svc-ext-authz-iap-dryrun \
  --location=${REGION}

認可ポリシー

認可ポリシーは、セキュリティ プロバイダ(IAP)をターゲット Gateway リソースにバインドし、インターセプト プロファイル(REQUEST_AUTHZ)を指定します。

認可ポリシーを作成する

# create authz policy config file (attach dry-run authz extension)
cat > cfg/${AGW_NAME}-authz-policy-profile-iap.yaml << EOF
name: ${AGW_NAME}-authz-policy-profile-iap
target:
  resources:
    - "projects/${PROJ_ID}/locations/${REGION}/agentGateways/${AGW_NAME}"
policyProfile: REQUEST_AUTHZ
action: CUSTOM
customProvider:
  authzExtension:
    resources:
      - "projects/${PROJ_ID}/locations/${REGION}/authzExtensions/${AGW_NAME}-svc-ext-authz-iap-dryrun"
EOF
# import authz policy config file (enable authz policy)
gcloud beta network-security authz-policies import ${AGW_NAME}-authz-policy-profile-iap \
  --source=cfg/${AGW_NAME}-authz-policy-profile-iap.yaml \
  --location=${REGION}
# show authz policy details (verify dry run mode)
gcloud beta network-security authz-policies describe ${AGW_NAME}-authz-policy-profile-iap \
  --location=${REGION}

これで認可に関する説明は終わりです。次は Codebase セクションに進みます。

6. コードベース

この Codelab で使用するエージェント コードとエンドポイント登録スクリプトは、リモートの Google Cloud GitHub リポジトリで管理されています。次の手順では、リポジトリをローカルに複製し、必要なファイルを現在の作業ディレクトリ構造にコピーしてから、一時ファイルをクリーンアップします。

Agent Runtime がパッケージ化されたエージェント アプリケーション コードとその依存関係アーティファクトをアップロード、ビルド、デプロイするために、ストレージ ステージング バケットが作成されます。

リモート アーティファクトを取得する

# clone remote repository to temp local dir
git clone https://github.com/GoogleCloudPlatform/cloud-networking-solutions.git ./temp_agw_cuj_arun_egress_emcp
# copy agent runtime and endpoint definitions to working project dir
cp -r temp_agw_cuj_arun_egress_emcp/codelabs/agw-cuj-arun-egress-emcp/agent-datacommons ./agent-datacommons
cp -r temp_agw_cuj_arun_egress_emcp/codelabs/agw-cuj-arun-egress-emcp/endpoints ./endpoints
# remove temporary directory
rm -rf temp_agw_cuj_arun_egress_emcp

ステージング バケットを作成する

# create storage bucket for agent deployment artifacts
gcloud storage buckets create gs://${STAGING_BUCKET} --location=${REGION}
# verify staging bucket url
gcloud storage buckets list --format="value(storage_url)"

これでコードベースの説明は終わりです。次は Registry セクションに進みます。

7. レジストリ

Agent Registry は、AI エコシステム内のすべてのエージェント、MCP サーバー、エンドポイント(API)の一元的なインベントリです。また、AI アプリケーションで使用するために登録された他のツールやサービスを一覧表示、検索、検出するために使用できるカタログでもあります。Agent Gateway の下り(内向き)モード(agent-to-anywhere)は、レジストリのデータモデルをガバナンス フレームワークとして使用し、下り(内向き)アクセス制御を適用します。プリンシパル呼び出しエージェントの IAM ロール付与は、レジストリ リソースにバインドされたポリシーに対してチェックされます。

環境をブートストラップし、さまざまな Google API とサービスを使用してエージェントをサポートするために、スクリプトを使用して、endpoints/googleapis.txt のホスト名とロケーションを使用して共通の API エンドポイントのセットをすばやく登録します。

エンドポイントの登録

# run python script to register google api endpoints
python3 endpoints/register_endpoints.py \
  --multi-region=${MREGION} \
  --region=${REGION} \
  --mtls-endpoints=include

エンドポイントを確認する

# list registry regional endpoints (verify registration)
gcloud agent-registry endpoints list --location=${REGION} \
  --format="table(displayName, name.basename():label=ENDPOINT_ID, interfaces[0].url:label=URL)"

これでレジストリに関する説明は終了です。次は Data Commons セクションに進みます。

8. データコモンズ

データコモンズは、公開データセットを整理し、誰でも利用できるようにする Google の取り組みです。これは無料のサービスであり、アカウントを作成した後、API キーを使用してアクセスできます。

API キーを作成

アカウントを作成したら、次の手順で API キーを取得します。

  • Data Commons API Portal にログインします。
  • 右上にある [My Apps] ボタンをクリックします。
  • 右上にあるユーザー名の下の [+ NEW APP] ボタンをクリックします。
  • アプリに名前を付けます(例: 「Codelab Agent MCP」)。
  • Data Commons API の [有効にする] ボタンをクリックします。 api.datacommons.org
  • 右下の [保存] ボタンをクリックします。

これにより、API キーとシークレットが作成されます。キー値の横にあるコピーアイコンをクリックして、[API キーをコピー] します。値をターミナル コマンドに貼り付けて、DC_API_KEY 環境変数を設定します。

# set api key env var
 export DC_API_KEY="YOUR_API_KEY_HERE"

MCP サーバーを作成する toolspec

MCP サーバーを手動で登録する場合は、登録時にツール仕様ファイルを含める必要があります。toolspec.json ファイルをアップロードすると、エンドポイントで使用可能なすべてのツールが一覧表示され、他のユーザーがそれらを見つけられるようになります。

agent-datacommons/ コードベースに含まれる test_mcp.py スクリプトは、ターゲット MCP サーバー(SSE または HTTP 経由)に接続して toolspec.json ファイルを生成し、list_tools() を呼び出してサーバーが公開する利用可能なツールをすべて取得します。

# generate toolspec for registry ingestion
uv --directory agent-datacommons run python3 test_mcp.py --toolspec=include --token="${DC_API_KEY}"

生成された toolspec 出力を確認すると、下り(外向き)ポリシーの評価と適用に Agent Gateway が使用できる MCP 属性が表示されます。

# show toolspec mcp attributes
jq '.tools[] | {name, isReadOnly, isDestructive, isIdempotent, isOpenWorld}' agent-datacommons/toolspec.json

MCP サーバーを登録する

# register mcp server
gcloud agent-registry services create ${MCP_RESOURCE_NAME} \
  --location=${REGION} \
  --display-name="${MCP_DISPLAY_NAME}" \
  --description="mcp server for data commons" \
  --mcp-server-spec-type=tool-spec \
  --mcp-server-spec-content=agent-datacommons/toolspec.json \
  --interfaces=url=${MCP_URL},protocolBinding=JSONRPC
# list registry regional mcp servers
gcloud agent-registry mcp-servers list --location=${REGION} --format="table(displayName, interfaces.url)"
# show mcp server registry details
gcloud agent-registry services describe ${MCP_RESOURCE_NAME} --location=${REGION}
# fetch mcp server registry id
export MCP_REGISTRY_ID=$(gcloud agent-registry services describe ${MCP_RESOURCE_NAME} \
  --location=${REGION} \
  --format="value(registryResource.basename())")
echo ${MCP_REGISTRY_ID}

これで Data Commons の説明は終わりです。次はランタイム セクションに進みます。

9. ランタイム

Agent Runtime にデプロイされた agent-datacommons ADK エージェントは、Agent Platform と統合するために、デプロイ スクリプトで次の設定で構成されます。

  • "identity_type": types.IdentityType.AGENT_IDENTITY: エージェントに一意の SPIFFE ベースのプリンシパル ID をプロビジョニングします。
  • "agent_gateway_config": { "agent_to_anywhere_config": {"agent_gateway": } }: すべてのアウトバウンド エージェント開始トラフィックを Agent Gateway に転送して、ポリシーの評価と適用を行う

エージェントをデプロイする

# deploy agent runtime workload
uv --directory agent-datacommons run python3 deploy_agent.py \
  --project=${PROJ_ID} \
  --region=${REGION} \
  --src-dir=./agent \
  --staging-bucket=${STAGING_BUCKET} \
  --display-name="${RE_AGENT_NAME}" \
  --description="agent for data commons stats" \
  --enable-telemetry \
  --enable-agent-identity \
  --agent-gateway-egress=${AGW_URI} \
  --env-var="DC_API_KEY=${DC_API_KEY}"

デプロイのバイタルを取得する

# fetch agent runtime resource (reasoning engine) id
export RE_ENGINE_ID=$(curl -s -X GET \
  "https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJ_ID}/locations/${REGION}/reasoningEngines" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" | \
  jq -r --arg name "${RE_AGENT_NAME}" '.reasoningEngines[] | select(.displayName==$name) | .name | split("/") | last')
echo ${RE_ENGINE_ID}
# fetch agent runtime (reasoning engine) agent identity
export RE_AGENT_IDENTITY=$(gcloud agent-registry agents list \
  --location=${REGION} --filter="displayName=${RE_AGENT_NAME}" \
  --format="value(attributes.'agentregistry.googleapis.com/system/RuntimeIdentity'.principal)")
echo ${RE_AGENT_IDENTITY}
# fetch agent registry uid for agent
export RE_AGENT_REGISTRY_ID=$(gcloud agent-registry agents list \
  --location=${REGION} \
  --filter="displayName=${RE_AGENT_NAME}" \
  --format="value(uid)")
echo ${RE_AGENT_REGISTRY_ID}

レジストリ エントリを確認する

# show agent resource registry details
gcloud agent-registry agents describe ${RE_AGENT_REGISTRY_ID} --location=${REGION}

10. ポリシー

エージェント ガバナンス承認ポリシーにより、AI エージェントからのトラフィックがエージェント ゲートウェイを通過して宛先(SaaS アプリケーションのサードパーティ MCP サーバー エンドポイントなど)に到達することが許可されます。トラフィックが宛先に到達すると、通常のサービスレベルまたはアプリケーション レベルの権限によってデータアクセスが承認されます。

Agent Gateway の下り(外向き)の IAM ロール付与により、エージェント プリンシパル ID が Agent Gateway を介して登録済み宛先リソースにアクセスできるアクセス ポリシーが有効になります。ポリシーは Agent Gateway レベルで適用され、Identity-Aware Proxy(IAP)IAM ポリシーを使用して検証されます。

Agent Gateway の下り(外向き)用にエージェントの IAM ロールを付与する

Agent Gateway は、着信リクエストをチェックして、呼び出し元エージェントの ID がターゲット リソースに対する iap.webServiceVersions.egressViaIAP 権限(ロール roles/iap.egressor によって付与)を持っていることを検証します。

選択した宛先リソースでエージェント ID または Agent Runtime プリンシパル セットroles/iap.egressor を付与すると、この下り(外向き)トラフィックが許可されます。この Codelab では、ロールはプリンシパル agent に適用され、特定の Agent Runtime エージェント ID に権限が付与されます。

IAM ポリシーは、エージェント レジストリのデータモデルで定義されている宛先リソースにバインドされます。iap_web/agentRegistry リソースは、IAM 階層の「レジストリ全体」レベルを表します。ここで、agentRegistryagentsmcpServersendpoints の個々の子リソースの親として機能します。この Codelab では、IAM ポリシーは mcpServer レベルと endpoint レベルにバインドされ、特定のサブ リソースに権限が適用されます。

条件付き MCP フィルタリングについて

Data Commons MCP サーバーには 2 つのツールがあります。

  • search_indicators: 利用可能なデータの検出、変数の検索、データ カバレッジの把握に関するクエリ
  • get_observations: 特定のデータポイントまたは時系列を取得するクエリ

MCP サーバーで条件付きガバナンス ポリシーを構成する際に注意すべき標準の MCP オペレーションがいくつかあります。MCP クライアントが search_indicators または get_observationstools/call を行う前に、まずプロトコル ハンドシェイクと検出リクエストを送信する必要があります。

  • initialize
  • notifications/initialized
  • tools/list

条件付きポリシー フィルタリングを説明するために、ポリシーは次の条件で構成されます。

表。MCP リクエストのポリシー評価

リクエスト / メソッド

mcp.toolName の値

CEL の評価

結果

initialize

""

"" in ['search_indicators', '']

✅ 許可(200)

tools/list

""

"" in ['search_indicators', '']

✅ 許可(200)

search_indicators

"search_indicators"

"search_indicators" in [...]

✅ 許可(200)

get_observations

"get_observations"

"get_observations" in [...]

❌ DENIED(403)

プロトコルのハンドシェイクと search_indicators ツール呼び出しを許可するには、条件付きポリシー ルールに "search_indicators" または ""(空の文字列)の許可が含まれます。

レジストリ IAP MCP サーバーの IAM ポリシーを構成する

# show iap iam policy for mcp server
gcloud beta iap web get-iam-policy \
  --region=${REGION} \
  --resource-type=agent-registry \
  --mcp-server=${MCP_REGISTRY_ID}

注: まだポリシーが定義されていないため、etag: はデフォルトの ACAB を返す必要があります。

# fetch active etag on policy for mcp server
export IAP_ETAG=$(gcloud beta iap web get-iam-policy \
  --resource-type=agent-registry --region=${REGION} \
  --mcp-server=${MCP_REGISTRY_ID} --format="value(etag)")
echo ${IAP_ETAG}
# create policy config file
cat > cfg/iap-policy-dc-agent-to-dc-mcp-tool-1.json << EOF
{
  "bindings": [
    {
      "role": "roles/iap.egressor",
      "members": [
        "${RE_AGENT_IDENTITY}"
      ],
      "condition": {
        "title": "allow ${RE_AGENT_NAME} to use search_indicators tool for ${MCP_DISPLAY_NAME}",
        "expression": "api.getAttribute('iap.googleapis.com/mcp.toolName', '') in ['search_indicators', '']"
      }
    }
  ],
  "etag": "${IAP_ETAG}",
  "version": 3
}
EOF
# import policy file (bind iam policy)
gcloud beta iap web set-iam-policy cfg/iap-policy-dc-agent-to-dc-mcp-tool-1.json \
  --resource-type=agent-registry \
  --mcp-server=${MCP_REGISTRY_ID} \
  --region=${REGION}
# verify iap iam policy for mcp server
gcloud beta iap web get-iam-policy \
  --region=${REGION} \
  --resource-type=agent-registry \
  --mcp-server=${MCP_REGISTRY_ID}

ポリシーの説明は以上です。次は監査セクションに進みます。

11. 監査

Agent Gateway 認可拡張機能が DRY_RUN モードで動作しています。アウトバウンド リクエストは監視され、ログに記録されますが、ブロックされません。

エージェントのクエリをテストする

ブラウザ ウィンドウで Google Cloud コンソール UI を開き、次の場所に移動します。

  • Agent Platform → Agents → Deployments → agent-datacommons
  • [プレイグラウンド] タブを選択します。

または、このターミナル コマンドをエコーして、リンクをクリックしてエージェント プレイグラウンドに移動します。

# playground
echo "https://console.cloud.google.com/agent-platform/runtimes/locations/${REGION}/agent-engines/${RE_ENGINE_ID}/playground?project=${PROJ_ID}"

テストクエリを送信します。

  • What data do you have on water quality in Zimbabwe?
  • Compare the life expectancy, economic inequality, and GDP growth for BRICS nations

クエリが有効なレスポンスを返すことを確認します。

監査ログを分析する

ログを表示し、ドライラン ポリシーの評価を検査します。

# list unique urls with http status and iap authorization result
gcloud logging read \
  "resource.type=\"networkservices.googleapis.com/Gateway\" \
  AND httpRequest.requestUrl:*" \
  --project=${PROJ_ID} \
  --limit=200 \
  --format="value(httpRequest.status, jsonPayload.authzPolicyInfo.result, httpRequest.requestUrl)" | sort -u
200     ALLOWED https://api.datacommons.org/mcp
200     ALLOWED https://cloudresourcemanager.googleapis.com:443/google.cloud.resourcemanager.v3.Projects/GetProject
200     ALLOWED https://telemetry.googleapis.com/v1/traces
200     ALLOWED https://${REGION}-aiplatform.googleapis.com/v1beta1/projects/${PROJ_ID}/locations/${REGION}/publishers/google/models/gemini-2.5-flash:generateContent
200     ALLOWED https://${REGION}-aiplatform.googleapis.com/v1beta1/projects/${PROJ_ID}/locations/${REGION}/reasoningEngines/${RE_ENGINE_ID}/sessions/${RE_SESSION_ID}
200     ALLOWED https://${REGION}-aiplatform.googleapis.com/v1beta1/projects/${PROJ_ID}/locations/${REGION}/reasoningEngines/${RE_ENGINE_ID}/sessions/${RE_SESSION_ID}:appendEvent
200     ALLOWED https://${REGION}-aiplatform.googleapis.com/v1beta1/projects/${PROJ_ID}/locations/${REGION}/reasoningEngines/${RE_ENGINE_ID}/sessions/${RE_SESSION_ID}/events
202     ALLOWED https://api.datacommons.org/mcp

レジストリの IAP エンドポイントの IAM ポリシーを更新する

テレメトリー エンドポイントに対するエージェントの下り(外向き)権限を付与する

# set var for endpoint display name
export ENDPOINT_1_DISPLAY_NAME="telemetry.googleapis.com"
echo ${ENDPOINT_1_DISPLAY_NAME}
# fetch endpoint registry id
export ENDPOINT_1_REGISTRY_ID=$(gcloud agent-registry services list \
  --location=${REGION} \
  --filter="displayName=${ENDPOINT_1_DISPLAY_NAME}" \
  --format="value(registryResource.basename())")
echo ${ENDPOINT_1_REGISTRY_ID}
# create policy config file
cat > cfg/iap-policy-re-agent-to-ep-1.json << EOF
{
  "bindings": [
    {
      "role": "roles/iap.egressor",
      "members": [
        "${RE_AGENT_IDENTITY}"
      ]
    }
  ]
}
EOF
# import policy file (bind iam policy)
gcloud -q beta iap web set-iam-policy cfg/iap-policy-re-agent-to-ep-1.json \
  --resource-type=agent-registry \
  --endpoint=${ENDPOINT_1_REGISTRY_ID} \
  --region=${REGION}
# verify iap iam policy for telemetry endpoint
gcloud beta iap web get-iam-policy \
  --region=${REGION} \
  --resource-type=agent-registry \
  --endpoint=${ENDPOINT_1_REGISTRY_ID}

aiplatform エンドポイントに対するエージェントのアウトバウンド権限を付与する

# set var for endpoint display name
export ENDPOINT_2_DISPLAY_NAME="${REGION}-aiplatform.googleapis.com"
echo ${ENDPOINT_2_DISPLAY_NAME}
# fetch endpoint registry id
export ENDPOINT_2_REGISTRY_ID=$(gcloud agent-registry services list \
  --location=${REGION} \
  --filter="displayName=${ENDPOINT_2_DISPLAY_NAME}" \
  --format="value(registryResource.basename())")
echo ${ENDPOINT_2_REGISTRY_ID}
# create policy config file
cat > cfg/iap-policy-re-agent-to-ep-2.json << EOF
{
  "bindings": [
    {
      "role": "roles/iap.egressor",
      "members": [
        "${RE_AGENT_IDENTITY}"
      ]
    }
  ]
}
EOF
# import policy file (bind iam policy)
gcloud -q beta iap web set-iam-policy cfg/iap-policy-re-agent-to-ep-2.json \
  --resource-type=agent-registry \
  --endpoint=${ENDPOINT_2_REGISTRY_ID} \
  --region=${REGION}
# verify iap iam policy for aiplatform endpoint
gcloud beta iap web get-iam-policy \
  --region=${REGION} \
  --resource-type=agent-registry \
  --endpoint=${ENDPOINT_2_REGISTRY_ID}

cloudresourcemanager エンドポイントに対するエージェントの下り(外向き)権限を付与する

# set var for endpoint display name
export ENDPOINT_3_DISPLAY_NAME="cloudresourcemanager.googleapis.com"
echo ${ENDPOINT_3_DISPLAY_NAME}
# fetch endpoint registry id
export ENDPOINT_3_REGISTRY_ID=$(gcloud agent-registry services list \
  --location=${REGION} \
  --filter="displayName=${ENDPOINT_3_DISPLAY_NAME}" \
  --format="value(registryResource.basename())")
echo ${ENDPOINT_3_REGISTRY_ID}
# create policy config file
cat > cfg/iap-policy-re-agent-to-ep-3.json << EOF
{
  "bindings": [
    {
      "role": "roles/iap.egressor",
      "members": [
        "${RE_AGENT_IDENTITY}"
      ]
    }
  ]
}
EOF
# import policy file (bind iam policy)
gcloud -q beta iap web set-iam-policy cfg/iap-policy-re-agent-to-ep-3.json \
  --resource-type=agent-registry \
  --endpoint=${ENDPOINT_3_REGISTRY_ID} \
  --region=${REGION}
# verify iap iam policy for cloudresourcemanager endpoint
gcloud beta iap web get-iam-policy \
  --region=${REGION} \
  --resource-type=agent-registry \
  --endpoint=${ENDPOINT_3_REGISTRY_ID}

監査に関する説明は以上です。次は適用セクションに進みます。

12. 適用

エージェントは DRY_RUN モードでゲートウェイを介してリクエストを正常に実行できました。認可ポリシーを更新して、Agent Gateway IAP 認可拡張機能を ENFORCE モードに移行します。

認可拡張機能を更新する

# create authz extension config file (enforced mode)
cat > cfg/${AGW_NAME}-svc-ext-authz-iap-enforced.yaml << EOF
name: ${AGW_NAME}-svc-ext-authz-iap-enforced
service: iap.googleapis.com
failOpen: false
timeout: 1s
metadata:
  iapPolicyVersion: "V1"
EOF
# import authz extension file (create extension)
gcloud service-extensions authz-extensions import ${AGW_NAME}-svc-ext-authz-iap-enforced \
  --source=cfg/${AGW_NAME}-svc-ext-authz-iap-enforced.yaml \
  --location=${REGION}
# list authz extensions (imported configs)
gcloud service-extensions authz-extensions list --location=${REGION}

認可ポリシーを更新する

# re-write authz policy config file (pointing to enforced authz extension)
cat > cfg/${AGW_NAME}-authz-policy-profile-iap.yaml << EOF
name: ${AGW_NAME}-authz-policy-profile-iap
target:
  resources:
    - "projects/${PROJ_ID}/locations/${REGION}/agentGateways/${AGW_NAME}"
policyProfile: REQUEST_AUTHZ
action: CUSTOM
customProvider:
  authzExtension:
    resources:
      - "projects/${PROJ_ID}/locations/${REGION}/authzExtensions/${AGW_NAME}-svc-ext-authz-iap-enforced"
EOF
# import authz policy config file (enable new authz policy)
gcloud beta network-security authz-policies import ${AGW_NAME}-authz-policy-profile-iap \
  --source=cfg/${AGW_NAME}-authz-policy-profile-iap.yaml \
  --location=${REGION}
# show authz policy details (verify enforced mode)
gcloud beta network-security authz-policies describe ${AGW_NAME}-authz-policy-profile-iap \
  --location=${REGION}

条件付き許可を確認する

コンソール UI でエージェントの [Playground] に戻ります。

追加のテストクエリを送信します(許可されているsearch_indicators ツールを呼び出そうとします)。

  • What data topics do you have for Peru?

Gemini 基盤モデル(${REGION}-aiplatform.googleapis.com/...)、テレメトリー API(telemetry.googleapis.com/...)、Data Commons MCP サーバー エンドポイント(api.datacommons.org/mcp)へのエージェント リクエストが HTTP 200 OK ステータス コードで渡されていることを確認します。

# show gateway logs for http requests
gcloud logging read \
  "resource.type=\"networkservices.googleapis.com/Gateway\" \
  AND httpRequest.requestUrl:*" \
  --project=${PROJ_ID} \
  --limit=10 \
  --format="table(
    timestamp.date(tz=LOCAL):label=TIMESTAMP,
    httpRequest.requestMethod:label=METHOD,
    httpRequest.status:label=STATUS,
    jsonPayload.authzPolicyInfo.result:label=IAP_AUTHZ,
    jsonPayload.agentGatewayInfo.mcpInfo.method:label=MCP_METHOD,
    httpRequest.requestUrl:label=URL)"

ブロックされているリクエストがないことを確認します。ゲートウェイ監査ログで、HTTP 403 Forbidden ステータス コードで拒否された下り(外向き)試行を探します。

# show gateway logs for authz denies
gcloud logging read \
  "resource.type=\"networkservices.googleapis.com/Gateway\" \
  AND (jsonPayload.authzPolicyInfo.result=\"DENIED\" OR httpRequest.status=403)" \
  --project=${PROJ_ID} \
  --limit=10 \
  --format="table(
    timestamp.date(tz=LOCAL):label=TIMESTAMP,
    httpRequest.requestMethod:label=METHOD,
    httpRequest.status:label=STATUS,
    jsonPayload.enforcedGatewaySecurityPolicy.serverNameIndication:label=SNI,
    jsonPayload.authzPolicyInfo.result:label=AUTHZ_RESULT,
    jsonPayload.authzPolicyInfo.policies[0].name.basename():label=DENYING_POLICY
  )"
# show gateway logs for mcp requests with method and tool name
gcloud logging read \
  "resource.type=\"networkservices.googleapis.com/Gateway\" \
  AND jsonPayload.agentGatewayInfo.mcpInfo.method:*" \
  --project=${PROJ_ID} \
  --limit=10 \
  --format="table(
    timestamp.date(tz=LOCAL):label=TIMESTAMP,
    httpRequest.status:label=STATUS,
    jsonPayload.authzPolicyInfo.result:label=IAP_AUTHZ,
    jsonPayload.agentGatewayInfo.mcpInfo.method:label=MCP_METHOD,
    jsonPayload.agentGatewayInfo.mcpInfo.parameter:label=TOOL_NAME,
    httpRequest.requestUrl:label=URL
  )"

条件付き拒否を検証する

追加のテストクエリを送信します(拒否get_observations ツールを呼び出そうとします)。

  • What are the diabetes levels in Peru compared to Slovakia?

エージェントはまず search_indicators を確認してから get_observations を使用しようとしますが、失敗し、エージェントの回答は未完了のままになります。

# show gateway logs for mcp requests with method and tool name
gcloud logging read \
  "resource.type=\"networkservices.googleapis.com/Gateway\" \
  AND jsonPayload.agentGatewayInfo.mcpInfo.method:*" \
  --project=${PROJ_ID} \
  --limit=10 \
  --format="table(
    timestamp.date(tz=LOCAL):label=TIMESTAMP,
    httpRequest.status:label=STATUS,
    jsonPayload.authzPolicyInfo.result:label=IAP_AUTHZ,
    jsonPayload.agentGatewayInfo.mcpInfo.method:label=MCP_METHOD,
    jsonPayload.agentGatewayInfo.mcpInfo.parameter:label=TOOL_NAME,
    httpRequest.requestUrl:label=URL
  )"
TIMESTAMP            STATUS  IAP_AUTHZ  MCP_METHOD                 TOOL_NAME          URL
YYYY-MM-DDTHH:MM:SS  403     DENIED     tools/call                 get_observations   https://api.datacommons.org/mcp
YYYY-MM-DDTHH:MM:SS          ALLOWED    tools/call                 get_observations   https://api.datacommons.org/mcp
YYYY-MM-DDTHH:MM:SS  403     DENIED     tools/call                 get_observations   https://api.datacommons.org/mcp
YYYY-MM-DDTHH:MM:SS  200     ALLOWED    tools/call                 search_indicators  https://api.datacommons.org/mcp
YYYY-MM-DDTHH:MM:SS  200     ALLOWED    tools/list                                    https://api.datacommons.org/mcp
YYYY-MM-DDTHH:MM:SS  202     ALLOWED    notifications/initialized                     https://api.datacommons.org/mcp

これで、ガバナンス ポリシーが想定どおりに機能していることを確認できます。

空白のステータスと ALLOWED を示す 2 行目は、403 応答の送信後にソケットを閉じたときに Agent Gateway によって出力されるセカンダリ接続の切断ログイベントです(接続クローズ イベントには応答ステータス コードがないため、httpRequest.status は空白です)。

これで適用に関する説明は終わりです。次はクリーンアップ セクションに進みます。

13. クリーンアップ

# delete agent
curl -s -X DELETE "https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJ_ID}/locations/${REGION}/reasoningEngines/${RE_ENGINE_ID}?force=true" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)"

# next
# delete storage bucket
gcloud -q storage rm --recursive gs://${STAGING_BUCKET}

# next
# clear policy on mcp server
export IAP_ETAG=$(gcloud beta iap web get-iam-policy --resource-type=agent-registry --mcp-server=${MCP_REGISTRY_ID} --region=${REGION} --format="value(etag)")
cat > cfg/iap-policy-empty.json << EOF
{
  "bindings": [],
  "etag": "${IAP_ETAG}"
}
EOF

gcloud -q beta iap web set-iam-policy cfg/iap-policy-empty.json \
  --resource-type=agent-registry \
  --mcp-server=${MCP_REGISTRY_ID} \
  --region=${REGION}

# next
# clear policy on endpoint 1
export IAP_ETAG=$(gcloud beta iap web get-iam-policy --resource-type=agent-registry --endpoint=${ENDPOINT_1_REGISTRY_ID} --region=${REGION} --format="value(etag)")
cat > cfg/iap-policy-empty.json << EOF
{
  "bindings": [],
  "etag": "${IAP_ETAG}"
}
EOF

gcloud -q beta iap web set-iam-policy cfg/iap-policy-empty.json \
  --resource-type=agent-registry \
  --endpoint=${ENDPOINT_1_REGISTRY_ID} \
  --region=${REGION}

# next
# clear policy on endpoint 2
export IAP_ETAG=$(gcloud beta iap web get-iam-policy --resource-type=agent-registry --endpoint=${ENDPOINT_2_REGISTRY_ID} --region=${REGION} --format="value(etag)")
cat > cfg/iap-policy-empty.json << EOF
{
  "bindings": [],
  "etag": "${IAP_ETAG}"
}
EOF

gcloud -q beta iap web set-iam-policy cfg/iap-policy-empty.json \
  --resource-type=agent-registry \
  --endpoint=${ENDPOINT_2_REGISTRY_ID} \
  --region=${REGION}

# next
# clear policy on endpoint 3
export IAP_ETAG=$(gcloud beta iap web get-iam-policy --resource-type=agent-registry --endpoint=${ENDPOINT_3_REGISTRY_ID} --region=${REGION} --format="value(etag)")
cat > cfg/iap-policy-empty.json << EOF
{
  "bindings": [],
  "etag": "${IAP_ETAG}"
}
EOF

gcloud -q beta iap web set-iam-policy cfg/iap-policy-empty.json \
  --resource-type=agent-registry \
  --endpoint=${ENDPOINT_3_REGISTRY_ID} \
  --region=${REGION}

# next
# remove manual registry entry
gcloud -q agent-registry services delete ${MCP_RESOURCE_NAME} --location=${REGION}
# delete gateway resources
gcloud -q beta network-security authz-policies delete ${AGW_NAME}-authz-policy-profile-iap --location=${REGION}

gcloud -q beta service-extensions authz-extensions delete ${AGW_NAME}-svc-ext-authz-iap-dryrun --location=${REGION}

gcloud -q beta service-extensions authz-extensions delete ${AGW_NAME}-svc-ext-authz-iap-enforced --location=${REGION}

gcloud -q network-services agent-gateways delete ${AGW_NAME} --location=${REGION}

# next
# clean up local working directories and generated configs
rm -rf cfg agent-datacommons endpoints

# end

これでクリーンアップは完了です。次はまとめに進みます。

14. おわりに

おめでとうございます!Agent Gateway を使用してツールにアクセスするエージェントのアウトバウンド通信が正常にデプロイされ、管理されました。

cosmopup

Cosmopup は Codelab が最高だと思っています。

次のステップ

ご意見、ご質問、修正点などがありましたら、こちらのフィードバック フォームからお気軽にお寄せください。

ありがとうございました