1. 简介
随着企业组织采用生成式 AI,架构正迅速从独立的单体聊天机器人演变为分布式多智能体系统(智能体到智能体 / A2A)。在这些现代拓扑中,高级编排器代理通过将任务委托给独立 Google Cloud 项目中的专业领域工作代理、Model Context Protocol (MCP) 工具服务器和后端企业数据库,来协调复杂的业务工作流。
不过,大规模运行多智能体系统会带来严重的安全、治理和运营挑战:
- 影子代理和工具蔓延:当开发团队在没有集中式目录的情况下在隔离项目中部署代理时,组织会无法了解存在哪些工具和子代理。
- 不受监控的跨项目出站流量:允许代理直接使用未经检查的网络路由会带来数据外泄风险,并绕过安全边界。
- 脆弱的硬编码集成:对下游代理网址和推理引擎 ID 进行硬编码会创建脆弱的依赖项,这些依赖项会在升级或重新部署期间中断。
- 缺少最小权限身份:共享服务账号无法在单个代理实例级别提供加密的不可否认性。
为解决这些挑战,Gemini Enterprise Agent Platform 提供了一个统一的治理和连接控制平面,该平面由四个核心支柱组成:
- 代理网关 (
networkservices.googleapis.com):受管理的区域网络和政策执行代理。在AGENT_TO_ANYWHERE出站流量模式下运行,可拦截出站智能体流量,将授权评估委托给安全扩展程序,并在项目边界之间路由请求。 - Agent Registry (
agentregistry.googleapis.com):单一的企业服务目录。它提供了一个集中式、经过审核的目录,其中包含组织中的所有可用工具、MCP 服务器和对等代理,可实现动态运行时自动发现,而无需硬编码端点。 - 代理身份和 IAP v2 管理 (
iap.googleapis.com和iam.googleapis.com):一种加密身份和访问权限框架。执行代理会收到唯一的经过证明的 SPIFFE 机器 URN (principal://...)。出站流量会根据集中式 IAM Unified Access Policies (UAP / IAP v2) 进行评估,使用丰富的通用表达式语言 (CEL) 目录条件 (destination.agent_registry.*) 验证通用权限iap.googleapis.com/resources.egressViaIAP。 - Agent Runtime(推理引擎):完全托管式无服务器执行平台,适用于基于 Python 的智能体应用,具有与中央网关的原生配置绑定 (
agent_gateway_config)。
Codelab 业务场景:多项目食品和饮料采购
在此 Codelab 中,您将构建并管理一个真实的跨多个项目的购买生态系统,该生态系统涵盖三个不同的 Google Cloud 项目:
- 中央治理项目 (
PROJECT_GOVERNANCE):由中央 IT 和 SecOps 拥有,用于托管 Agent Gateway、Agent Registry 和 Unified Access Policies。 - 消费者编排器项目 (
PROJECT_CONCIERGE):由采购团队所有,用于托管采购礼宾智能体,该智能体可动态发现供应商并路由客户订单。 - Domain Vendor Project (
PROJECT_SELLERS):由外部或部门供应商所有,用于托管 Burger Seller Agent 和 Pizza Seller Agent。
图 1. 多项目集中式治理架构
为什么需要跨项目集中式治理?
在大型企业组织中,产品团队和数据科学团队会在数十个独立的 Google Cloud 项目中构建 AI 智能体。如果让每个团队直接控制工具注册、出站网络路由和安全防护栏,就会导致未经审核的工具蔓延、DLP 政策不一致、VPC 出站流量不受监控,以及审核日志分散。
跨项目集中式治理将政策编写与代理执行分开:
- 中央 IT 和 SecOps 在单个集中式治理项目中制定安全政策、审核工具和监控出站流量。
- 产品和应用团队专注于独立的Agent Runtime 项目中的业务逻辑,直接绑定到中央网关,而无需管理本地 VPC、互连或分散的政策引擎,从而减少运营开销。
图 2. 三层跨项目治理架构和边界
Unified Access Policies 中的双层身份范围界定模型
当代理通过 Agent Gateway 进行通信时,Identity-Aware Proxy (IAP v2) 会根据调用方的代理身份(一种以加密方式证明的、基于 SPIFFE 的身份,会自动向运行时容器颁发)评估访问权限,并对照全局 IAM 访问权限政策:
- 第 1 级:基本 Google Cloud API(通过规则 1 中的
principalSet://实现粗略的授权):项目级出站授权,允许各个 Spoke 项目中的所有代理运行时访问标准 Google API(aiplatform、iamcredentials、telemetry、agentregistry),以进行发现、令牌生成和推理。 - 第 2 层:业务工具和 A2A 服务(通过规则 2 和 3 中的
principal://实现精细的访问权限控制):严格的最小权限访问权限,绑定到各个推理引擎实例,通过通用表达式语言 (CEL) 条件强制执行,这些条件以特定的已注册 Agent Registry 服务 (destination.agent_registry.agent.name) 为目标。
构建内容
PROJECT_GOVERNANCE中的集中式 Agent Gateway (centralized-agw)- 严格强制模式 (
failOpen: false) 下的 IAP v2 授权服务扩展程序和授权政策 - 基础 IAM 统一访问权限政策 (
uap-rules.json) 和项目政策绑定 - 跨项目服务代理 IAM 权限 (
ar_agw_cross_project_sa) - 共享的中央 Google Cloud Storage (GCS) 暂存存储桶
PROJECT_SELLERS中孤立的汉堡和披萨卖家代理PROJECT_CONCIERGE中具有动态 REST 自动发现功能的购买助理代理- 具有跨项目 mTLS 网址的 Central Agent Registry 中的服务注册
- 通过实时验证和 Cloud Logging 审核动态更新 IAP v2 出站政策
图 3. 分步实现顺序
学习内容
- 如何为集中式网关配置跨项目服务代理 IAM 权限
- 如何在多项目环境中通过中央 Agent Gateway 路由 Agent Runtime 出站流量
- 如何使用 Service Extensions (
iapPolicyVersion: "V2") 将 Agent Gateway 授权委托给 Identity-Aware Proxy (IAP v2) - 如何使用通用表达式语言 (CEL) 规则编写和绑定 IAM Unified Access Policies (UAP),以管理已注册的 Agent Registry 目标 (
destination.agent_registry.*) - 如何通过针对 Agent Registry 的运行时自动发现来消除硬编码的代理 ID 和网址
- 如何测试实际的边界零信任封锁 (
HTTP 403 Forbidden) 并验证 Cloud Logging 中的实时政策更新
所需条件
- 3 个启用了结算功能的 Google Cloud 项目:
PROJECT_GOVERNANCE:中央治理、网关、注册表和 IAM 访问权限政策PROJECT_CONCIERGE:购买礼宾编排器代理PROJECT_SELLERS:汉堡和披萨专业销售代理
- 在所有 3 个项目中都具有
roles/owner或管理权限的 IAM 用户或服务账号 - Google Cloud 组织(用于 SPIFFE 信任网域映射)
- Google Cloud Shell 或安装了
gcloudCLI、python(3.11+) 和uv的本地机器
介绍部分到此结束…接下来是设置和环境部分。
2. 设置
虽然此架构涵盖 3 个不同的 Google Cloud 项目,但您可以在设置为 PROJECT_GOVERNANCE 的单个 Cloud Shell 终端中执行 100% 的终端部署命令、代码库下载和暂存操作。每个部署脚本和 gcloud 命令都通过 CLI 标志 (--project) 明确指定了相应目标项目。
首先,访问 Google Cloud 云项目命令行:
- Cloud Shell 位于
shell.cloud.google.com,或者 - 安装了
gcloudCLI 的本地终端
设置项目上下文
# set terminal project context to Central Governance Project
gcloud config set project SET_YOUR_GOVERNANCE_PROJECT_ID_HERE
# login to gcloud cli
gcloud auth login
# login for application default credentials
gcloud auth application-default login
更新 gcloud CLI(推荐)
# update gcloud components
gcloud components update --quiet
设置 shell 环境变量
输入您的项目专用标识符。
# 1. Project Identifiers
export PROJECT_GOVERNANCE="SET_YOUR_GOVERNANCE_PROJECT_ID_HERE"
export PROJECT_CONCIERGE="SET_YOUR_CONCIERGE_PROJECT_ID_HERE"
export PROJECT_SELLERS="SET_YOUR_SELLERS_PROJECT_ID_HERE"
这些 shell 变量将自动派生。
# 2. Regional & Gateway Settings
export REGION="us-central1"
export AGW_NAME="centralized-agw"
export UAP_POLICY_NAME="uap-policy-${AGW_NAME}"
export UAP_BINDING_NAME="uap-binding-${AGW_NAME}"
# 3. Retrieve Project Numbers
export PROJECT_NUMBER_GOVERNANCE=$(gcloud projects describe ${PROJECT_GOVERNANCE} --format="value(projectNumber)")
export PROJECT_NUMBER_CONCIERGE=$(gcloud projects describe ${PROJECT_CONCIERGE} --format="value(projectNumber)")
export PROJECT_NUMBER_SELLERS=$(gcloud projects describe ${PROJECT_SELLERS} --format="value(projectNumber)")
# 4. Obtain Organization ID
export ORG_ID=$(gcloud projects get-ancestors ${PROJECT_GOVERNANCE} --format="value(id, type)" | grep organization | awk '{print $1}')
# 5. Set Application Default Credentials (ADC) Quota Project
gcloud auth application-default set-quota-project ${PROJECT_GOVERNANCE}
echo "Governance Project: ${PROJECT_GOVERNANCE} (${PROJECT_NUMBER_GOVERNANCE})"
echo "Concierge Project: ${PROJECT_CONCIERGE} (${PROJECT_NUMBER_CONCIERGE})"
echo "Sellers Project: ${PROJECT_SELLERS} (${PROJECT_NUMBER_SELLERS})"
echo "Organization ID: ${ORG_ID}"
echo "UAP Policy Name: ${UAP_POLICY_NAME}"
echo "UAP Binding Name: ${UAP_BINDING_NAME}"
为配置文件创建本地目录
# create config folder
mkdir -p cfg
为 Unified Access Policies 分配 Access Policy Admin 角色
# grant Access Policy Admin and Project IAM Admin to current user in Governance Project
for ROLE in "roles/iam.accessPolicyAdmin" "roles/resourcemanager.projectIamAdmin"; do
gcloud projects add-iam-policy-binding ${PROJECT_GOVERNANCE} \
--member="user:$(gcloud config get-value account)" \
--role="${ROLE}" \
--condition=None
done
为 IAP v2 启用 Cloud Audit 数据访问日志
默认情况下,Google Cloud 会停用数据访问审核日志,以避免产生意外的存储费用。由于 IAP v2 会将授权决策(granted=true 和 granted=false)作为数据访问审核日志发出,因此请在 PROJECT_GOVERNANCE 中为 iap.googleapis.com 启用 ADMIN_READ、DATA_READ 和 DATA_WRITE 日志记录:
# 1. export current IAM policy for PROJECT_GOVERNANCE
gcloud projects get-iam-policy ${PROJECT_GOVERNANCE} \
--format=json > cfg/gov_iam_policy.json
# 2. append auditConfigs for iap.googleapis.com
python3 -c "
import json
with open('cfg/gov_iam_policy.json') as f:
policy = json.load(f)
audit_configs = [c for c in policy.get('auditConfigs', []) if c.get('service') != 'iap.googleapis.com']
audit_configs.append({
'service': 'iap.googleapis.com',
'auditLogConfigs': [
{'logType': 'ADMIN_READ'},
{'logType': 'DATA_READ'},
{'logType': 'DATA_WRITE'}
]
})
policy['auditConfigs'] = audit_configs
with open('cfg/gov_iam_policy.json', 'w') as f:
json.dump(policy, f, indent=2)
"
# 3. apply updated policy
gcloud projects set-iam-policy ${PROJECT_GOVERNANCE} cfg/gov_iam_policy.json
# 4. verify auditConfigs applied
gcloud projects get-iam-policy ${PROJECT_GOVERNANCE} --format="yaml(auditConfigs)"
启用必需的 Google Cloud API
# enable google apis (agent platform & security bundle, part 1)
for PROJ in ${PROJECT_GOVERNANCE} ${PROJECT_CONCIERGE} ${PROJECT_SELLERS}; do
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 \
agentidentity.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 \
--project=${PROJ}
done
# enable google apis (agent platform bundle, part 2)
for PROJ in ${PROJECT_GOVERNANCE} ${PROJECT_CONCIERGE} ${PROJECT_SELLERS}; do
gcloud services enable \
securitycenter.googleapis.com \
saasservicemgmt.googleapis.com \
storage.googleapis.com \
telemetry.googleapis.com \
texttospeech.googleapis.com \
--project=${PROJ}
done
# enable google apis (foundational & agent runtime build bundle, part 3)
for PROJ in ${PROJECT_GOVERNANCE} ${PROJECT_CONCIERGE} ${PROJECT_SELLERS}; do
gcloud services enable \
artifactregistry.googleapis.com \
cloudbuild.googleapis.com \
cloudresourcemanager.googleapis.com \
iamcredentials.googleapis.com \
serviceusage.googleapis.com \
run.googleapis.com \
orgpolicy.googleapis.com \
--project=${PROJ}
done
验证所有项目的 API 启用情况
确保所有三个项目(PROJECT_GOVERNANCE、PROJECT_CONCIERGE 和 PROJECT_SELLERS)都启用了完全相同的 API,有助于建立运营一致性,并防止出现运行时令牌铸造失败、架构编目错误或遥测数据丢失。
在 Cloud Shell 中运行以下验证脚本,以验证所有三个项目之间的 API 对等性:
# validate that all required APIs are enabled across all 3 projects
python3 - << 'EOF'
import subprocess
import os
import sys
REQUIRED_APIS = [
"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",
"agentidentity.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",
"securitycenter.googleapis.com",
"saasservicemgmt.googleapis.com",
"storage.googleapis.com",
"telemetry.googleapis.com",
"texttospeech.googleapis.com",
"artifactregistry.googleapis.com",
"cloudbuild.googleapis.com",
"cloudresourcemanager.googleapis.com",
"iamcredentials.googleapis.com",
"serviceusage.googleapis.com",
"run.googleapis.com",
"orgpolicy.googleapis.com"
]
projects = {
"GOVERNANCE": os.environ.get("PROJECT_GOVERNANCE", ""),
"CONCIERGE": os.environ.get("PROJECT_CONCIERGE", ""),
"SELLERS": os.environ.get("PROJECT_SELLERS", "")
}
enabled = {}
for role, proj in projects.items():
if not proj:
print(f"Error: Environment variable for {role} is not set.")
sys.exit(1)
res = subprocess.run(
["gcloud", "services", "list", "--enabled", f"--project={proj}", "--format=value(config.name)"],
capture_output=True, text=True, check=True
)
enabled[role] = set(res.stdout.strip().splitlines())
print(f"\n{'API Name':<36} | {'GOVERNANCE':<12} | {'CONCIERGE':<12} | {'SELLERS':<12}")
print("-" * 78)
all_synced = True
for api in REQUIRED_APIS:
g_status = "ENABLED" if api in enabled["GOVERNANCE"] else "MISSING"
c_status = "ENABLED" if api in enabled["CONCIERGE"] else "MISSING"
s_status = "ENABLED" if api in enabled["SELLERS"] else "MISSING"
if "MISSING" in (g_status, c_status, s_status):
all_synced = False
print(f"{api:<36} | {g_status:<12} | {c_status:<12} | {s_status:<12}")
print("-" * 78)
if all_synced:
print("✅ All 29 required APIs are ENABLED and synchronized across all three projects.\n")
else:
print("❌ Discrepancies detected. Please re-run the enablement commands for missing services.\n")
sys.exit(1)
EOF
验证输出示例:
您应该会看到所有 API 均已启用。
✅ All 30 required APIs are ENABLED and synchronized across all three projects.
配置组织政策
默认 Google Cloud 组织政策会强制执行限制,以将 IAM v3 访问权限政策绑定限制为资源 (constraints/iam.managed.disableAccessPolicyBinding)。
通过将 enforce: false 明确设置为“允许”,在项目级层替换任何继承的组织政策限制条件。
# disable iam v3 constraint (allow v3 access policies)
gcloud org-policies set-policy /dev/stdin << EOF
name: projects/${PROJECT_NUMBER_GOVERNANCE}/policies/iam.managed.disableAccessPolicyBinding
spec:
rules:
- enforce: false
EOF
# verify org policy constraints on project
gcloud org-policies describe iam.managed.disableAccessPolicyBinding \
--project=${PROJECT_GOVERNANCE} --effective
设置部分到此结束…接下来请参阅注册核心 Google API 部分。
3. Agent Registry
注册核心 Google API 端点服务
代理网关要求在中央代理注册表中注册 Google API 网址,以便配置了 agent_gateway_config 的代理能够将出站流量安全地路由到核心 Google Cloud 后端服务(例如 aiplatform、IAM 凭据和遥测)。
在 Agent Registry 中创建 core-gapi-services
# register core google api endpoints in agent registry with standard and :443 port variants
gcloud agent-registry services create core-gapi-services \
--project=${PROJECT_GOVERNANCE} \
--location=${REGION} \
--display-name="gapi.core.services" \
--description="Core Google Cloud APIs and Service Endpoints" \
--endpoint-spec-type=no-spec \
--interfaces=protocolBinding=JSONRPC,url=https://telemetry.googleapis.com \
--interfaces=protocolBinding=JSONRPC,url=https://telemetry.mtls.googleapis.com \
--interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com \
--interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com:443 \
--interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com \
--interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com:443 \
--interfaces=protocolBinding=JSONRPC,url=https://aiplatform.googleapis.com \
--interfaces=protocolBinding=JSONRPC,url=https://aiplatform.googleapis.com:443 \
--interfaces=protocolBinding=JSONRPC,url=https://aiplatform.mtls.googleapis.com \
--interfaces=protocolBinding=JSONRPC,url=https://aiplatform.mtls.googleapis.com:443 \
--interfaces=protocolBinding=JSONRPC,url=https://cloudresourcemanager.googleapis.com \
--interfaces=protocolBinding=JSONRPC,url=https://iamcredentials.googleapis.com \
--interfaces=protocolBinding=JSONRPC,url=https://iamcredentials.mtls.googleapis.com \
--interfaces=protocolBinding=JSONRPC,url=https://agentregistry.googleapis.com \
--interfaces=protocolBinding=JSONRPC,url=https://agentregistry.mtls.googleapis.com \
--interfaces=protocolBinding=JSONRPC,url=https://agentregistry.googleapis.com:443 \
--interfaces=protocolBinding=JSONRPC,url=https://agentregistry.mtls.googleapis.com:443
捕获核心 API 端点资源 ID
# capture the underlying Agent Registry endpoint ID
export ENDPOINT_ID=$(gcloud agent-registry services describe core-gapi-services \
--project=${PROJECT_GOVERNANCE} \
--location=${REGION} \
--format="value(registryResource)" | awk -F'/' '{print $NF}')
echo "Core APIs Endpoint ID: ${ENDPOINT_ID}"
了解智能体身份中的 principalSet 与 principal
在 Google Cloud IAM 和 Gemini Enterprise Agent Platform 中,为正在执行的代理容器颁发的机器身份使用由 Identity-Aware Proxy (IAP v2) 评估的经过加密证明的 SPIFFE URN。配置 IAM Unified Access Policies 时,您可以指定特定单个 principal 或基于属性的 principalSet:
维度 |
|
|
IAM 语法 |
|
|
粒度 | 精细(实例级):标识单个特定的推理引擎容器实例。 | 粗粒度(项目级):识别共享通用项目属性的所有推理引擎。 |
URN 格式 |
|
|
Agent Platform 中的使用情形 | 第 2 层(业务工具和 A2A):授权特定编排器代理调用目标网域工具(例如,采购礼宾 $\rightarrow$ 汉堡卖家)。 | 第 1 级(基础架构):向项目中的所有代理授予对 Google Cloud API 的出站访问权限 ( |
生命周期影响 | 如果代理被删除并重新创建,其新的引擎 ID 需要更新后的 IAM 政策绑定。 | 自动应用于相应项目中新部署的代理,无需进行额外的 IAM 更新。 |
使用 Unified Access Policies (UAP / IAP v2) 进行声明式治理
在旧版 IAP v1 中,出站流量政策使用 gcloud beta iap web add-iam-policy-binding 直接附加到各个 Agent Registry 资源。在 IAP v2 和 Unified Access Policies下,系统不再使用按资源绑定的方式,而是采用单一的集中式 IAM 访问权限政策 (cfg/uap-rules.json)。
core-gapi-services 的基础出站授权将配置为第 5 部分中统一访问政策的规则 1,确保所有代理容器在部署之前都已建立基础出站路由。
如需深入了解主账号标识符和工作负载身份机制,请参阅:
至此,核心 API 端点注册完成…接下来,请前往部署集中式 Agent Gateway部分。
4. Agent Gateway
部署集中式 Agent Gateway
在 $PROJECT_GOVERNANCE 项目中以 AGENT_TO_ANYWHERE 出站流量模式部署集中式 Agent Gateway (centralized-agw)。
定义网关配置清单
为出站流量治理创建 cfg/${AGW_NAME}.yaml:
# generate agent gateway config yaml
cat > cfg/${AGW_NAME}.yaml << EOF
name: ${AGW_NAME}
protocols:
- MCP
googleManaged:
governedAccessPath: AGENT_TO_ANYWHERE
registries:
- "//agentregistry.googleapis.com/projects/${PROJECT_GOVERNANCE}/locations/${REGION}"
EOF
导入 Agent Gateway 配置
# import and create agent gateway
gcloud network-services agent-gateways import ${AGW_NAME} \
--source="cfg/${AGW_NAME}.yaml" \
--location=${REGION} \
--project=${PROJECT_GOVERNANCE}
验证 Agent Gateway 详细信息
# show agent gateway status
gcloud network-services agent-gateways describe ${AGW_NAME} \
--location=${REGION} \
--project=${PROJECT_GOVERNANCE}
示例输出:
agentGatewayCard:
mtlsEndpoint: projects/${AGW_TP_ID}/regions/us-central1/serviceAttachments/unitkind1-swp-mtls-psc-sa
rootCertificates:
- |
-----BEGIN CERTIFICATE-----
MIIDwzCCAqugAwIBAgITNQuWGopdOZaHdcK7r7AYFhonqDANBgkqhkiG9w0BAQsF
...
-----END CERTIFICATE-----
serviceExtensionsServiceAccount: service-${PROJ_NO}@gcp-sa-dep.iam.gserviceaccount.com
createTime: 'YYYY-MM-DDT12:34:56.789098765Z'
googleManaged:
governedAccessPath: AGENT_TO_ANYWHERE
name: projects/${PROJECT_GOVERNANCE}/locations/us-central1/agentGateways/centralized-agw
protocols:
- MCP
registries:
- //agentregistry.googleapis.com/projects/${PROJECT_GOVERNANCE}/locations/us-central1
updateTime: 'YYYY-MM-DDT12:34:56.789098765Z'
网关部署到此结束…接下来请参阅配置授权部分。
5. 授权
配置 Agent Gateway 授权和基础 UAP
Agent Gateway 使用与 Identity-Aware Proxy (IAP v2) Unified Access Policies (UAP) 集成的授权政策 (networksecurity.authzPolicies) 来保护和管理出站工具和代理流量。
授权架构概览
图 4. 授权架构概览
授权架构由三个相互关联的层组成:
- IAP 服务扩展程序 (
authzExtension):配置了service: iap.googleapis.com、metadata: iapPolicyVersion: "V2"和failOpen: false的区域资源,用于严格执行边界零信任。 - 网关授权政策 (
authzPolicy):以 Agent Gateway 为目标的区域级资源,包含policyProfile: REQUEST_AUTHZ和action: CUSTOM,将路由授权检查发送到 IAP 授权扩展程序。 - IAM 统一访问权限政策和绑定 (
accessPolicy和policyBinding):由 IAP 评估的全局 IAM v3 资源。它会根据调用方 SPIFFE 身份和 CEL 目录条件验证通用权限iap.googleapis.com/resources.egressViaIAP。
第 1 步:创建并导入 IAP v2 授权扩展程序
在严格的 ENFORCE 模式下,使用 iapPolicyVersion: "V2" 和 failOpen: false 创建服务扩展程序清单:
# create authz extension config file in ENFORCE mode
cat > cfg/${AGW_NAME}-svc-ext-authz-iap.yaml << EOF
name: ${AGW_NAME}-svc-ext-authz-iap
service: iap.googleapis.com
failOpen: false
timeout: 1s
metadata:
iapPolicyVersion: "V2"
EOF
导入授权扩展程序:
# import IAP v2 authz extension
gcloud service-extensions authz-extensions import ${AGW_NAME}-svc-ext-authz-iap \
--source=cfg/${AGW_NAME}-svc-ext-authz-iap.yaml \
--location=${REGION} \
--project=${PROJECT_GOVERNANCE}
验证授权扩展服务是否处于活动状态:
# describe authz extension
gcloud service-extensions authz-extensions describe ${AGW_NAME}-svc-ext-authz-iap \
--location=${REGION} \
--project=${PROJECT_GOVERNANCE}
示例输出:
createTime: 'YYYY-MM-DDT12:34:56.789098765Z'
failOpen: false
metadata:
iapPolicyVersion: V2
name: projects/${PROJECT_GOVERNANCE}/locations/us-central1/authzExtensions/centralized-agw-svc-ext-authz-iap
service: iap.googleapis.com
timeout: 1s
第 2 步:创建并导入网关授权政策
创建附加到 Agent Gateway 并将请求验证委托给 IAP Authz 扩展程序的授权政策配置:
# create authz policy manifest
cat > cfg/${AGW_NAME}-authz-policy-profile-iap.yaml << EOF
name: ${AGW_NAME}-authz-policy-profile-iap
target:
resources:
- "projects/${PROJECT_GOVERNANCE}/locations/${REGION}/agentGateways/${AGW_NAME}"
policyProfile: REQUEST_AUTHZ
action: CUSTOM
customProvider:
authzExtension:
resources:
- "projects/${PROJECT_GOVERNANCE}/locations/${REGION}/authzExtensions/${AGW_NAME}-svc-ext-authz-iap"
EOF
导入授权政策:
# import 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} \
--project=${PROJECT_GOVERNANCE}
验证有效的授权政策:
# describe authz policy
gcloud beta network-security authz-policies describe ${AGW_NAME}-authz-policy-profile-iap \
--location=${REGION} \
--project=${PROJECT_GOVERNANCE}
第 3 步:创建初始统一访问权限政策(规则 1:核心 Google API)
创建 cfg/uap-rules.json,其中规则 1 授权三个项目 principalSet 访问 core-gapi-services:
# create initial unified access policy rules manifest
cat > cfg/uap-rules.json << EOF
[
{
"description": "Rule 1: Allow agent runtimes across all 3 projects to reach Core Google APIs",
"effect": "ALLOW",
"principals": [
"principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJECT_NUMBER_GOVERNANCE}",
"principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJECT_NUMBER_CONCIERGE}",
"principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJECT_NUMBER_SELLERS}"
],
"operation": {
"permissions": [
"iap.googleapis.com/resources.egressViaIAP"
]
},
"conditions": {
"iap.googleapis.com": {
"expression": \
"destination.is_registered == true && \
destination.agent_registry.resource_type == 'ENDPOINT' && ( \
destination.agent_registry.endpoint.name == 'projects/${PROJECT_GOVERNANCE}/locations/${REGION}/endpoints/core-gapi-services' || \
destination.agent_registry.endpoint.name == 'projects/${PROJECT_GOVERNANCE}/locations/${REGION}/endpoints/${ENDPOINT_ID}' || \
destination.agent_registry.endpoint.name == 'projects/${PROJECT_NUMBER_GOVERNANCE}/locations/${REGION}/endpoints/${ENDPOINT_ID}')"
}
}
}
]
EOF
第 4 步:创建并绑定 IAM 访问权限政策
创建全局 IAM 访问权限政策:
# create global IAM access policy
gcloud iam access-policies create ${UAP_POLICY_NAME} \
--details-rules=cfg/uap-rules.json \
--project=${PROJECT_GOVERNANCE} \
--location=global
将访问权限政策绑定到 PROJECT_GOVERNANCE:
# bind access policy to governance project
gcloud iam policy-bindings create ${UAP_BINDING_NAME} \
--policy="projects/${PROJECT_GOVERNANCE}/locations/global/accessPolicies/${UAP_POLICY_NAME}" \
--target-resource="//cloudresourcemanager.googleapis.com/projects/${PROJECT_GOVERNANCE}" \
--project=${PROJECT_GOVERNANCE} \
--location=global
验证政策绑定是否处于有效状态:
# verify policy binding
gcloud iam policy-bindings describe ${UAP_BINDING_NAME} \
--project=${PROJECT_GOVERNANCE} \
--location=global
示例输出:
name: projects/${PROJECT_GOVERNANCE}/locations/global/policyBindings/uap-binding-centralized-agw
policy: projects/${PROJECT_GOVERNANCE}/locations/global/accessPolicies/uap-policy-centralized-agw
policyKind: ACCESS_POLICY
target:
resource: //cloudresourcemanager.googleapis.com/projects/${PROJECT_GOVERNANCE}
现在,在严格的 ENFORCE 模式下,所有三个项目都已安全授权基础 Google Cloud API 出站流量。
至此,网关授权设置完毕…接下来请参阅配置跨项目 IAM 权限部分。
6. 跨项目 IAM
配置跨项目 IAM 权限
在此多项目拓扑中,Agent Runtime 位于 spoke 项目(PROJECT_CONCIERGE 和 PROJECT_SELLERS)中,而 Central Agent Gateway 和 Agent Registry 位于 PROJECT_GOVERNANCE 中。
由于 Google Cloud 项目是隔离的安全边界,因此必须在两个运营层面上明确授予跨项目访问权限:
- 控制平面(部署时):部署配置了
--agent-gateway-config的代理容器时,spoke 项目的Agent Runtime 服务代理 (service-) 必须将容器连接到中央网关。我们创建了一个最小的自定义角色 (@gcp-sa-aiplatform.iam.gserviceaccount.com ar_agw_cross_project_sa),该角色在PROJECT_GOVERNANCE中授予networkservices.agentGateways.use、get和operations.get。 - 数据平面(运行时执行):
- 目录发现:Spoke 身份需要在
PROJECT_GOVERNANCE中具有roles/agentregistry.viewer,才能动态解析目标代理端点。 - 目标调用:礼宾服务智能体需要
PROJECT_SELLERS中的roles/aiplatform.user才能针对卖家推理引擎执行查询。
- 目录发现:Spoke 身份需要在
在 PROJECT_GOVERNANCE 中创建自定义 IAM 角色
# create custom role in central governance project
gcloud iam roles create ar_agw_cross_project_sa \
--project=${PROJECT_GOVERNANCE} \
--title="Runtime Agent Gateway Cross-Project SA" \
--description="Custom role for cross-project service agents to access Central Agent Gateway" \
--permissions="networkservices.agentGateways.get,networkservices.agentGateways.use,networkservices.operations.get" \
--stage="GA"
为 Agent Runtime 服务代理分配自定义角色
# 1. ensure aiplatform service identities are provisioned across all projects
for PROJ in ${PROJECT_GOVERNANCE} ${PROJECT_CONCIERGE} ${PROJECT_SELLERS}; do
gcloud beta services identity create --service=aiplatform.googleapis.com --project=${PROJ}
done
# 2. derive aiplatform service agent emails
export CONCIERGE_AI_SA="service-${PROJECT_NUMBER_CONCIERGE}@gcp-sa-aiplatform.iam.gserviceaccount.com"
export CONCIERGE_RE_SA="service-${PROJECT_NUMBER_CONCIERGE}@gcp-sa-aiplatform-re.iam.gserviceaccount.com"
export CONCIERGE_COMPUTE_SA="${PROJECT_NUMBER_CONCIERGE}-compute@developer.gserviceaccount.com"
export SELLERS_AI_SA="service-${PROJECT_NUMBER_SELLERS}@gcp-sa-aiplatform.iam.gserviceaccount.com"
export SELLERS_RE_SA="service-${PROJECT_NUMBER_SELLERS}@gcp-sa-aiplatform-re.iam.gserviceaccount.com"
export SELLERS_COMPUTE_SA="${PROJECT_NUMBER_SELLERS}-compute@developer.gserviceaccount.com"
# 3. grant custom role & network viewer to Concierge and Sellers Service Agents
for SA in ${CONCIERGE_AI_SA} ${SELLERS_AI_SA}; do
gcloud projects add-iam-policy-binding ${PROJECT_GOVERNANCE} \
--member="serviceAccount:${SA}" \
--role="projects/${PROJECT_GOVERNANCE}/roles/ar_agw_cross_project_sa" \
--condition=None
gcloud projects add-iam-policy-binding ${PROJECT_GOVERNANCE} \
--member="serviceAccount:${SA}" \
--role="roles/networkservices.viewer" \
--condition=None
done
# 4. grant agent registry viewer on Governance Project for dynamic autodiscovery
for MEMBER in "serviceAccount:${CONCIERGE_AI_SA}" "serviceAccount:${CONCIERGE_RE_SA}" "serviceAccount:${CONCIERGE_COMPUTE_SA}" "serviceAccount:${SELLERS_AI_SA}" "serviceAccount:${SELLERS_RE_SA}" "serviceAccount:${SELLERS_COMPUTE_SA}" "principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJECT_NUMBER_CONCIERGE}" "principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJECT_NUMBER_SELLERS}"; do
gcloud projects add-iam-policy-binding ${PROJECT_GOVERNANCE} \
--member="${MEMBER}" \
--role="roles/agentregistry.viewer" \
--condition=None
done
# 5. grant agent project viewer on Governance Project for dynamic autodiscovery
for SA in ${CONCIERGE_COMPUTE_SA} ${CONCIERGE_AI_SA}; do
gcloud projects add-iam-policy-binding ${PROJECT_GOVERNANCE} \
--member="serviceAccount:${SA}" \
--role="roles/viewer" \
--condition=None
done
# 6. grant aitplatform user on Sellers project to Concierge for cross-project A2A invocation
for MEMBER in "serviceAccount:${CONCIERGE_AI_SA}" "serviceAccount:${CONCIERGE_RE_SA}" "serviceAccount:${CONCIERGE_COMPUTE_SA}" "principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJECT_NUMBER_CONCIERGE}"; do
gcloud projects add-iam-policy-binding ${PROJECT_SELLERS} \
--member="${MEMBER}" \
--role="roles/aiplatform.user" \
--condition=None
done
至此,跨项目 IAM 设置完成…接下来,请前往部署销售代理和礼宾代理部分。
7. Agent Runtime
部署销售代理和礼宾代理
此 Codelab 使用的多代理应用代码库和部署脚本维护在远程 Google Cloud GitHub 代码库中。以下步骤会将代码库克隆到本地,将必要的文件复制到当前工作目录结构中,清理临时文件,并使用 uv 安装依赖项。
提取远程制品
# clone remote repository to temp local dir
git clone https://github.com/GoogleCloudPlatform/cloud-networking-solutions.git ./temp_agw_cuj_arun_multiproject
# copy multi-agent application files to current working directory
cp -r temp_agw_cuj_arun_multiproject/codelabs/agw-cuj-arun-multiproject ./cross-project-multiagent
# remove temporary directory
rm -rf temp_agw_cuj_arun_multiproject
# install dependencies
uv sync --directory ./cross-project-multiagent
创建共享的中央暂存桶
# create shared central staging bucket
gcloud storage buckets create gs://${PROJECT_GOVERNANCE}-shared-staging \
--project=${PROJECT_GOVERNANCE} \
--location=${REGION}
# grant cross-project read/write access to runtime service agents
gcloud storage buckets add-iam-policy-binding gs://${PROJECT_GOVERNANCE}-shared-staging \
--member="serviceAccount:service-${PROJECT_NUMBER_CONCIERGE}@gcp-sa-aiplatform.iam.gserviceaccount.com" \
--role="roles/storage.objectAdmin"
gcloud storage buckets add-iam-policy-binding gs://${PROJECT_GOVERNANCE}-shared-staging \
--member="serviceAccount:service-${PROJECT_NUMBER_SELLERS}@gcp-sa-aiplatform.iam.gserviceaccount.com" \
--role="roles/storage.objectAdmin"
跨项目 Agent Gateway 绑定的运作方式
在此步骤中,您将把卖家代理部署到 Spoke 项目 (PROJECT_SELLERS) 中,同时配置这些代理,使其通过 PROJECT_GOVERNANCE 中的中央 Agent Gateway 路由出站流量:
# !-- for example purposes -- NOT a command to execute --!
# snippet from deploy_burger.py
burger_config = {
"staging_bucket": staging_bucket_uri,
"gcs_dir_name": "burger_agent",
"display_name": "burger-seller-agent-adk",
"identity_type": "AGENT_IDENTITY",
"agent_gateway_config": {
"agent_to_anywhere_config": {
"agent_gateway": f"projects/{args.governance_project}/locations/{args.region}/agentGateways/{args.gateway}"
}
},
}
deployed_burger = client.agent_engines.create(agent=burger_playground, config=burger_config)
由于我们在统一访问政策中较早确立了规则 1,因此通过网关向 Google Cloud API 发出的容器初始化请求不会中断。
将汉堡和披萨销售代理部署到 PROJECT_SELLERS
# 1. deploy Burger Seller Agent to PROJECT_SELLERS
uv run --directory ./cross-project-multiagent python deploy_burger.py \
--project=${PROJECT_SELLERS} \
--region=${REGION} \
--governance-project=${PROJECT_GOVERNANCE} \
--gateway=projects/${PROJECT_GOVERNANCE}/locations/${REGION}/agentGateways/${AGW_NAME}
# 2. deploy Pizza Seller Agent to PROJECT_SELLERS
uv run --directory ./cross-project-multiagent python deploy_pizza.py \
--project=${PROJECT_SELLERS} \
--region=${REGION} \
--governance-project=${PROJECT_GOVERNANCE} \
--gateway=projects/${PROJECT_GOVERNANCE}/locations/${REGION}/agentGateways/${AGW_NAME}
验证卖家网关路由
# retrieve deployed seller reasoning engine IDs
export BURGER_ENGINE_ID=$(grep BURGER_SELLER_AGENT_ID cross-project-multiagent/burger_agent.env | awk -F'/' '{print $NF}')
export PIZZA_ENGINE_ID=$(grep PIZZA_SELLER_AGENT_ID cross-project-multiagent/pizza_agent.env | awk -F'/' '{print $NF}')
echo "Burger Engine ID: ${BURGER_ENGINE_ID}"
echo "Pizza Engine ID: ${PIZZA_ENGINE_ID}"
# inspect runtime configuration for both Seller Agents
for ENGINE_ID in ${BURGER_ENGINE_ID} ${PIZZA_ENGINE_ID}; do
curl -s -X GET "https://${REGION}-aiplatform.googleapis.com/v1beta1/projects/${PROJECT_SELLERS}/locations/${REGION}/reasoningEngines/${ENGINE_ID}" \
-H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
-H "Content-Type: application/json" \
| jq '{displayName: .displayName, identityType: .spec.identityType, effectiveIdentity: .spec.effectiveIdentity, agentGatewayConfig: .spec.deploymentSpec.agentGatewayConfig}'
done
将“购物礼宾”代理部署到 PROJECT_CONCIERGE
# deploy Purchasing Concierge to PROJECT_CONCIERGE
uv run --directory ./cross-project-multiagent python deploy_concierge_adk.py \
--project=${PROJECT_CONCIERGE} \
--region=${REGION} \
--staging-bucket=gs://${PROJECT_GOVERNANCE}-shared-staging \
--gateway-name=${AGW_NAME} \
--gateway-project=${PROJECT_GOVERNANCE}
验证购买网关路由
# retrieve Concierge engine ID
export CONCIERGE_ENGINE_ID=$(grep CONCIERGE_AGENT_ID cross-project-multiagent/concierge_agent.env | awk -F'/' '{print $NF}')
echo "Concierge Engine ID: ${CONCIERGE_ENGINE_ID}"
# inspect runtime configuration for Purchasing Concierge
curl -s -X GET "https://${REGION}-aiplatform.googleapis.com/v1beta1/projects/${PROJECT_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}" \
-H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
-H "Content-Type: application/json" \
| jq '{displayName: .displayName, identityType: .spec.identityType, effectiveIdentity: .spec.effectiveIdentity, agentGatewayConfig: .spec.deploymentSpec.agentGatewayConfig}'
输出应显示 Concierge 代理运行时身份和项目,以及与治理项目 Agent Gateway 的绑定。
{
"displayName": "purchasing-concierge-adk",
"identityType": "AGENT_IDENTITY",
"effectiveIdentity": "agents.global.org-${ORG_ID}.system.id.goog/resources/aiplatform/projects/${PROJECT_CONCIERGE}/locations/us-central1/reasoningEngines/${CONCIERGE_ENGINE_ID}",
"agentGatewayConfig": {
"agentToAnywhereConfig": {
"agentGateway": "projects/${PROJECT_GOVERNANCE}/locations/us-central1/agentGateways/centralized-agw"
}
}
}
至此,代理部署已完成…接下来请参阅在中央 Agent Registry 中注册代理部分。
8. 跨项目注册表
在中央 Agent Registry 中注册代理
在 PROJECT_GOVERNANCE 中使用跨项目区域 mTLS 端点和数字项目编号注册中央 Agent Registry 中的所有三个代理。
在 Agent Registry 中将服务注册为非 A2A 代理
# 1. register Burger Seller Agent
gcloud agent-registry services create burger-seller-agent \
--project=${PROJECT_GOVERNANCE} \
--location=${REGION} \
--display-name="Burger Seller Agent" \
--description="Specialist agent that sells burgers and fries" \
--agent-spec-type=no-spec \
--interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com/v1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${BURGER_ENGINE_ID}:query \
--interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com/v1beta1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${BURGER_ENGINE_ID}:query
# 2. register Pizza Seller Agent
gcloud agent-registry services create pizza-seller-agent \
--project=${PROJECT_GOVERNANCE} \
--location=${REGION} \
--display-name="Pizza Seller Agent" \
--description="Specialist agent that sells pizzas and pasta" \
--agent-spec-type=no-spec \
--interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com/v1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${PIZZA_ENGINE_ID}:query \
--interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com/v1beta1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${PIZZA_ENGINE_ID}:query
# 3. register Purchasing Concierge Agent
gcloud agent-registry services create purchasing-concierge-adk \
--project=${PROJECT_GOVERNANCE} \
--location=${REGION} \
--display-name="Purchasing Concierge Agent" \
--description="Orchestrator concierge agent that routes purchasing requests" \
--agent-spec-type=no-spec \
--interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com/v1/projects/${PROJECT_NUMBER_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}:query \
--interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com/v1beta1/projects/${PROJECT_NUMBER_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}:query
捕获底层 Agent Registry ID
# capture underlying Agent Registry Agent UUIDs
export BURGER_AGENT_ID=$(gcloud agent-registry services describe burger-seller-agent --project=${PROJECT_GOVERNANCE} --location=${REGION} --format="value(registryResource)" | awk -F'/' '{print $NF}')
export PIZZA_AGENT_ID=$(gcloud agent-registry services describe pizza-seller-agent --project=${PROJECT_GOVERNANCE} --location=${REGION} --format="value(registryResource)" | awk -F'/' '{print $NF}')
export CONCIERGE_AGENT_ID=$(gcloud agent-registry services describe purchasing-concierge-adk --project=${PROJECT_GOVERNANCE} --location=${REGION} --format="value(registryResource)" | awk -F'/' '{print $NF}')
echo "Burger Agent ID: ${BURGER_AGENT_ID}"
echo "Pizza Agent ID: ${PIZZA_AGENT_ID}"
echo "Concierge Agent ID: ${CONCIERGE_AGENT_ID}"
注册表配置到此结束…接下来请参阅配置 A2A 出站政策部分。
9. UAP 政策
在统一访问权限政策中配置 A2A 出站流量政策
在严格 ENFORCE 模式下,代理网关的默认拒绝架构:
- 规则 1(基准 Google Cloud API):允许所有 3 个项目中的代理容器访问
core-gapi-services。 - 规则 2(汉堡卖家代理:允许):允许采购礼宾代理实例专门调用汉堡卖家代理。
- 披萨销售代理 (默认拒绝):有意未纳入政策规则。在
ENFORCE模式 (failOpen: false) 下,如果 Concierge 尝试调用 Pizza Seller,系统会立即在网关边界处终止该尝试,并返回HTTP 403 Forbidden。
制定礼宾智能体身份
# formulate the exact SPIFFE machine identity for the Concierge Agent
export CONCIERGE_SPIFFE_PRINCIPAL="principal://agents.global.org-${ORG_ID}.system.id.goog/resources/aiplatform/projects/${PROJECT_NUMBER_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}"
echo "Concierge SPIFFE Principal: ${CONCIERGE_SPIFFE_PRINCIPAL}"
使用规则 1 和 2 更新清单
创建新的 cfg/uap-rules-update-2.json 以包含规则 1(核心 API)和现在的规则 2(汉堡卖家代理):
# create addendum to update policy manifest with Rule 2 for Burger Agent
cat > cfg/uap-rules-update-2.json << EOF
[
{
"description": "Rule 2: Allow Purchasing Concierge to invoke Burger Seller Agent via Central Gateway",
"effect": "ALLOW",
"principals": [
"${CONCIERGE_SPIFFE_PRINCIPAL}"
],
"operation": {
"permissions": [
"iap.googleapis.com/resources.egressViaIAP"
]
},
"conditions": {
"iap.googleapis.com": {
"expression": \
"destination.is_registered == true && \
destination.agent_registry.resource_type == 'AGENT' && ( \
destination.agent_registry.agent.name == 'projects/${PROJECT_GOVERNANCE}/locations/${REGION}/agents/burger-seller-agent' || \
destination.agent_registry.agent.name == 'projects/${PROJECT_GOVERNANCE}/locations/${REGION}/agents/${BURGER_AGENT_ID}' || \
destination.agent_registry.agent.name == 'projects/${PROJECT_NUMBER_GOVERNANCE}/locations/${REGION}/agents/${BURGER_AGENT_ID}')"
}
}
}
]
EOF
应用更新后的访问权限政策
# update IAM access policy with Burger rule
gcloud iam access-policies update ${UAP_POLICY_NAME} \
--add-details-rules=cfg/uap-rules-update-2.json \
--project=${PROJECT_GOVERNANCE} \
--location=global
验证 IAM 访问权限政策详情
# inspect updated access policy
gcloud iam access-policies describe ${UAP_POLICY_NAME} \
--project=${PROJECT_GOVERNANCE} \
--location=global
示例输出:
details:
rules:
- conditions:
iap.googleapis.com:
expression: destination.is_registered == true && destination.agent_registry.resource_type
== 'ENDPOINT' && (destination.agent_registry.endpoint.name == 'projects/${PROJECT_GOVERNANCE}/locations/us-central1/endpoints/core-gapi-services'
|| destination.agent_registry.endpoint.name == 'projects/${PROJECT_NUMBER_GOVERNANCE}/locations/us-central1/endpoints/${ENDPOINT_ID}')
description: 'Rule 1: Allow agent runtimes across all 3 projects to reach Core
Google APIs'
effect: ALLOW
operation:
permissions:
- iap.googleapis.com/resources.egressViaIAP
principals:
- principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJECT_NUMBER_GOVERNANCE}
- principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJECT_NUMBER_CONCIERGE}
- principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJECT_NUMBER_SELLERS}
- conditions:
iap.googleapis.com:
expression: (destination.is_registered == true) && (destination.agent_registry.resource_type
== 'AGENT') && (destination.agent_registry.agent.name == 'projects/${PROJECT_GOVERNANCE}/locations/us-central1/agents/burger-seller-agent'
|| destination.agent_registry.agent.name == 'projects/${PROJECT_NUMBER_GOVERNANCE}/locations/us-central1/agents/${BURGER_AGENT_ID}')
description: 'Rule 2: Allow Purchasing Concierge to invoke Burger Seller Agent
via Central Gateway'
effect: ALLOW
operation:
permissions:
- iap.googleapis.com/resources.egressViaIAP
principals:
- principal://agents.global.org-${ORG_ID}.system.id.goog/resources/aiplatform/projects/${PROJECT_NUMBER_CONCIERGE}/locations/us-central1/reasoningEngines/${CONCIERGE_ENGINE_ID}
name: projects/${PROJECT_GOVERNANCE}/locations/global/accessPolicies/uap-policy-centralized-agw
至此,政策设置已完成…接下来请参阅测试和验证治理政策部分。
10. 验证政策
通过 Cloud Logging 测试和验证治理政策
在本部分中,您将在 Agent Runtime AI Playground 中测试跨项目的智能体到智能体 (A2A) 互动,观察严格模式下的实时边界 HTTP 403 Forbidden 阻止 ENFORCE,实时修改统一访问政策,并验证即时订单审批。
第 1 步:在 PROJECT_CONCIERGE 中打开 Agent Runtime AI Playground
- 打开 Google Cloud 控制台。
- 在顶部项目选择器栏中,切换到
PROJECT_CONCIERGE。 - 在导航菜单中,依次前往 Agent Platform > 代理 > 部署。
- 点击
purchasing-concierge-adk。 - 选择 Playground 以在屏幕右侧打开互动式聊天界面。
第 2 步:测试汉堡订单(规则 2 匹配 -> 200 OK)
在 Playground 对话窗口中,提交以下顺序提示:
I would like 10 Classic Cheeseburgers. Place this order now.
如果需要确认回复,请提交以下回复:
Confirmed, please place the order.
或者,通过 Cloud Shell / 终端以编程方式进行测试:
uv run --directory ./cross-project-multiagent python -c "
import vertexai
from vertexai.preview import reasoning_engines
vertexai.init(project='${PROJECT_CONCIERGE}', location='${REGION}')
agent = reasoning_engines.ReasoningEngine('projects/${PROJECT_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}')
response = agent.query(input={'message': 'I would like 22 Spicy Cajun Burgers please. Place this order now.'})
print(response)
"
如果需要确认响应,请使用以下命令:
uv run --directory ./cross-project-multiagent python -c "
import vertexai
from vertexai.preview import reasoning_engines
vertexai.init(project='${PROJECT_CONCIERGE}', location='${REGION}')
agent = reasoning_engines.ReasoningEngine('projects/${PROJECT_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}')
response = agent.query(input='Yes please place the order now.')
print(response['text'])
"
幕后会发生什么:
- 动态发现:在会话启动期间,购买 Concierge 通过
core-gapi-services(通过规则 1 授权的 Agent Gateway)查询PROJECT_GOVERNANCE中的中央 Agent Registry,以发现burger-seller-agent的区域 mTLS 端点。 - 意图解析和 A2A 调用:购买助理中的 Gemini 解析食物订单意图,并通过出站 RPC 调用汉堡卖家代理
https://${REGION}-aiplatform.mtls.googleapis.com/.../reasoningEngines/${BURGER_ENGINE_ID}。 - Agent Gateway 拦截和 SPIFFE 传播:出站流量由
agent_gateway_config捕获并定向到PROJECT_GOVERNANCE中的中央 Agent Gateway,其中包含 Concierge 的加密 SPIFFE 身份 (principal://...)。 - IAP v2 政策评估:中央 Agent Gateway 调用 IAP 授权扩展程序 (
authzExtension)。IAP v2 会评估 IAM Unified Access Policies 中的规则 2。由于调用方匹配${CONCIERGE_SPIFFE_PRINCIPAL},而目标匹配burger-seller-agent,因此 IAP 返回ALLOW(granted: true)。 - 跨项目执行:Agent Gateway 将授权的跨项目请求代理到
PROJECT_SELLERS,Burger Seller Reasoning Engine 在其中处理订单并返回确认信息。
预期响应:
Your order for 10 Classic Cheeseburger(s) has been placed!
Here is a summary of your order:
- 10x Classic Cheeseburger @ IDR 85,000/each = IDR 850,000
Total: IDR 850,000
Your Order ID is: e8f9c732-f347-4cc4-acff-cfe09ccbeddd
第 3 步:检查 Agent Gateway 和 IAP v2 审核日志 (HTTP 200 / ALLOWED)
在 PROJECT_GOVERNANCE 中查询 Agent Gateway 请求日志:
# query Agent Gateway logs for successful 200 OK requests
gcloud logging read "
logName=\"projects/${PROJECT_GOVERNANCE}/logs/networkservices.googleapis.com%2Fgateway_requests\"
AND jsonPayload.authzPolicyInfo.result=\"ALLOWED\"
" \
--project="${PROJECT_GOVERNANCE}" \
--limit=10 \
--format="table(
timestamp.date('%H:%M:%S'):label=TIME,
httpRequest.requestMethod:label=METHOD,
httpRequest.status:label=STATUS,
jsonPayload.authzPolicyInfo.result:label=AUTHZ,
httpRequest.requestUrl:label=URL
)"
日志应捕获源自辐条项目(PROJECT_CONCIERGE 和 PROJECT_SELLERS)的出站流量,并包含 Gemini 推理调用 (generateContent)、Cloud Trace 遥测 (/v1/traces) 和 IAM 凭据查找的出站字段,这些流量会被规则 1 (core-gapi-services) 透明地拦截和授权。
查询 IAP v2 Cloud Audit 数据访问日志,以验证政策版本 POLICY_VERSION_V2:
# query IAP v2 audit logs with shortened principal and resource fields
gcloud logging read "
logName=\"projects/${PROJECT_GOVERNANCE}/logs/cloudaudit.googleapis.com%2Fdata_access\"
AND protoPayload.serviceName=\"iap.googleapis.com\"
" \
--project="${PROJECT_GOVERNANCE}" \
--limit=5 \
--format="table(
timestamp.date('%H:%M:%S'):label=TIME,
protoPayload.authenticationInfo.principalSubject.sub('\.global\..*\/reasoningEngines\/', '.[...]/reasoningEngines/'):label=CALLER,
protoPayload.authorizationInfo[0].granted:label=GRANTED,
protoPayload.metadata.destination.agent_registry.resource_type.basename():label=TYPE,
protoPayload.metadata.destination.agent_registry.resource_id.basename():label=RESOURCE_ID,
protoPayload.authorizationInfo[0].permission.basename():label=PERMISSION
)"
示例输出:
TIME CALLER GRANTED TYPE RESOURCE_ID PERMISSION
HH:MM:SS principal://agents.[...]/reasoningEngines/${CONCIERGE_ENGINE_ID} True Endpoint ${ENDPOINT_ID} resources.egressViaIAP
HH:MM:SS principal://agents.[...]/reasoningEngines/${BURGER_ENGINE_ID} True Endpoint ${ENDPOINT_ID} resources.egressViaIAP
HH:MM:SS principal://agents.[...]/reasoningEngines/${CONCIERGE_ENGINE_ID} True Endpoint ${ENDPOINT_ID} resources.egressViaIAP
HH:MM:SS principal://agents.[...]/reasoningEngines/${BURGER_ENGINE_ID} True Endpoint ${ENDPOINT_ID} resources.egressViaIAP
第 4 步:测试披萨订单(默认拒绝 -> HTTP 403 禁止强制执行)
在同一 Playground 对话窗口中,提交以下披萨订购提示:
I would like 10 BBQ Chicken Pizzas. Place this order now.
如果需要确认回复,请提交以下回复:
Confirmed, please place the order.
或者,通过 Cloud Shell / 终端以编程方式进行测试:
uv run --directory ./cross-project-multiagent python -c "
import vertexai
from vertexai.preview import reasoning_engines
vertexai.init(project='${PROJECT_CONCIERGE}', location='${REGION}')
agent = reasoning_engines.ReasoningEngine('projects/${PROJECT_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}')
response = agent.query(input='I would like 8 Hawaiian pizzas, please. Place this order now.')
print(response)
"
如果需要确认响应,请使用以下命令:
uv run --directory ./cross-project-multiagent python -c "
import vertexai
from vertexai.preview import reasoning_engines
vertexai.init(project='${PROJECT_CONCIERGE}', location='${REGION}')
agent = reasoning_engines.ReasoningEngine('projects/${PROJECT_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}')
response = agent.query(input='Yes please place the order now.')
print(response['text'])
"
预期响应:
I apologize, but I am unable to process that request at the moment. It seems
there was an issue connecting to the pizza seller agent. Please try again later.
幕后会发生什么:
- 动态发现:采购 Concierge 在启动期间从中央 Agent Registry 中解析了
pizza-seller-agent端点。 - 意图解析和 A2A 调用:采购礼宾中的 Gemini 尝试将披萨订单请求分派到
PROJECT_SELLERS中的披萨销售方端点。 - 网关拦截:出站远程过程调用 (RPC) 由
agent_gateway_config捕获并定向到中央 Agent Gateway。 - IAP v2 政策评估(默认拒绝):中央 Agent Gateway 调用 IAP v2。由于统一访问权限政策中不存在与
pizza-seller-agent匹配的规则,因此 IAP 返回DENY(granted: false)。 - 严格的边界阻止:由于授权扩展程序处于 ENFORCE 模式 (
failOpen: false),因此中央 Agent Gateway 会立即终止出站连接并返回HTTP 403 Forbidden。流量永远不会离开网关,也永远不会到达PROJECT_SELLERS。
第 5 步:检查 Agent Gateway 日志中是否有被屏蔽的请求 (HTTP 403 / DENIED)
# query Agent Gateway logs for blocked 403 requests
gcloud logging read "
logName=\"projects/${PROJECT_GOVERNANCE}/logs/networkservices.googleapis.com%2Fgateway_requests\"
AND httpRequest.status=403
" \
--project="${PROJECT_GOVERNANCE}" \
--limit=5 \
--format="table(
timestamp.date('%H:%M:%S'):label=TIME,
httpRequest.requestMethod:label=METHOD,
httpRequest.status:label=STATUS,
jsonPayload.authzPolicyInfo.result:label=AUTHZ,
httpRequest.requestUrl:label=URL
)"
被拒绝的日志输出示例:
TIME METHOD STATUS AUTHZ URL
HH:MM:SS POST 403 DENIED https://us-central1-aiplatform.mtls.googleapis.com/v1beta1/projects/${PROJECT_SELLERS}/locations/us-central1/reasoningEngines/${PIZZA_ENGINE_ID}:query
查询 IAP v2 数据访问审核日志,以了解拒绝的决策:
# query IAP v2 audit logs with shortened principal and resource fields
gcloud logging read "
logName=\"projects/${PROJECT_GOVERNANCE}/logs/cloudaudit.googleapis.com%2Fdata_access\"
AND protoPayload.serviceName=\"iap.googleapis.com\"
" \
--project="${PROJECT_GOVERNANCE}" \
--limit=5 \
--format="table(
timestamp.date('%H:%M:%S'):label=TIME,
protoPayload.authenticationInfo.principalSubject.sub('\.global\..*\/reasoningEngines\/', '.[...]/reasoningEngines/'):label=CALLER,
protoPayload.authorizationInfo[0].granted:label=GRANTED,
protoPayload.metadata.destination.agent_registry.resource_type.basename():label=TYPE,
protoPayload.metadata.destination.agent_registry.resource_id.basename():label=RESOURCE_ID,
protoPayload.authorizationInfo[0].permission.basename():label=PERMISSION
)"
拒绝审核日志输出示例:
TIME CALLER GRANTED TYPE RESOURCE_ID PERMISSION
HH:MM:SS principal://agents.[...]/reasoningEngines/${PIZZA_ENGINE_ID} True Endpoint ${REGISTRY_ID} resources.egressViaIAP
HH:MM:SS principal://agents.[...]/reasoningEngines/${PIZZA_ENGINE_ID} True Endpoint ${REGISTRY_ID} resources.egressViaIAP
HH:MM:SS principal://agents.[...]/reasoningEngines/${CONCIERGE_ENGINE_ID} False Agent ${REGISTRY_ID} resources.egressViaIAP
HH:MM:SS principal://agents.[...]/reasoningEngines/${PIZZA_ENGINE_ID} True Endpoint ${REGISTRY_ID} resources.egressViaIAP
第 6 步:动态授予 Pizza Agent 出站访问权限
创建新的 cfg/uap-rules-update-3.json 以包含规则 1(核心 API)、规则 2(汉堡卖家代理)和现在的规则 3(披萨卖家代理)
# create addendum to update policy manifest with Rule 3 for Pizza Agent
cat > cfg/uap-rules-update-3.json << EOF
[
{
"description": "Rule 3: Allow Purchasing Concierge to invoke Pizza Seller Agent via Central Gateway",
"effect": "ALLOW",
"principals": [
"${CONCIERGE_SPIFFE_PRINCIPAL}"
],
"operation": {
"permissions": [
"iap.googleapis.com/resources.egressViaIAP"
]
},
"conditions": {
"iap.googleapis.com": {
"expression": \
"destination.is_registered == true && \
destination.agent_registry.resource_type == 'AGENT' && ( \
destination.agent_registry.agent.name == 'projects/${PROJECT_GOVERNANCE}/locations/${REGION}/agents/pizza-seller-agent' || \
destination.agent_registry.agent.name == 'projects/${PROJECT_GOVERNANCE}/locations/${REGION}/agents/${PIZZA_AGENT_ID}' || \
destination.agent_registry.agent.name == 'projects/${PROJECT_NUMBER_GOVERNANCE}/locations/${REGION}/agents/${PIZZA_AGENT_ID}')"
}
}
}
]
EOF
实时应用政策更新:
# update IAM access policy with Pizza rule
gcloud iam access-policies update ${UAP_POLICY_NAME} \
--add-details-rules=cfg/uap-rules-update-3.json \
--project=${PROJECT_GOVERNANCE} \
--location=global
第 7 步:再次查询 Pizza 代理(立即返回 200 OK 成功响应)
在 Playground 对话窗口中,重新提交披萨订购提示:
I would like 10 BBQ Chicken Pizzas. Place this order now.
如果需要确认回复,请提交以下回复:
Confirmed, please place the order.
或者,通过 Cloud Shell / 终端以编程方式进行测试:
uv run --directory ./cross-project-multiagent python -c "
import vertexai
from vertexai.preview import reasoning_engines
vertexai.init(project='${PROJECT_CONCIERGE}', location='${REGION}')
agent = reasoning_engines.ReasoningEngine('projects/${PROJECT_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}')
response = agent.query(input='I would like 11 Veggie pizzas, please. Place this order now.')
print(response)
"
如果需要确认响应,请使用以下命令:
uv run --directory ./cross-project-multiagent python -c "
import vertexai
from vertexai.preview import reasoning_engines
vertexai.init(project='${PROJECT_CONCIERGE}', location='${REGION}')
agent = reasoning_engines.ReasoningEngine('projects/${PROJECT_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}')
response = agent.query(input='Yes please place the order now.')
print(response['text'])
"
预期响应:
Your order has been placed!
**Order ID:** 8d6c13d7-31dc-4d80-b6a7-80d1e50b6411
**Order Details:**
* 10 x BBQ Chicken Pizza @ IDR 130,000 each = IDR 1,300,000
**Total: IDR 1,300,000**
幕后会发生什么:
- 动态政策刷新:更新 IAM 统一访问权限政策后,IAP 评估引擎会立即生效,无需停机,也无需重新部署任何容器。
- A2A 调用:Concierge 通过中央 Agent Gateway 调度请求。
- IAP v2 政策评估(批准):IAP v2 匹配规则 3,验证调用方身份和目标 CEL 表达式,并返回
ALLOW(granted: true)。 - 跨项目执行:中央 Agent Gateway 将授权的流量代理到
PROJECT_SELLERS,Pizza Seller 在其中处理订单。
第 8 步:检查 Agent Gateway 日志中已获批准的披萨请求
# query Agent Gateway logs for successful 200 OK requests
gcloud logging read "
logName=\"projects/${PROJECT_GOVERNANCE}/logs/networkservices.googleapis.com%2Fgateway_requests\"
AND jsonPayload.authzPolicyInfo.result=\"ALLOWED\"
" \
--project="${PROJECT_GOVERNANCE}" \
--limit=10 \
--format="table(
timestamp.date('%H:%M:%S'):label=TIME,
httpRequest.requestMethod:label=METHOD,
httpRequest.status:label=STATUS,
jsonPayload.authzPolicyInfo.result:label=AUTHZ,
httpRequest.requestUrl:label=URL
)"
授权日志输出示例:
TIME METHOD STATUS AUTHZ URL
HH:MM:SS POST 200 ALLOWED https://us-central1-aiplatform.mtls.googleapis.com/v1beta1/projects/${PROJECT_SELLERS}/locations/us-central1/publishers/google/models/gemini-2.5-flash:generateContent
HH:MM:SS POST 200 ALLOWED https://us-central1-aiplatform.mtls.googleapis.com/v1beta1/projects/${PROJECT_SELLERS}/locations/us-central1/reasoningEngines/${PIZZA_ENGINE_ID}:query
测试和验证到此结束…接下来请前往清理部分。
11. 清理
为避免系统因本 Codelab 中使用的资源向您的 Google Cloud 账号收取费用,请严格按照依赖关系的逆序执行清理步骤:
1. 清理 Reasoning Engine 部署
在两个运行时项目中执行包含的 cleanup_old_deployments.py 脚本,以删除推理引擎并等待其长时间运行的操作:
# delete all Reasoning Engines deployed in Concierge and Sellers projects
uv run --directory ./cross-project-multiagent python cleanup_old_deployments.py --project=${PROJECT_CONCIERGE} --region=${REGION}
uv run --directory ./cross-project-multiagent python cleanup_old_deployments.py --project=${PROJECT_SELLERS} --region=${REGION}
或者,您也可以内嵌列出并删除推理引擎:
uv run --directory ./cross-project-multiagent python -c '
import vertexai
import os
from vertexai.preview import reasoning_engines
region = os.environ.get("REGION", "us-central1")
for proj in [os.environ.get("PROJECT_CONCIERGE"), os.environ.get("PROJECT_SELLERS")]:
if not proj:
continue
print(f"Cleaning reasoning engines in {proj}...")
vertexai.init(project=proj, location=region)
for eng in reasoning_engines.ReasoningEngine.list():
print(f" Deleting {eng.resource_name} ({eng.display_name})...")
eng.delete()
'
2. 删除 Agent Registry 服务
# delete agent registry services in Central Governance Project
for SERVICE in burger-seller-agent pizza-seller-agent purchasing-concierge-adk core-gapi-services; do
gcloud agent-registry services delete ${SERVICE} \
--project=${PROJECT_GOVERNANCE} \
--location=${REGION} \
--quiet || true
done
3. 删除 IAM 统一访问权限政策绑定和访问权限政策
# 1. delete IAM policy binding
gcloud -q iam policy-bindings delete ${UAP_BINDING_NAME} \
--project=${PROJECT_GOVERNANCE} \
--location=global || true
# 2. delete IAM access policy
gcloud -q iam access-policies delete ${UAP_POLICY_NAME} \
--project=${PROJECT_GOVERNANCE} \
--location=global || true
4. 删除智能体网关和安全政策
# 1. delete authorization policy
gcloud beta network-security authz-policies delete ${AGW_NAME}-authz-policy-profile-iap \
--location=${REGION} \
--project=${PROJECT_GOVERNANCE} --quiet || true
# 2. delete authorization extension
gcloud service-extensions authz-extensions delete ${AGW_NAME}-svc-ext-authz-iap \
--location=${REGION} \
--project=${PROJECT_GOVERNANCE} --quiet || true
# 3. delete agent gateway
gcloud network-services agent-gateways delete ${AGW_NAME} \
--project=${PROJECT_GOVERNANCE} \
--location=${REGION} --quiet || true
5. 移除跨项目 IAM 绑定和自定义角色
# 1. remove custom role and network viewer bindings for spoke service agents
for NUM in "${PROJECT_NUMBER_CONCIERGE}" "${PROJECT_NUMBER_SELLERS}"; do
SA="service-${NUM}@gcp-sa-aiplatform.iam.gserviceaccount.com"
gcloud projects remove-iam-policy-binding ${PROJECT_GOVERNANCE} \
--member="serviceAccount:${SA}" \
--role="projects/${PROJECT_GOVERNANCE}/roles/ar_agw_cross_project_sa" --quiet || true
gcloud projects remove-iam-policy-binding ${PROJECT_GOVERNANCE} \
--member="serviceAccount:${SA}" \
--role="roles/networkservices.viewer" --quiet || true
done
# 2. remove registry viewer permissions across both spoke projects
for NUM in "${PROJECT_NUMBER_CONCIERGE}" "${PROJECT_NUMBER_SELLERS}"; do
for MEMBER in \
"serviceAccount:service-${NUM}@gcp-sa-aiplatform.iam.gserviceaccount.com" \
"serviceAccount:service-${NUM}@gcp-sa-aiplatform-re.iam.gserviceaccount.com" \
"serviceAccount:${NUM}-compute@developer.gserviceaccount.com" \
"principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${NUM}"; do
gcloud projects remove-iam-policy-binding ${PROJECT_GOVERNANCE} \
--member="${MEMBER}" \
--role="roles/agentregistry.viewer" --quiet || true
done
done
# 3. remove project viewer permissions
for MEMBER in \
"serviceAccount:${PROJECT_NUMBER_CONCIERGE}-compute@developer.gserviceaccount.com" \
"serviceAccount:service-${PROJECT_NUMBER_CONCIERGE}@gcp-sa-aiplatform.iam.gserviceaccount.com"; do
gcloud projects remove-iam-policy-binding ${PROJECT_GOVERNANCE} \
--member="${MEMBER}" \
--role="roles/viewer" --quiet || true
done
# 4. remove spoke-to-spoke delegation in Sellers project
for MEMBER in \
"serviceAccount:service-${PROJECT_NUMBER_CONCIERGE}@gcp-sa-aiplatform.iam.gserviceaccount.com" \
"serviceAccount:service-${PROJECT_NUMBER_CONCIERGE}@gcp-sa-aiplatform-re.iam.gserviceaccount.com" \
"serviceAccount:${PROJECT_NUMBER_CONCIERGE}-compute@developer.gserviceaccount.com" \
"principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJECT_NUMBER_CONCIERGE}"; do
gcloud projects remove-iam-policy-binding ${PROJECT_SELLERS} \
--member="${MEMBER}" \
--role="roles/aiplatform.user" --quiet || true
done
# 5. delete custom IAM role after all bindings have been unlinked
gcloud iam roles delete ar_agw_cross_project_sa \
--project=${PROJECT_GOVERNANCE} --quiet || true
如果您在设置阶段分配了 roles/iam.accessPolicyAdmin 和 roles/resourcemanager.projectIamAdmin,请从活跃用户账号中移除这些权限,以恢复最小权限:
# 6. remove Access Policy Admin and Project IAM Admin roles from user
for ROLE in "roles/iam.accessPolicyAdmin" "roles/resourcemanager.projectIamAdmin"; do
gcloud projects remove-iam-policy-binding ${PROJECT_GOVERNANCE} \
--member="user:$(gcloud config get-value account)" \
--role="${ROLE}" \
--condition=None --quiet || true
done
6. 恢复了审核数据日志记录和组织政策限制条件
# 1. Export current Central Governance IAM policy
gcloud projects get-iam-policy ${PROJECT_GOVERNANCE} --format=json > cfg/gov_iam_policy.json
# 2. Filter out iap.googleapis.com from auditConfigs
python3 -c "
import json
with open('cfg/gov_iam_policy.json') as f:
policy = json.load(f)
if 'auditConfigs' in policy:
# Remove iap.googleapis.com; if nothing else remains, clear the list
policy['auditConfigs'] = [
ac for ac in policy['auditConfigs'] if ac.get('service') != 'iap.googleapis.com'
]
with open('cfg/gov_iam_policy.json', 'w') as f:
json.dump(policy, f, indent=2)
"
# 3. Apply the updated policy to revert audit logging to default
gcloud projects set-iam-policy ${PROJECT_GOVERNANCE} cfg/gov_iam_policy.json
7. 还原组织政策限制条件
# revert iam v3 access policy binding org policy on project to org level setting
gcloud org-policies delete iam.managed.disableAccessPolicyBinding --project=${PROJECT_GOVERNANCE}
8. 删除共享 GCS 暂存存储桶和本地制品
# delete central staging bucket
gcloud storage rm -r gs://${PROJECT_GOVERNANCE}-shared-staging
# remove local configuration manifests, environment files, and application
rm -rf cfg/ cross-project-multiagent/ *.env
清理部分到此结束…接下来是总结!
12. 总结
恭喜!您已使用 Vertex AI Agent Runtime、中央 Agent Gateway、Agent Registry 和 IAM Unified Access Policies (UAP) 在 Google Cloud 上部署并管理多项目 Agent-to-Agent (A2A) 架构。
关键概念总结
- 集中式出站流量边界:通过
PROJECT_GOVERNANCE中使用agentGatewayConfig的中央 Agent Gateway 路由辐条运行时容器(PROJECT_CONCIERGE、PROJECT_SELLERS)。 - 声明式治理 (UAP):使用单个可审核的 IAM 访问政策替换了分散的按资源绑定,该政策由 IAP v2 在网关处进行评估。
- 加密身份:使用容器 SPIFFE 身份 (
principal://...) 而不是长期有效的密钥来强制执行最低权限出站流量。 - 动态服务发现:通过中央 Agent Registry 在运行时解析对等 Agent Endpoint,从而无需对网址和项目 ID 进行硬编码。
- 运行时政策灵活性:通过政策更新,将
pizza-seller-agent从“默认拒绝”(403 Forbidden) 实时过渡到“允许”(200 OK),且无需重启容器。

Cosmopup 说:“代理太棒了,他们负责所有跨项目工作,而我则专注于我的主要目标:打盹!”