1. Introducción
A medida que las organizaciones empresariales adoptan la IA generativa, las arquitecturas evolucionan rápidamente de chatbots monolíticos independientes a sistemas multiagente distribuidos (agente a agente o A2A). En estas topologías modernas, los agentes orquestadores de alto nivel coordinan flujos de trabajo empresariales complejos delegando tareas a agentes trabajadores de dominio especializados, servidores de herramientas del Protocolo de contexto del modelo (MCP) y bases de datos empresariales de backend en proyectos independientes de Google Cloud.
Sin embargo, operar sistemas multiagente a gran escala plantea desafíos críticos de seguridad, administración y operación:
- Proliferación de agentes y herramientas no oficiales: Cuando los equipos de desarrollo implementan agentes en proyectos aislados sin un catálogo centralizado, las organizaciones pierden visibilidad sobre qué herramientas y subagentes existen.
- Salida entre proyectos sin supervisión: Permitir que los agentes tengan rutas de red directas y sin inspeccionar crea riesgos de robo de datos y omite los perímetros de seguridad.
- Integraciones codificadas de forma rígida y frágiles: La codificación de forma rígida de las URLs de los agentes de nivel inferior y los IDs de Reasoning Engine crea dependencias frágiles que se interrumpen durante las actualizaciones o los reenvíos.
- Falta de identidad con privilegios mínimos: Las cuentas de servicio compartidas no proporcionan un no repudio criptográfico a nivel de la instancia del agente individual.
Para resolver estos desafíos, la plataforma de agentes de Gemini Enterprise proporciona un plano de control unificado de administración y conectividad compuesto por cuatro pilares fundamentales:
- Agent Gateway (
networkservices.googleapis.com): Es un proxy administrado de aplicación de políticas y de red regional. Cuando opera en el modo de salidaAGENT_TO_ANYWHERE, intercepta el tráfico saliente del agente, delega las evaluaciones de autorización a las extensiones de seguridad y enruta las solicitudes a través de los perímetros del proyecto. - Agent Registry (
agentregistry.googleapis.com): Es el catálogo de servicios empresariales único. Proporciona un directorio centralizado y verificado de todas las herramientas, servidores de MCP y agentes pares disponibles en toda la organización, lo que permite el autodescubrimiento dinámico en el tiempo de ejecución sin extremos codificados. - Gobernanza de la identidad del agente y de IAP v2 (
iap.googleapis.comyiam.googleapis.com): Un marco criptográfico de identidad y acceso. Los agentes de ejecución reciben URN de máquina SPIFFE únicas y certificadas (principal://...). El tráfico de salida se evalúa en función de las políticas de acceso unificado de IAM (UAP / IAP v2) centralizadas que verifican el permiso universaliap.googleapis.com/resources.egressViaIAPcon condiciones enriquecidas del catálogo de Common Expression Language (CEL) (destination.agent_registry.*). - Agent Runtime (motores de razonamiento): Es una plataforma de ejecución sin servidores completamente administrada para aplicaciones basadas en agentes de Python que incluye vinculaciones de configuración nativas (
agent_gateway_config) a las puertas de enlace centrales.
Situación empresarial del codelab: Compra de alimentos y bebidas en varios proyectos
En este codelab, compilarás y administrarás un ecosistema de compras de varios proyectos del mundo real que abarca tres proyectos distintos de Google Cloud:
- Proyecto de administración central (
PROJECT_GOVERNANCE): Es propiedad de TI central y SecOps, y aloja Central Agent Gateway, Central Agent Registry y las políticas de acceso unificadas de IAM. - Proyecto del orquestador de consumidores (
PROJECT_CONCIERGE): Es propiedad del equipo de adquisiciones y aloja el agente de Concierge de compras, que descubre proveedores de forma dinámica y enruta los pedidos de los clientes. - Proyecto de proveedor de dominio (
PROJECT_SELLERS): Es propiedad de proveedores externos o departamentales, y aloja los agentes Burger Seller Agent y Pizza Seller Agent.
Fig. 1: Arquitectura de administración centralizada de varios proyectos
¿Por qué la administración centralizada entre proyectos?
En las grandes organizaciones empresariales, los equipos de productos y los grupos de ciencia de datos crean agentes de IA en decenas de proyectos independientes de Google Cloud. Darle a cada equipo control directo sobre el registro de herramientas, las rutas de red de salida y las medidas de seguridad crea una proliferación de herramientas no verificadas, políticas de DLP incoherentes, salida de VPC no supervisada y registros de auditoría fragmentados.
La administración centralizada entre proyectos separa la creación de políticas de la ejecución de agentes:
- El equipo central de TI y Operaciones de seguridad crea políticas de seguridad, verifica herramientas y supervisa el tráfico de salida dentro de un solo Proyecto de gobernanza centralizada.
- Los equipos de productos y aplicaciones se enfocan exclusivamente en la lógica empresarial en sus proyectos de tiempo de ejecución de agentes independientes, y se vinculan directamente a la puerta de enlace central sin la sobrecarga operativa de administrar VPCs locales, interconexiones o motores de políticas fragmentados.
Fig. 2: Arquitectura y límites de administración entre proyectos de tres niveles
Modelo de alcance de identidad de dos niveles en las políticas de acceso unificado
Cuando los agentes se comunican a través de Central Agent Gateway, Identity-Aware Proxy (IAP v2) evalúa el acceso según la identidad del agente del llamador (una identidad basada en SPIFFE y certificada de forma criptográfica que se emite automáticamente al contenedor de tiempo de ejecución) en comparación con una política de acceso global de IAM:
- Nivel 1: APIs de Google Cloud básicas (gruesas a través de
principalSet://en la regla 1): Autorización de salida para todo el proyecto que permite que todos los tiempos de ejecución del agente en los proyectos radiales lleguen a las APIs de Google estándar (aiplatform,iamcredentials,telemetry,agentregistry) para la detección, la generación de tokens y la inferencia. - Nivel 2: Herramientas empresariales y servicios de A2A (detallados a través de
principal://en las reglas 2 y 3): Acceso estricto con privilegios mínimos vinculado a instancias individuales de Reasoning Engine, que se aplica con condiciones de Common Expression Language (CEL) dirigidas a servicios específicos registrados de Agent Registry (destination.agent_registry.agent.name).
Qué compilarás
- Agent Gateway centralizado (
centralized-agw) enPROJECT_GOVERNANCE - Extensión del servicio de autorización de IAP v2 y política de autorización en modo STRICT de ENFORCE (
failOpen: false) - Política de acceso unificado de IAM fundamental (
uap-rules.json) y vinculación de política del proyecto - Permisos de IAM de agentes de servicio entre proyectos (
ar_agw_cross_project_sa) - Bucket de etapa de pruebas central compartido de Google Cloud Storage (GCS)
- Agentes de venta de hamburguesas y pizzas aislados en
PROJECT_SELLERS - Agente de Concierge de compras con detección automática dinámica de REST en
PROJECT_CONCIERGE - Registros de servicios en Central Agent Registry con URLs de mTLS entre proyectos
- Actualizaciones dinámicas de la política de salida de IAP v2 con verificación en vivo y auditorías de Cloud Logging
Fig. 3: Secuencia de implementación paso a paso
Qué aprenderá
- Cómo configurar permisos de IAM de agentes de servicio entre proyectos para puertas de enlace centralizadas
- Cómo enrutar la salida de Agent Runtime a través de un Agent Gateway central en entornos de varios proyectos
- Cómo delegar la autorización de Agent Gateway a Identity-Aware Proxy (IAP v2) con Service Extensions (
iapPolicyVersion: "V2") - Cómo crear y vincular políticas de acceso unificadas (UAP) de IAM con reglas de Common Expression Language (CEL) que rigen los destinos registrados de Agent Registry (
destination.agent_registry.*) - Cómo eliminar los IDs y las URLs de agentes codificados de forma rígida con el descubrimiento automático en tiempo de ejecución en Agent Registry
- Cómo probar el bloqueo de confianza cero del perímetro real (
HTTP 403 Forbidden) y verificar las actualizaciones de políticas en tiempo real en Cloud Logging
Requisitos
- 3 proyectos de Google Cloud con la facturación habilitada:
PROJECT_GOVERNANCE: Políticas de IAM, registro, puerta de enlace y administración centralPROJECT_CONCIERGE: Agente organizador de conserjería de comprasPROJECT_SELLERS: Agentes de ventas especialistas en hamburguesas y pizzas
- Una cuenta de servicio o usuario de IAM con permisos de
roles/ownero permisos administrativos en los 3 proyectos - Una organización de Google Cloud (para la asignación del dominio de confianza de SPIFFE)
- Google Cloud Shell o una máquina local con la CLI de
gcloud,python(3.11 o versiones posteriores) yuvinstalados
Con esto, concluye la parte de la introducción. A continuación, se abordará la sección Configuración y entorno.
2. Configuración
Si bien esta arquitectura abarca 3 proyectos distintos de Google Cloud, puedes ejecutar el 100% de los comandos de implementación de la terminal, las descargas del repositorio y las operaciones de etapa de pruebas desde una sola terminal de Cloud Shell configurada en PROJECT_GOVERNANCE. Cada secuencia de comandos de implementación y comando de gcloud apunta de forma explícita al proyecto de destino adecuado a través de marcas de la CLI (--project).
Para comenzar, accede a la línea de comandos de tu proyecto de Google Cloud:
- Cloud Shell en
shell.cloud.google.com - Una terminal local con la CLI de
gcloudinstalada
Establece el contexto de tu proyecto
# 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
Actualiza la CLI de gcloud (recomendado)
# update gcloud components
gcloud components update --quiet
Establece variables de entorno de shell
Ingresa los identificadores específicos de tu proyecto.
# 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"
Estas variables de shell se derivarán automáticamente.
# 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}"
Crea un directorio local para los archivos de configuración
# create config folder
mkdir -p cfg
Asigna el rol de administrador de políticas de acceso para las políticas de acceso unificado
# 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
Habilita los registros de auditoría de acceso a los datos de Cloud para IAP v2
De forma predeterminada, Google Cloud inhabilita los registros de auditoría de acceso a los datos para evitar costos de almacenamiento no deseados. Dado que IAP v2 emite decisiones de autorización (granted=true y granted=false) como registros de auditoría de acceso a los datos, habilita el registro de ADMIN_READ, DATA_READ y DATA_WRITE para iap.googleapis.com en PROJECT_GOVERNANCE:
# 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)"
Habilita las APIs de Google Cloud requeridas
# 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
Valida la habilitación de la API en todos los proyectos
Asegurarse de que los tres proyectos (PROJECT_GOVERNANCE, PROJECT_CONCIERGE y PROJECT_SELLERS) tengan habilitadas exactamente las mismas APIs establece la coherencia operativa y evita errores en la generación de tokens durante el tiempo de ejecución, errores en la catalogación de esquemas o pérdidas de telemetría.
Ejecuta la siguiente secuencia de comandos de validación en Cloud Shell para verificar la paridad de la API en los tres proyectos:
# 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
Ejemplo de resultado de validación:
Deberías ver todas las APIs habilitadas.
✅ All 30 required APIs are ENABLED and synchronized across all three projects.
Configura las políticas de la organización
Las políticas de la organización predeterminadas de Google Cloud aplican restricciones que limitan las vinculaciones de políticas de acceso de IAM v3 a los recursos (constraints/iam.managed.disableAccessPolicyBinding).
Anula cualquier restricción de política de la organización heredada a nivel del proyecto estableciendo explícitamente enforce: false como permitir.
# 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
Con esto, concluye la parte de configuración. A continuación, se encuentra la sección Register Core Google APIs.
3. Agent Registry
Registra el servicio de extremos de las APIs principales de Google
Agent Gateway requiere que las URLs de las APIs de Google se registren en el Registro central de agentes para que los agentes configurados con agent_gateway_config puedan enrutar el tráfico de salida de forma segura a los servicios de backend principales de Google Cloud (como aiplatform, las credenciales de IAM y la telemetría).
Crea core-gapi-services en Agent Registry
# 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
Captura el ID del recurso del extremo de las APIs de Capture Core
# 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}"
Información sobre principalSet y principal en la identidad del agente
En Google Cloud IAM y la plataforma de agentes de Gemini Enterprise, las identidades de máquinas emitidas para los contenedores de agentes en ejecución usan URN de SPIFFE con certificación criptográfica que evalúa Identity-Aware Proxy (IAP v2). Cuando configuras políticas de acceso unificado de IAM, puedes segmentar la política para un solo principal específico o un principalSet basado en atributos:
Dimensión |
|
|
Sintaxis de IAM |
|
|
Nivel de detalle | Detallado (a nivel de la instancia): Identifica una sola instancia específica del contenedor de Reasoning Engine. | Gruesa (a nivel del proyecto): Identifica todos los motores de razonamiento que comparten un atributo de proyecto común. |
Patrón de URN |
|
|
Caso de uso en Agent Platform | Nivel 2 (Herramientas empresariales y A2A): Autoriza a agentes de orquestación específicos para invocar herramientas de dominio objetivo (p.ej., Concierge de compras $\rightarrow$ Vendedor de hamburguesas). | Nivel 1 (infraestructura fundamental): Se otorga a todos los agentes de un proyecto acceso de salida a las APIs de Google Cloud ( |
Impacto en el ciclo de vida | Si se borra y se vuelve a crear un agente, su nuevo ID de Engine requiere una vinculación de política de IAM actualizada. | Se aplica automáticamente a los agentes implementados recientemente en ese proyecto sin actualizaciones adicionales de IAM. |
Administración declarativa con políticas de acceso unificado (UAP / IAP v2)
En la versión heredada de IAP v1, las políticas de salida se adjuntaban directamente a los recursos individuales de Agent Registry con gcloud beta iap web add-iam-policy-binding. En IAP v2 y políticas de acceso unificado, las vinculaciones por recurso se eliminan en favor de una política de acceso de IAM única y centralizada (cfg/uap-rules.json).
La autorización de salida fundamental para core-gapi-services se configurará como Regla 1 en la política de acceso unificada de la sección 5, lo que garantiza que todos los contenedores de agentes tengan rutas de salida fundamentales establecidas antes de la implementación.
Para obtener detalles técnicos más profundos sobre los identificadores principales y los mecanismos de identidad de cargas de trabajo, consulta los siguientes recursos:
- Google Cloud IAM: Principal Identifiers & Principal Sets (Google Cloud IAM: Identificadores principales y conjuntos de principales)
- Cómo funciona la identidad del agente
- Configura políticas de acceso unificado de IAM para Agent Gateway
Con esto, finaliza el registro del endpoint de las APIs principales. A continuación, consulta la sección Implementa Centralized Agent Gateway.
4. Agent Gateway
Implementa Centralized Agent Gateway
Implementa el Agent Gateway centralizado (centralized-agw) en el modo de salida AGENT_TO_ANYWHERE dentro del proyecto $PROJECT_GOVERNANCE.
Define el manifiesto de configuración de la puerta de enlace
Crea cfg/${AGW_NAME}.yaml para la administración del tráfico de salida:
# 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
Importa la configuración de 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}
Verifica los detalles de Agent Gateway
# show agent gateway status
gcloud network-services agent-gateways describe ${AGW_NAME} \
--location=${REGION} \
--project=${PROJECT_GOVERNANCE}
Resultado de muestra:
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'
Con esto, se completa la implementación de la puerta de enlace. A continuación, consulta la sección Configura la autorización.
5. Autorización
Configura la autorización de Agent Gateway y la UAP fundamental
Agent Gateway protege y administra el tráfico saliente de herramientas y agentes con políticas de autorización (networksecurity.authzPolicies) integradas en las políticas de acceso unificado (UAP) de Identity-Aware Proxy (IAP v2).
Descripción general de la arquitectura de autorización
Fig. 4: Descripción general de la arquitectura de autorización
La arquitectura de autorización se compone de tres capas interconectadas:
- Extensión de servicio de IAP (
authzExtension): Es un recurso regional configurado conservice: iap.googleapis.com,metadata: iapPolicyVersion: "V2"yfailOpen: falsepara la aplicación estricta de la confianza cero en el perímetro. - Política de autorización de Agent Gateway (
authzPolicy): Es un recurso regional que segmenta tu Agent Gateway conpolicyProfile: REQUEST_AUTHZyaction: CUSTOM, y enruta las verificaciones de autorización a la extensión de autorización de IAP. - IAM Unified Access Policy & Binding (
accessPolicyypolicyBinding): Es un recurso global de IAM v3 que evalúa IAP. Verifica el permiso universaliap.googleapis.com/resources.egressViaIAPen relación con las identidades SPIFFE del llamador y las condiciones del catálogo de CEL.
Paso 1: Crea e importa la extensión de autorización de IAP v2
Crea el manifiesto de la extensión de servicio con iapPolicyVersion: "V2" y failOpen: false en modo ENFORCE estricto:
# 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
Importa la extensión de autorización:
# 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}
Verifica que la extensión de Authz esté activa:
# describe authz extension
gcloud service-extensions authz-extensions describe ${AGW_NAME}-svc-ext-authz-iap \
--location=${REGION} \
--project=${PROJECT_GOVERNANCE}
Resultado de muestra:
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
Paso 2: Crea e importa la política de autorización de Gateway
Crea una configuración de política de autorización que se adjunte al Agent Gateway y delegue la verificación de solicitudes en la extensión de Authz de IAP:
# 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
Importa la política de autorización:
# 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}
Verifica la política de autorización activa:
# describe authz policy
gcloud beta network-security authz-policies describe ${AGW_NAME}-authz-policy-profile-iap \
--location=${REGION} \
--project=${PROJECT_GOVERNANCE}
Paso 3: Crea la política de acceso unificado inicial (regla 1: APIs principales de Google)
Crea cfg/uap-rules.json con la regla 1 que autoriza a los tres principalSet del proyecto a llegar a 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
Paso 4: Crea y vincula la política de acceso de IAM
Crea la política de acceso de IAM global:
# create global IAM access policy
gcloud iam access-policies create ${UAP_POLICY_NAME} \
--details-rules=cfg/uap-rules.json \
--project=${PROJECT_GOVERNANCE} \
--location=global
Vincula la política de acceso a 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
Verifica que la vinculación de políticas esté activa:
# verify policy binding
gcloud iam policy-bindings describe ${UAP_BINDING_NAME} \
--project=${PROJECT_GOVERNANCE} \
--location=global
Resultado de muestra:
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}
El tráfico de salida de la API fundamental de Google Cloud ahora está autorizado de forma segura en los tres proyectos en modo ENFORCE estricto.
Con esto, se completa la configuración de la autorización de la puerta de enlace. A continuación, consulta la sección Configura permisos de IAM entre proyectos.
6. IAM entre proyectos
Configura los permisos de IAM entre proyectos
En esta topología de varios proyectos, los Agent Runtimes residen en proyectos radiales (PROJECT_CONCIERGE y PROJECT_SELLERS), mientras que el Agent Registry y el Central Agent Gateway residen en PROJECT_GOVERNANCE.
Dado que los proyectos de Google Cloud son perímetros de seguridad aislados, el acceso entre proyectos debe otorgarse de forma explícita en dos capas operativas:
- Plano de control (tiempo de implementación): Cuando se implementa un contenedor de agente configurado con
--agent-gateway-config, el agente de servicio de Agent Runtime (service-) del proyecto de radio debe adjuntar el contenedor a la puerta de enlace central. Creamos un rol personalizado mínimo (@gcp-sa-aiplatform.iam.gserviceaccount.com ar_agw_cross_project_sa) que otorganetworkservices.agentGateways.use,getyoperations.getenPROJECT_GOVERNANCE. - Plano de datos (ejecución del tiempo de ejecución):
- Descubrimiento de catálogo: Las identidades de los radios necesitan
roles/agentregistry.viewerenPROJECT_GOVERNANCEpara resolver los extremos del agente objetivo de forma dinámica. - Invocación de destino: El agente de Concierge necesita
roles/aiplatform.userenPROJECT_SELLERSpara ejecutar consultas en los motores de razonamiento del vendedor.
- Descubrimiento de catálogo: Las identidades de los radios necesitan
Crea un rol de IAM personalizado en PROJECT_GOVERNANCE
# 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"
Asigna un rol personalizado a los agentes de servicio de 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
Con esto, se completa la configuración de IAM entre proyectos. A continuación, ve a la sección Implementa agentes de vendedor y asistente.
7. Agent Runtime
Implementa agentes de vendedores y asistentes
El código base de la aplicación de varios agentes y los secuencias de comandos de implementación que se usan para este codelab se mantienen en un repositorio de GitHub de Google Cloud remoto. En los siguientes pasos, se clonará el repositorio de forma local, se copiarán los archivos necesarios en la estructura del directorio de trabajo actual, se limpiarán los archivos temporales y se instalarán las dependencias con uv.
Recupera artefactos remotos
# 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
Crea un bucket central de etapa de pruebas compartido
# 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"
Cómo funciona la vinculación de Agent Gateway entre proyectos
En este paso, implementarás los agentes de vendedor en el proyecto radial (PROJECT_SELLERS) y los configurarás para que enruten el tráfico de salida a través del Agent Gateway central en PROJECT_GOVERNANCE:
# !-- 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)
Dado que la Regla 1 se estableció anteriormente en nuestra Política de acceso unificada, las solicitudes de inicialización de contenedores a las APIs de Google Cloud se permiten a través de la puerta de enlace sin interrupciones.
Implementa agentes de venta de hamburguesas y pizzas en 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}
Valida el enrutamiento de Seller Gateway
# 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
Implementa el agente de asistente de compras en 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}
Valida el enrutamiento de la puerta de enlace de compras
# 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}'
El resultado debería mostrar la identidad y el proyecto del tiempo de ejecución del agente de Concierge, y la vinculación a la Agent Gateway del proyecto de Gobernanza.
{
"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"
}
}
}
Con esto, se completan las implementaciones de agentes. A continuación, se abordará la sección Register Agents in Central Agent Registry.
8. Registro multiproyecto
Cómo registrar agentes en el registro central de agentes
Registra los tres agentes en el Agent Registry central en PROJECT_GOVERNANCE con extremos de mTLS regionales entre proyectos y números de proyectos numéricos.
Registra servicios como agentes que no son de A2A en Agent Registry
# 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
Captura los IDs subyacentes de Agent Registry
# 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}"
Con esto, se completa la configuración del registro. A continuación, se abordará la sección Configure A2A Egress Policies.
9. Políticas de la UAP
Configura políticas de salida de A2A en la política de acceso unificado
En la arquitectura de rechazo predeterminado de Agent Gateway en el modo ENFORCE estricto, se aplican las siguientes reglas:
- Regla 1 (APIs de Google Cloud de referencia): Permite que los contenedores de agentes de los 3 proyectos lleguen a
core-gapi-services. - Regla 2 (agente de Burger Seller: ALLOW): Permite que la instancia del agente de Purchasing Concierge invoque específicamente al agente de Burger Seller.
- Agente de vendedor de pizza (DENIED by Default): Se omitió intencionalmente de las reglas de la política. En el modo
ENFORCE(failOpen: false), cualquier intento del asistente para invocar al vendedor de pizzas se finalizará de inmediato en el perímetro de la puerta de enlace conHTTP 403 Forbidden.
Formula la identidad del agente de Concierge
# 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}"
Actualiza el manifiesto con las reglas 1 y 2
Crea un nuevo cfg/uap-rules-update-2.json para incluir la regla 1 (APIs principales) y ahora la regla 2 (agente de Burger Seller):
# 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
Aplica la política de acceso actualizada
# 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
Verifica los detalles de la política de acceso de IAM
# inspect updated access policy
gcloud iam access-policies describe ${UAP_POLICY_NAME} \
--project=${PROJECT_GOVERNANCE} \
--location=global
Resultado de muestra:
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
Con esto, se completa la configuración de la política. A continuación, consulta la sección Prueba y verifica las políticas de gobierno.
10. Verifica las políticas
Prueba y verifica las políticas de gobierno a través de Cloud Logging
En esta sección, probarás las interacciones entre proyectos de Agent-to-Agent (A2A) en Agent Runtime AI Playground, observarás el bloqueo perimetral HTTP 403 Forbidden en tiempo real en el modo ENFORCE estricto, modificarás la política de acceso unificada en vivo y validarás la aprobación inmediata de pedidos.
Paso 1: Abre la zona de pruebas de IA de Agent Runtime en PROJECT_CONCIERGE
- Abre la consola de Google Cloud.
- En la barra superior del selector de proyectos, cambia a
PROJECT_CONCIERGE. - En el menú de navegación, ve a Agent Platform > Agents > Deployments.
- Haz clic en
purchasing-concierge-adk. - Selecciona Playground para abrir la interfaz de chat interactiva en el lado derecho de la pantalla.
Paso 2: Prueba el pedido de hamburguesa (coincidencia de la regla 2 -> 200 OK)
En la ventana de chat de Playground, envía la siguiente instrucción de pedido:
I would like 10 Classic Cheeseburgers. Place this order now.
Y si se necesita una respuesta de confirmación, envía la siguiente respuesta:
Confirmed, please place the order.
Como alternativa, puedes probar el programa de forma programática desde Cloud Shell o la terminal:
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)
"
Y, si se necesita una respuesta de confirmación, usa este comando:
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'])
"
Qué sucede tras bambalinas:
- Descubrimiento dinámico: Durante el inicio de la sesión, el Concierge de compras consultó el Agent Registry central en
PROJECT_GOVERNANCE(a través decore-gapi-servicesa través de Agent Gateway autorizado por la regla 1) para descubrir el extremo de mTLS regional paraburger-seller-agent. - Resolución de la intención y llamada a A2A: Gemini dentro del asistente de compras analiza la intención del pedido de comida y llama al agente de Burger Seller a través de una RPC saliente a
https://${REGION}-aiplatform.mtls.googleapis.com/.../reasoningEngines/${BURGER_ENGINE_ID}. - Intercepción de Agent Gateway y propagación de SPIFFE:
agent_gateway_configcaptura el tráfico de salida y lo dirige al Agent Gateway central enPROJECT_GOVERNANCE, que lleva la identidad criptográfica de SPIFFE de Concierge (principal://...). - Evaluación de la política de IAP v2: La puerta de enlace del agente central invoca la extensión de autorización de IAP (
authzExtension). La IAP v2 evalúa la regla 2 en la política de acceso unificada de IAM. Dado que la persona que llama coincide con${CONCIERGE_SPIFFE_PRINCIPAL}y el destino coincide conburger-seller-agent, IAP devuelveALLOW(granted: true). - Ejecución entre proyectos: El Agent Gateway reenvía la solicitud autorizada entre proyectos a
PROJECT_SELLERS, donde el motor de razonamiento de Burger Seller procesa el pedido y devuelve la confirmación.
Respuesta esperada:
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
Paso 3: Inspecciona los registros de auditoría de Agent Gateway y de IAP v2 (HTTP 200 / ALLOWED)
Registros de solicitudes de Agent Gateway de consultas en PROJECT_GOVERNANCE:
# 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
)"
Los registros deben capturar el tráfico saliente que se origina en ambos proyectos radiales (PROJECT_CONCIERGE y PROJECT_SELLERS) con campos de salida para las llamadas de razonamiento de Gemini (generateContent), la telemetría de Cloud Trace (/v1/traces) y las búsquedas de credenciales de IAM, que la regla 1 intercepta y autoriza de forma transparente (core-gapi-services).
Consulta los registros de auditoría de acceso a los datos de Cloud Audit Logging de IAP v2 para verificar la versión de la política 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
)"
Resultado de muestra:
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
Paso 4: Prueba el pedido de pizza (rechazo predeterminado -> HTTP 403 prohibido FORZADO)
En la misma ventana de chat de Playground, envía la siguiente instrucción de pedido de pizza:
I would like 10 BBQ Chicken Pizzas. Place this order now.
Y si se necesita una respuesta de confirmación, envía la siguiente respuesta:
Confirmed, please place the order.
Como alternativa, puedes probar el programa de forma programática desde Cloud Shell o la terminal:
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)
"
Y, si se necesita una respuesta de confirmación, usa este comando:
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'])
"
Respuesta esperada:
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.
Qué sucede tras bambalinas:
- Descubrimiento dinámico: El Concierge de compras resolvió el extremo
pizza-seller-agentdel Agent Registry central durante el inicio. - Resolución de la intención y la invocación de A2A: Gemini dentro del Concierge de compras intenta enviar la solicitud de pedido de pizza al extremo del vendedor de pizzas en
PROJECT_SELLERS. - Intercepción de Agent Gateway:
agent_gateway_configcaptura la RPC saliente y la dirige al Agent Gateway central. - Evaluación de políticas de IAP v2 (rechazo predeterminado): Central Agent Gateway invoca IAP v2. Dado que no existe ninguna regla en la política de acceso unificado que coincida con
pizza-seller-agent, IAP devuelveDENY(granted: false). - Bloqueo de perímetro estricto: Debido a que la extensión de autorización está en modo de aplicación forzosa (
failOpen: false), el Agent Gateway central finaliza de inmediato la conexión saliente y devuelveHTTP 403 Forbidden. El tráfico nunca sale de la puerta de enlace y nunca llega aPROJECT_SELLERS.
Paso 5: Inspecciona los registros de Agent Gateway para ver las solicitudes bloqueadas (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
)"
Ejemplo de registro de salida rechazado:
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
Consulta los registros de auditoría de acceso a los datos de IAP v2 para la decisión rechazada:
# 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
)"
Ejemplo de salida del registro de auditoría de política denegada:
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
Paso 6: Otorga acceso de salida de forma dinámica al agente de Pizza
Crea un nuevo cfg/uap-rules-update-3.json para incluir la regla 1 (APIs principales), la regla 2 (agente de vendedor de hamburguesas) y ahora la regla 3 (agente de vendedor de pizzas).
# 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
Aplica la actualización de la política en vivo:
# 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
Paso 7: Vuelve a consultar al agente de pizzas (éxito inmediato con código 200 OK)
En la ventana de chat de Playground, vuelve a enviar la instrucción del pedido de pizza:
I would like 10 BBQ Chicken Pizzas. Place this order now.
Y si se necesita una respuesta de confirmación, envía la siguiente respuesta:
Confirmed, please place the order.
Como alternativa, puedes probar el programa de forma programática desde Cloud Shell o la terminal:
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)
"
Y, si se necesita una respuesta de confirmación, usa este comando:
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'])
"
Respuesta esperada:
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**
Qué sucede tras bambalinas:
- Actualización dinámica de políticas: La actualización de la política de acceso unificada de IAM se aplica de inmediato en el motor de evaluación de IAP sin tiempo de inactividad y sin volver a implementar ningún contenedor.
- Invocación de A2A: El asistente personal envía la solicitud a través de Central Agent Gateway.
- Evaluación de la política de IAP v2 (aprobación): La IAP v2 coincide con la regla 3, verifica la identidad del llamador y la expresión CEL de destino, y devuelve
ALLOW(granted: true). - Ejecución entre proyectos: Central Agent Gateway reenvía el tráfico autorizado a
PROJECT_SELLERS, donde Pizza Seller procesa el pedido.
Paso 8: Inspecciona los registros de Agent Gateway para ver las solicitudes de pizza aprobadas
# 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
)"
Ejemplo de registro de salida de concesión:
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
Con esto, se completan las pruebas y la verificación. A continuación, se muestra la sección Limpieza.
11. Limpieza
Para evitar que se generen cargos en tu cuenta de Google Cloud por los recursos que se usaron en este Codelab, ejecuta los pasos de desmantelamiento en orden inverso estricto de dependencia:
1. Limpia las implementaciones de Reasoning Engine
Ejecuta la secuencia de comandos cleanup_old_deployments.py incluida en ambos proyectos de entorno de ejecución para borrar los motores de razonamiento y esperar sus operaciones de larga duración:
# 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}
Como alternativa, puedes enumerar y borrar motores de razonamiento intercalados:
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. Borra los servicios de 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. Borra la vinculación de la política de acceso unificado de IAM y la política de acceso
# 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. Borra Agent Gateway y las políticas de seguridad
# 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. Quita las vinculaciones de IAM entre proyectos y el rol personalizado
# 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
Si asignaste roles/iam.accessPolicyAdmin y roles/resourcemanager.projectIamAdmin durante la fase de configuración, quítalos de tu cuenta de usuario activa para restablecer el principio de privilegio mínimo:
# 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. Revierte el registro de datos de auditoría y las restricciones de políticas de la organización
# 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. Cómo revertir las restricciones de las políticas de la organización
# 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. Borra el bucket de GCS compartido para la etapa intermedia y los artefactos locales
# 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
Aquí concluye la sección de limpieza. A continuación, veremos la Conclusión.
12. Conclusión
¡Felicitaciones! Implementaste y gobernaste una arquitectura de agente a agente (A2A) de varios proyectos en Google Cloud con Vertex AI Agent Runtime, Central Agent Gateway, Agent Registry y las políticas de acceso unificado (UAP) de IAM.
Resumen de los conceptos clave
- Perímetro de salida centralizado: Contenedores de entorno de ejecución de radios enrutados (
PROJECT_CONCIERGE,PROJECT_SELLERS) a través de un Agent Gateway central enPROJECT_GOVERNANCEconagentGatewayConfig. - Declarative Governance (UAP): Se reemplazaron las vinculaciones fragmentadas por recurso con una sola política de acceso de IAM auditable que IAP v2 evalúa en la puerta de enlace.
- Identidad criptográfica: Se aplica el principio de privilegio mínimo para el tráfico de salida con identidades SPIFFE de contenedores (
principal://...) en lugar de claves de larga duración. - Detección dinámica de servicios: Se resuelven los Agent Endpoints de los agentes de pares en el tiempo de ejecución a través del Agent Registry central, lo que elimina las URLs y los IDs de proyectos codificados.
- Agilidad de la política en el tiempo de ejecución: Se realizó la transición de
pizza-seller-agentde Denegación predeterminada (403 Forbidden) a Permitido (200 OK) en tiempo real a través de la actualización de la política, sin reiniciar el contenedor.

Cosmopup dice: "Los agentes son geniales. Hacen todo el trabajo entre proyectos mientras yo me enfoco en mi objetivo principal: ¡dormir una siesta!"
Próximos pasos y documentación
- Descripción general de Gemini Enterprise Agent Platform
- Configura y, luego, implementa Agent Gateway
- Análisis detallado de la identidad del agente y la certificación de SPIFFE
- Políticas de acceso unificado de IAM y atributos de CEL
- Descripción general del catálogo de servicios del registro de agentes
- Lineamientos de Model Armor y Sensitive Data Protection
- Interfaces de Private Service Connect (PSC-I) con Agent Gateway