從 Agent Runtime 輸出至外部 MCP 的代理閘道

1. 簡介

本程式碼實驗室將探討 Agent Gateway 的輸出管理功能,適用於存取 Google Cloud 外部代管外部 Model Context Protocol (MCP) 伺服器的 AI 代理。

從獨立聊天機器人到具備多代理工作流程的自治系統,AI 應用程式都能動態叫用外部工具。為代理程式提供受控存取權,讓代理程式查詢資料庫、擷取網頁內容及執行動作,是確保代理程式安全且有效率的關鍵。不過,在企業環境中,確保代理程式工具的執行安全是一大挑戰。如果代理程式具有直接網路存取權,提示詞注入攻擊或模型幻覺可能會導致代理程式洩露私密資料或執行破壞性指令。

如要大規模管理自主代理,Agent Gateway 會提供集中式零信任強制執行點,直接整合至 Agent Platform 架構。Agent Gateway 不會依賴各個應用程式或代理程式碼專屬的自訂實作項目,而是在平台層級強制執行網路路由、代理程式管理和執行階段安全措施。

當 Agent Gateway 以輸出 (代理至任何位置) 模式運作時,會代理設定為使用閘道的所有代理輸出要求。系統會使用專屬的代理程式身分驗證每個代理程式工作負載要求,並使用 Identity-Aware Proxy (IAP) 政策授權。系統會動態解碼並檢查 MCP 工具呼叫,確保符合政策規定。安全管理員可以集中強制執行精細權限,確保代理只能叫用核准的端點和方法。

建構內容

  • 輸出模式下的 Agent Gateway (agent-to-anywhere)
  • Identity-Aware Proxy (IAP) 授權擴充功能
  • 具有代理身分的 Agent Runtime ADK 代理
  • Agent Registry,內含 Google API 和 MCP 端點
  • 外部 MCP 工具連線至 Data Commons 公開資料集
  • 使用 IAM 存取權控管的授權政策

figure1

圖 1. 程式碼研究室架構

課程內容

  • 如何依結構化設定順序部署 Agent Gateway
  • 如何將授權政策從模擬測試模式轉換為強制執行模式
  • 如何在 Agent Registry 中註冊 Google API 端點和 MCP 伺服器
  • 如何根據 MCP 協定屬性使用條件式授權政策
  • 如何稽核 Agent Gateway 記錄,驗證輸出管理

需求條件

  • 已啟用計費功能的 Google Cloud 雲端專案
  • 佈建網路服務和 Agent Platform 資源的 IAM 權限
  • 已安裝 Google Cloud CLI (gcloudbq 元件) 的 POSIX 相容 Shell (bashzsh)
  • 指令列工具:gitcurljq (JSON 處理器)、Python 3 和 uv (Python 套件管理工具)
  • 免費的 Data Commons API 金鑰,可存取查詢測試資料集

2. 概念

部署順序

本程式碼研究室會依循結構化設定順序,確保代理程式在初始化時能存取必要資源,並在套用強制執行的存取政策前確認連線。

本程式碼研究室使用下列部署順序:

  1. DRY_RUN 模式啟動:確認代理程式要求已成功送達閘道並通過 (僅限稽核模式)。
  2. 註冊所有服務:在代理程式登錄中註冊所有代理程式元件,並確認代理程式工具存取權。
  3. 建立授權政策:建立及套用授權政策,允許代理程式將輸出流量傳送至 MCP 伺服器和端點。
  4. 切換至 ENFORCED 模式:更新授權擴充功能政策,強制執行政策並封鎖未經授權的輸出流量。

figure2

圖 2. 部署順序

輸出路由拓撲

Agent Gateway 輸出 (代理至任何位置) 可做為代理工作負載的集中式零信任輸出代理。當代理程式向外部工具或 API 發出要求時,Agent Gateway 會攔截外送要求,並根據控管政策進行評估,然後再將要求傳送至目的地。在 Google Cloud Agent Platform 架構中,Agent Gateway 提供資料層連線,可連至:

  • 私人網路 (VPC):以企業內部 API、微服務、私人 VPC 中代管的資料庫,以及可透過混合式連線存取的內部部署或跨雲端網路為目標的輸出流量。
  • 外部網路 (網際網路):以第三方網路服務、SaaS API 或公開端點為目標的出站流量。
  • AI 服務和 Agent Platform:以代管的 Google Cloud API、基礎模型、Google MCP 端點 (例如 BigQuery) 和平台控管服務 (Agent Registry 和 IAP 政策) 為目標的輸出流量。

figure3

圖 3. Agent Gateway 輸出轉送拓撲

本程式碼實驗室的重點是從 Agent Runtime 上的自訂代理傳出流量,目標是可透過網際網路存取的外部第三方 MCP 伺服器端點。

檢查 MCP 通訊協定

Agent Gateway 輸出 (agent-to-anywhere) 可剖析 MCP 要求的內容,並根據精細的通訊協定屬性評估存取權政策。代理程式至 MCP 伺服器的輸出政策可以包含條件 (以一般運算語言 (CEL) 表示),系統會在每個要求執行階段強制執行這些條件。

MCP 呼叫通常會使用 JSON-RPC 傳輸通訊協定格式和 HTTP 傳輸。HTTP 主體中的 JSON 酬載包含所叫用 MCP 方法的詳細資料 (例如 tools/call)、目標工具名稱和任何引數。

Agent Gateway 會剖析 JSON 主體,找出要求中指定的工具 ID,藉此擷取 iap.googleapis.com/mcp.toolName 屬性。

通常不會在每個要求主體中傳送 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 伺服器要求的 Agent Gateway 輸出管理屬性:

屬性

MCP 方法 / 位置

說明

mcp.toolName

tools/call (內文)

RPC 酬載中要求使用的目標工具 ID (例如 "delete_instance")

mcp.tool.isReadOnly

Agent Registry (toolspec.json)

指出工具是否為唯讀 (不會修改環境)

mcp.tool.isDestructive

Agent Registry (toolspec.json)

指出呼叫工具是否可能導致無法復原的修改或資料遺失

mcp.tool.isIdempotent

Agent Registry (toolspec.json)

指出使用相同引數重複執行工具是否會產生完全相同的狀態

mcp.tool.isOpenWorld

Agent Registry (toolspec.json)

指出工具是否超出受限的內部系統,觸及不受限的公開網際網路

概念部分到此結束,接下來請前往「設定」部分。

3. 設定

必要的 IAM 角色

如要在本程式碼研究室中建立資源,您必須具備下列角色:

類別

必要 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

存取專案

本程式碼研究室使用單一 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

設定部分到此結束,接下來請前往「閘道」部分。

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) 的 Agent Gateway 授權擴充功能是一種服務擴充功能,用於將所有 Agent Platform 通訊的授權決策委派出去。

  1. Agent Gateway 委派流程:當代理嘗試叫用外部端點或 MCP 伺服器時,系統會將要求轉送至 Agent Gateway。閘道不會在本地評估存取權,而是使用授權擴充功能,將回呼傳送至 IAP 評估服務。IAP 會根據 Agent Registry 中目標資源的 IAM 政策,評估代理 (以 SPIFFE 為基礎) 身分。IAP 會將 ALLOWDENY 決策傳回閘道,閘道會轉送流量或以 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) 繫結至目標閘道資源,並指定攔截設定檔 (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}

授權部分到此結束,接下來請前往「程式碼集」部分。

6. 程式碼集

本程式碼研究室使用的代理程式碼和端點註冊指令碼,都維護在遠端 Google Cloud GitHub 存放區中。下列步驟會在本機複製存放區、將必要檔案複製到目前的工作目錄結構,然後清除暫存檔案。

系統會為 Agent Runtime 建立儲存空間暫存 bucket,用於上傳、建構及部署封裝的代理程式應用程式程式碼及其依附元件構件。

擷取遠端構件

# 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

建立暫存 bucket

# 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)"

程式碼集部分到此結束,接下來請前往「登錄」部分。

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)"

註冊部分到此結束,接下來請參閱「資料共用」部分。

8. Data Commons

Data Commons 是 Google 的一項計畫,旨在彙整公開資料集,供大眾使用。這項服務免費提供,建立帳戶後即可使用 API 金鑰存取。

建立 API 金鑰

建立帳戶後,請按照下列步驟取得 API 金鑰:

  • 登入 Data Commons API 入口網站
  • 按一下右上角的「我的應用程式」按鈕
  • 按一下使用者名稱右上角的「+ 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 檔案會列出端點提供的所有工具,方便其他使用者探索。

test_mcp.py 指令碼 (包含在 agent-datacommons/ 程式碼庫中) 會連線至目標 MCP 伺服器 (透過 SSE 或 HTTP),並呼叫 list_tools() 來擷取伺服器公開的所有可用工具,藉此產生 toolspec.json 檔案。

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

查看產生的 toolspec 輸出內容,即可瞭解代理閘道可用於評估及強制執行輸出政策的 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 主體身分
  • "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 代理的流量通過 Agent Gateway,並前往目的地 (例如 SaaS 應用程式的第三方 MCP 伺服器端點)。流量抵達目的地後,系統會透過一般服務層級或應用程式層級權限授權資料存取權。

Agent Gateway 輸出內容的 IAM 角色授權可啟用存取政策,允許代理主體身分透過 Agent Gateway 存取已註冊的目的地資源。系統會在 Agent Gateway 層級強制執行政策,並使用 Identity-Aware Proxy (IAP) IAM 政策驗證政策。

授予代理程式 IAM 角色,以供代理程式閘道輸出使用

Agent Gateway 會檢查傳入的要求,驗證呼叫代理身分是否對目標資源具有 iap.webServiceVersions.egressViaIAP 權限 (由 roles/iap.egressor 角色授予)。

在所選目標資源上,將 roles/iap.egressor 授予代理程式身分或 Agent Runtime 主體組合,即可允許這項輸出流量。在本程式碼研究室中,角色會套用至主體「agent」,並授予特定 Agent Runtime 代理身分權限。

IAM 政策會繫結至 Agent Registry 資料模型中定義的目的地資源。iap_web/agentRegistry 資源代表 IAM 階層中的「整個登錄檔」層級。其中 agentRegistryagentsmcpServersendpoints 各別子項資源的父項。在本程式碼研究室中,IAM 政策會繫結至 mcpServerendpoint 層級,將權限套用至特定子資源。

關於條件式 MCP 篩選

Data Commons MCP 伺服器提供兩項工具:

  • search_indicators:用於查詢可用的資料、搜尋變數或瞭解資料涵蓋範圍
  • get_observations:用於查詢,以擷取特定資料點或時間序列

在 MCP 伺服器上設定條件式控管政策時,請注意一些標準 MCP 作業。MCP 用戶端必須先傳送通訊協定交握和探索要求,才能進行 tools/callsearch_indicatorsget_observations

  • 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 控制台使用者介面,然後依序點選:

  • Agent Platform → Agents → Deployments → agent-datacommons
  • 選取「Playground」分頁標籤

或者,您也可以回應這個終端機指令,然後按一下連結,跳到代理程式遊樂場:

# 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 端點的身分與存取權管理政策

授予遙測端點的代理程式輸出權限

# 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
  )"

驗證條件式拒絕

提交額外測試查詢 (嘗試叫用「denied」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,是 Agent Gateway 在傳送 403 回應後關閉通訊端時發出的次要連線終止記錄事件 (因為連線關閉事件沒有回應狀態碼,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 認為程式碼研究室非常棒!

後續步驟

歡迎使用這份意見回饋表單提供任何意見、問題或修正建議

感謝您!