1. Introduzione
Man mano che le organizzazioni aziendali adottano l'AI generativa, le architetture si stanno evolvendo rapidamente da chatbot monolitici autonomi a sistemi multi-agente distribuiti (Agent-to-Agent/A2A). In queste topologie moderne, gli agenti orchestratori di alto livello coordinano workflow aziendali complessi delegando le attività ad agenti worker di dominio specializzati, server di strumenti Model Context Protocol (MCP) e database aziendali di backend in progetti cloud Google Cloud indipendenti.
Tuttavia, la gestione di sistemi multi-agente su larga scala introduce sfide critiche in termini di sicurezza, governance e operazioni:
- Shadow agent e proliferazione degli strumenti: quando i team di sviluppo eseguono il deployment degli agenti in progetti isolati senza un catalogo centralizzato, le organizzazioni perdono visibilità sugli strumenti e sui subagenti esistenti.
- Traffico in uscita tra progetti non monitorato: consentire agli agenti di utilizzare route di rete dirette e non ispezionate crea rischi di esfiltrazione dei dati e aggira i perimetri di sicurezza.
- Integrazioni hardcoded fragili: l'impostazione come hardcoded degli URL degli agenti downstream e degli ID del motore di ragionamento crea dipendenze fragili che si interrompono durante gli upgrade o i nuovi deployment.
- Mancanza di identità con privilegio minimo: i service account condivisi non forniscono il non ripudio crittografico a livello di singola istanza dell'agente.
Per risolvere queste sfide, Gemini Enterprise Agent Platform fornisce un control plane unificato per la governance e la connettività, composto da quattro pilastri fondamentali:
- Agent Gateway (
networkservices.googleapis.com): un proxy di rete e di applicazione delle policy regionale gestito. Operando in modalità in uscitaAGENT_TO_ANYWHERE, intercetta il traffico degli agenti in uscita, delega le valutazioni delle autorizzazioni alle estensioni di sicurezza e instrada le richieste attraverso i perimetri dei progetti. - Agent Registry (
agentregistry.googleapis.com): il catalogo dei servizi aziendali unificato. Fornisce una directory centralizzata e verificata di tutti gli strumenti, i server MCP e gli agenti peer disponibili nell'organizzazione, consentendo il rilevamento automatico dinamico in fase di runtime senza endpoint impostati come hardcoded. - Agent Identity & IAP v2 Governance (
iap.googleapis.com&iam.googleapis.com): un framework di identità e accesso crittografico. Gli agenti in esecuzione ricevono URN di macchine SPIFFE univoci e attestati (principal://...). L'uscita in uscita viene valutata in base alle Unified Access Policies (UAP/IAP v2) IAM centralizzate, verificando l'autorizzazione universaleiap.googleapis.com/resources.egressViaIAPutilizzando condizioni del catalogo Common Expression Language (CEL) avanzate (destination.agent_registry.*). - Agent Runtime (motori di ragionamento): una piattaforma di esecuzione serverless completamente gestita per applicazioni basate su agenti Python, con associazioni di configurazione native (
agent_gateway_config) ai gateway centrali.
Scenario aziendale del codelab: acquisto di cibo e bevande per più progetti
In questo codelab, creerai e gestirai un ecosistema di acquisto multiprogetto reale che comprende tre progetti Google Cloud distinti:
- Progetto di governance centrale (
PROJECT_GOVERNANCE): di proprietà del team IT centrale e SecOps, ospita l'Agent Gateway centrale, l'Agent Registry centrale e le policy di accesso unificato IAM. - Progetto Consumer Orchestrator (
PROJECT_CONCIERGE): di proprietà del team di approvvigionamento, ospita l'agente Purchasing Concierge che rileva dinamicamente i fornitori e indirizza gli ordini dei clienti. - Progetto Domain Vendor (
PROJECT_SELLERS): di proprietà di fornitori esterni o di reparto, che ospita l'agente Burger Seller e l'agente Pizza Seller.
Fig. 1 Architettura di governance centralizzata multiprogetto
Perché la governance centralizzata tra progetti?
Nelle grandi organizzazioni aziendali, i team di prodotto e i gruppi di data science creano agenti AI in decine di progetti Google Cloud indipendenti. Se ogni team ha il controllo diretto sulla registrazione degli strumenti, sulle route di rete in uscita e sulle misure di sicurezza, si crea una proliferazione di strumenti non verificati, policy DLP incoerenti, traffico in uscita dal VPC non monitorato e audit log frammentati.
La governance centralizzata tra progetti separa la creazione delle policy dall'esecuzione degli agenti:
- IT centrale e SecOps creano policy di sicurezza, verificano gli strumenti e monitorano il traffico in uscita all'interno di un unico progetto di governance centralizzata.
- I team di prodotto e applicazione si concentrano esclusivamente sulla logica di business nei loro progetti Agent Runtime indipendenti, collegandosi direttamente al gateway centrale senza l'overhead operativo della gestione di VPC locali, interconnessioni o Policy Engine frammentati.
Fig. 2. Architettura e confini di governance tra progetti a tre livelli
Modello di definizione dell'ambito dell'identità a due livelli in Unified Access Policies
Quando gli agenti comunicano tramite l'Agent Gateway centrale, Identity-Aware Proxy (IAP v2) valuta l'accesso in base all'Agent Identity del chiamante, un'identità basata su SPIFFE con attestazione crittografica emessa automaticamente per il container di runtime, rispetto a una policy di accesso IAM globale:
- Livello 1: API Google Cloud di base (generiche tramite
principalSet://nella Regola 1): autorizzazione del traffico in uscita a livello di progetto che consente a tutti i runtime degli agenti nei progetti spoke di raggiungere le API di Google standard (aiplatform,iamcredentials,telemetry,agentregistry) per il rilevamento, la generazione di token e l'inferenza. - Livello 2: strumenti aziendali e servizi A2A (granularità fine tramite
principal://nelle regole 2 e 3): accesso rigoroso con privilegio minimo associato a singole istanze del motore di ragionamento, applicato con condizioni CEL (Common Expression Language) che hanno come target servizi Agent Registry registrati specifici (destination.agent_registry.agent.name).
Cosa crei
- Agent Gateway centralizzato (
centralized-agw) inPROJECT_GOVERNANCE - Estensione del servizio di autorizzazione IAP v2 e policy Authz in modalità di applicazione forzata rigorosa (
failOpen: false) - Policy Unified Access Policies IAM di base (
uap-rules.json) e associazione delle policy del progetto - Autorizzazioni IAM dell'agente di servizio tra progetti (
ar_agw_cross_project_sa) - Bucket di gestione temporanea di Google Cloud Storage (GCS) centrale condiviso
- Agenti di vendita di hamburger e pizza isolati in
PROJECT_SELLERS - Acquisto dell'agente Concierge con rilevamento automatico REST dinamico in
PROJECT_CONCIERGE - Registrazioni dei servizi in Central Agent Registry con URL mTLS tra progetti
- Aggiornamenti dinamici delle policy in uscita di IAP v2 con verifica in tempo reale e audit di Cloud Logging
Fig 3. Sequenza di implementazione passo passo
Cosa imparerai
- Come configurare le autorizzazioni IAM dell'agente di servizio tra progetti per i gateway centralizzati
- Come instradare il traffico in uscita di Agent Runtime tramite un Agent Gateway centrale in ambienti multiprogetto
- Come delegare l'autorizzazione di Agent Gateway a Identity-Aware Proxy (IAP v2) utilizzando Service Extensions (
iapPolicyVersion: "V2") - Come creare e associare policy di accesso unificato (UAP) IAM con regole Common Expression Language (CEL) che regolano le destinazioni registrate in Agent Registry (
destination.agent_registry.*) - Come eliminare gli ID e gli URL degli agenti impostati come hardcoded utilizzando il rilevamento automatico in fase di runtime con Agent Registry
- Come testare il blocco Zero Trust del perimetro reale (
HTTP 403 Forbidden) e verificare gli aggiornamenti delle policy in tempo reale in Cloud Logging
Cosa serve
- 3 progetti Google Cloud con fatturazione abilitata:
PROJECT_GOVERNANCE: governance centrale, gateway, registry e policy di accesso IAMPROJECT_CONCIERGE: agente orchestratore di concierge per gli acquistiPROJECT_SELLERS: agenti di vendita specializzati in hamburger e pizza
- Un utente o un service account IAM con
roles/ownero autorizzazioni amministrative in tutti e tre i progetti - Un'organizzazione Google Cloud (per la mappatura del dominio di attendibilità SPIFFE)
- Google Cloud Shell o una macchina locale con l'interfaccia a riga di comando
gcloud,python(3.11+) euvinstallati
Con questo si conclude la parte introduttiva… Passiamo alla sezione Configurazione e ambiente.
2. Configurazione
Sebbene questa architettura si estenda su tre progetti Google Cloud distinti, puoi eseguire il 100% dei comandi di deployment del terminale, dei download dei repository e delle operazioni di gestione temporanea da un singolo terminale Cloud Shell impostato su PROJECT_GOVERNANCE. Ogni script di deployment e comando gcloud ha come target esplicito il progetto di destinazione appropriato tramite i flag dell'interfaccia a riga di comando (--project).
Per iniziare, accedi alla riga di comando del tuo progetto Google Cloud:
- Cloud Shell all'indirizzo
shell.cloud.google.comoppure - Un terminale locale con l'interfaccia a riga di comando
gcloudinstallata
Imposta il contesto del progetto
# 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
Aggiorna l'interfaccia a riga di comando gcloud (consigliato)
# update gcloud components
gcloud components update --quiet
Imposta le variabili di ambiente shell
Inserisci gli identificatori specifici del progetto.
# 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"
Queste variabili di shell verranno derivate automaticamente.
# 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 una directory locale per i file di configurazione
# create config folder
mkdir -p cfg
Assegna il ruolo Access Policy Admin per le Unified Access Policies
# 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
Abilita gli audit log di accesso ai dati di Cloud per IAP v2
Per impostazione predefinita, Google Cloud disabilita gli audit log di accesso ai dati per evitare costi di archiviazione imprevisti. Poiché IAP v2 emette decisioni di autorizzazione (granted=true e granted=false) come audit log di controllo dell'accesso ai dati, abilita il logging di ADMIN_READ, DATA_READ e DATA_WRITE per iap.googleapis.com in 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)"
Abilita le API Google Cloud richieste
# 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
Convalida l'abilitazione delle API in tutti i progetti
Se ti assicuri che tutti e tre i progetti (PROJECT_GOVERNANCE, PROJECT_CONCIERGE e PROJECT_SELLERS) abbiano esattamente le stesse API abilitate, stabilisci la coerenza operativa e previeni errori di generazione dei token di runtime, errori di catalogazione degli schemi o interruzioni della telemetria.
Esegui questo script di convalida in Cloud Shell per verificare la parità delle API in tutti e tre i progetti:
# 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
Esempio di output di convalida:
Dovresti vedere tutte le API abilitate.
✅ All 30 required APIs are ENABLED and synchronized across all three projects.
Configura le policy dell'organizzazione
Le policy dell'organizzazione Google Cloud predefinite applicano vincoli che limitano le associazioni delle policy di accesso IAM v3 alle risorse (constraints/iam.managed.disableAccessPolicyBinding).
Esegui l'override di eventuali limitazioni delle policy dell'organizzazione ereditate a livello di progetto impostando esplicitamente enforce: false su Consenti.
# 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
La parte di configurazione è terminata. Passa alla sezione Registra le API di Google principali.
3. Agent Registry
Registra il servizio endpoint API delle API di Google principali
Agent Gateway richiede che gli URL delle API di Google siano registrati nel Central Agent Registry in modo che gli agenti configurati con agent_gateway_config possano instradare il traffico in uscita in modo sicuro ai servizi di backend principali di Google Cloud (come aiplatform, credenziali IAM e telemetria).
Crea core-gapi-services in 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://cloudresourcemanager.googleapis.com:443 \
--interfaces=protocolBinding=JSONRPC,url=https://cloudresourcemanager.mtls.googleapis.com \
--interfaces=protocolBinding=JSONRPC,url=https://cloudresourcemanager.mtls.googleapis.com:443 \
--interfaces=protocolBinding=JSONRPC,url=https://iamcredentials.googleapis.com \
--interfaces=protocolBinding=JSONRPC,url=https://iamcredentials.googleapis.com:443 \
--interfaces=protocolBinding=JSONRPC,url=https://iamcredentials.mtls.googleapis.com \
--interfaces=protocolBinding=JSONRPC,url=https://iamcredentials.mtls.googleapis.com:443 \
--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
ID risorsa endpoint API 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}"
Informazioni su principalSet e principal in Agent Identity
In Google Cloud IAM e nella Gemini Enterprise Agent Platform, le identità delle macchine emesse per i container degli agenti in esecuzione utilizzano URN SPIFFE con attestazione crittografica valutati da Identity-Aware Proxy (IAP v2). Quando configuri le policy di accesso unificato IAM, puoi scegliere come target una singola principal specifica o una principalSet basata su attributi:
Dimensione |
|
|
Sintassi IAM |
|
|
Granularità | Granulare (a livello di istanza): identifica una singola istanza specifica del container del motore di ragionamento. | Granula grossolana (a livello di progetto): Identifica tutti i motori di ragionamento che condividono un attributo di progetto comune. |
Pattern URN |
|
|
Caso d'uso in Agent Platform | Livello 2 (strumenti aziendali e A2A): autorizzazione di agenti orchestratori specifici a richiamare strumenti del dominio di destinazione (ad es. Concierge per gli acquisti $\rightarrow$ Venditore di hamburger). | Livello 1 (Infrastruttura di base): concedi a tutti gli agenti di un progetto l'accesso in uscita alle API Google Cloud ( |
Impatto sul ciclo di vita | Se un agente viene eliminato e ricreato, il nuovo ID motore richiede un'associazione della policy IAM aggiornata. | Si applica automaticamente agli agenti di cui è stato eseguito il deployment di recente nel progetto senza ulteriori aggiornamenti IAM. |
Governance dichiarativa con Unified Access Policies (UAP/IAP v2)
Nella versione precedente di IAP v1, le policy in uscita venivano collegate direttamente alle singole risorse di Agent Registry utilizzando gcloud beta iap web add-iam-policy-binding. In IAP v2 e Unified Access Policies, le associazioni per risorsa vengono eliminate a favore di una singola policy di accesso IAM centralizzata (cfg/uap-rules.json).
L'autorizzazione di traffico in uscita di base per core-gapi-services verrà configurata come Regola 1 nella policy di accesso unificato nella Sezione 5, garantendo che tutti i container degli agenti abbiano rotte di traffico in uscita di base stabilite prima del deployment.
Per dettagli tecnici più approfonditi sugli identificatori delle entità e sui meccanismi di Workload Identity, consulta:
- Google Cloud IAM: Principal Identifiers & Principal Sets
- Come funziona l'identità dell'agente
- Configurazione delle policy di accesso unificato IAM per Agent Gateway
Con questo si conclude la registrazione degli endpoint API principali. Passa alla sezione Esegui il deployment di un Agent Gateway centralizzato.
4. Agent Gateway
Esegui il deployment di Agent Gateway centralizzato
Esegui il deployment dell'Agent Gateway centralizzato (centralized-agw) in modalità in uscita AGENT_TO_ANYWHERE all'interno del progetto $PROJECT_GOVERNANCE.
Definisci il manifest di configurazione del gateway
Crea cfg/${AGW_NAME}.yaml per la governance del traffico in uscita:
# 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 configurazione di 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 i dettagli di Agent Gateway
# show agent gateway status
gcloud network-services agent-gateways describe ${AGW_NAME} \
--location=${REGION} \
--project=${PROJECT_GOVERNANCE}
Esempio di output:
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 questo si conclude il deployment del gateway… Passa alla sezione Configura l'autorizzazione.
5. Autorizzazione
Configura l'autorizzazione di Agent Gateway e l'UAP di base
Agent Gateway protegge e gestisce il traffico in uscita degli strumenti e degli agenti utilizzando le policy di autorizzazione (networksecurity.authzPolicies) integrate con le Unified Access Policies (UAP) di Identity-Aware Proxy (IAP v2).
Panoramica dell'architettura di autorizzazione
Fig 4. Panoramica dell'architettura di autorizzazione
L'architettura di autorizzazione è composta da tre livelli interconnessi:
- Estensione di servizio IAP (
authzExtension): risorsa regionale configurata conservice: iap.googleapis.com,metadata: iapPolicyVersion: "V2"efailOpen: falseper l'applicazione di un perimetro rigido Zero Trust. - Policy di autorizzazione del gateway (
authzPolicy): risorsa regionale che ha come target l'Agent Gateway conpolicyProfile: REQUEST_AUTHZeaction: CUSTOM, indirizzando i controlli di autorizzazione all'estensione di autorizzazione IAP. - Unified Access Policies e associazione IAM (
accessPolicyepolicyBinding): risorsa IAM v3 globale valutata da IAP. Verifica l'autorizzazione universaleiap.googleapis.com/resources.egressViaIAPrispetto alle identità SPIFFE del chiamante e alle condizioni del catalogo CEL.
Passaggio 1: crea e importa l'estensione di autorizzazione IAP v2
Crea il manifest dell'estensione di servizio con iapPolicyVersion: "V2" e failOpen: false in modalità ENFORCE rigorosa:
# 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 l'estensione di autorizzazione:
# 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 che l'estensione Authz sia attiva:
# describe authz extension
gcloud service-extensions authz-extensions describe ${AGW_NAME}-svc-ext-authz-iap \
--location=${REGION} \
--project=${PROJECT_GOVERNANCE}
Esempio di output:
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
Passaggio 2: crea e importa la policy di autorizzazione del gateway
Crea una configurazione della policy di autorizzazione che si collega ad Agent Gateway e delega la verifica delle richieste all'estensione di autorizzazione 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 policy di autorizzazione:
# 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 policy di autorizzazione attiva:
# describe authz policy
gcloud beta network-security authz-policies describe ${AGW_NAME}-authz-policy-profile-iap \
--location=${REGION} \
--project=${PROJECT_GOVERNANCE}
Passaggio 3: crea la policy Unified Access Policies iniziale (Regola 1: API di Google principali)
Crea cfg/uap-rules.json con la Regola 1 che autorizza i tre principalSet del progetto a raggiungere 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
Passaggio 4: crea e associa la policy di accesso IAM
Crea la policy di accesso IAM globale:
# create global IAM access policy
gcloud iam access-policies create ${UAP_POLICY_NAME} \
--details-rules=cfg/uap-rules.json \
--project=${PROJECT_GOVERNANCE} \
--location=global
Associa la policy di accesso 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 che l'associazione della policy sia attiva:
# verify policy binding
gcloud iam policy-bindings describe ${UAP_BINDING_NAME} \
--project=${PROJECT_GOVERNANCE} \
--location=global
Esempio di output:
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}
Il traffico in uscita dell'API Google Cloud di base è ora autorizzato in modo sicuro in tutti e tre i progetti in modalità ENFORCE rigorosa.
La configurazione dell'autorizzazione del gateway è completata. Passa alla sezione Configura le autorizzazioni IAM tra progetti.
6. IAM tra progetti
Configura le autorizzazioni IAM tra progetti
In questa topologia multi-progetto, gli Agent Runtime si trovano nei progetti spoke (PROJECT_CONCIERGE e PROJECT_SELLERS), mentre l'Agent Gateway centrale e l'Agent Registry si trovano in PROJECT_GOVERNANCE.
Poiché i progetti Google Cloud sono perimetri di sicurezza isolati, l'accesso tra progetti deve essere concesso esplicitamente su due livelli operativi:
- Control plane (fase di deployment): quando esegui il deployment di un container dell'agente configurato con
--agent-gateway-config, l'agente di servizio Agent Runtime (service-) del progetto spoke deve collegare il container al gateway centrale. Creiamo un ruolo personalizzato minimo (@gcp-sa-aiplatform.iam.gserviceaccount.com ar_agw_cross_project_sa) che concedenetworkservices.agentGateways.use,geteoperations.getinPROJECT_GOVERNANCE. - Piano dati (esecuzione del runtime):
- Catalog Discovery: le identità spoke devono avere
roles/agentregistry.viewerinPROJECT_GOVERNANCEper risolvere dinamicamente gli Agent Endpoint di destinazione. - Chiamata del target: l'agente Concierge deve avere
roles/aiplatform.userinPROJECT_SELLERSper eseguire query sui motori di ragionamento del venditore.
- Catalog Discovery: le identità spoke devono avere
Crea un ruolo IAM personalizzato in 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"
Assegna un ruolo personalizzato agli agenti di servizio 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 questo si conclude la configurazione IAM tra progetti… Passiamo alla sezione Esegui il deployment degli agenti Seller e Concierge.
7. Agent Runtime
Esegui il deployment degli agenti di vendita e Concierge
Il codebase dell'applicazione multi-agente e gli script di deployment utilizzati per questo codelab sono gestiti in un repository GitHub di Google Cloud remoto. I passaggi seguenti cloneranno il repository localmente, copieranno i file necessari nella struttura della directory di lavoro corrente, puliranno i file temporanei e installeranno le dipendenze con uv.
Recupera artefatti remoti
# clone remote repository to temp local dir
git clone https://github.com/GoogleCloudPlatform/cloud-networking-solutions.git ./temp_agw_multiproject
# copy multi-agent application files to current working directory
cp -r temp_agw_multiproject/codelabs/agw-multiproject ./cross-project-multiagent
# remove temporary directory
rm -rf temp_agw_multiproject
# install dependencies
uv sync --directory ./cross-project-multiagent
Crea un bucket di gestione temporanea centrale condiviso
# 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"
Come funziona l'associazione di Agent Gateway tra progetti
In questo passaggio, eseguirai il deployment degli agenti venditore nel progetto spoke (PROJECT_SELLERS) configurandoli in modo da instradare il traffico in uscita tramite l'Agent Gateway centrale in 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)
Poiché la Regola 1 è stata stabilita in precedenza nella nostra policy di accesso unificato, le richieste di inizializzazione dei container alle API Google Cloud sono consentite tramite il gateway senza interruzioni.
Esegui il deployment degli agenti di vendita di hamburger e pizza su 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}
Convalida il routing del gateway del venditore
# 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
Esegui il deployment dell'agente Concierge per gli acquisti in 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}
Convalida il routing del gateway di acquisto
# 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}'
L'output dovrebbe mostrare l'identità e il progetto di Agent Runtime dell'agente Concierge e l'associazione all'Agent Gateway del progetto di governance.
{
"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 questo si concludono i deployment degli agenti… Passa alla sezione Registra gli agenti nel registro centrale degli agenti.
8. Registry tra progetti
Registra gli agenti in Central Agent Registry
Registra tutti e tre gli agenti nel registry centrale degli agenti in PROJECT_GOVERNANCE utilizzando endpoint mTLS regionali tra progetti e numeri di progetto numerici.
Registra i servizi come agenti non A2A in 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.googleapis.com/v1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${BURGER_ENGINE_ID}:query \
--interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com/v1beta1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${BURGER_ENGINE_ID}:query \
--interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com:443/v1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${BURGER_ENGINE_ID}:query \
--interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com:443/v1beta1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${BURGER_ENGINE_ID}:query \
--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 \
--interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com:443/v1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${BURGER_ENGINE_ID}:query \
--interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com:443/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.googleapis.com/v1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${PIZZA_ENGINE_ID}:query \
--interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com/v1beta1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${PIZZA_ENGINE_ID}:query \
--interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com:443/v1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${PIZZA_ENGINE_ID}:query \
--interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com:443/v1beta1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${PIZZA_ENGINE_ID}:query \
--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 \
--interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com:443/v1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${PIZZA_ENGINE_ID}:query \
--interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com:443/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.googleapis.com/v1/projects/${PROJECT_NUMBER_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}:query \
--interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com/v1beta1/projects/${PROJECT_NUMBER_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}:query \
--interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com:443/v1/projects/${PROJECT_NUMBER_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}:query \
--interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com:443/v1beta1/projects/${PROJECT_NUMBER_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}:query \
--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 \
--interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com:443/v1/projects/${PROJECT_NUMBER_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}:query \
--interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com:443/v1beta1/projects/${PROJECT_NUMBER_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}:query
Acquisisci gli ID di Agent Registry sottostanti
# 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 questo si conclude la configurazione del registry… Passiamo ora alla sezione Configura le policy in uscita A2A.
9. Policy UAP
Configura le policy in uscita A2A in Unified Access Policy
Nell'architettura Default Deny di Agent Gateway in modalità ENFORCE rigorosa:
- Regola 1 (API Google Cloud di base): consente ai container degli agenti in tutti e tre i progetti di raggiungere
core-gapi-services. - Regola 2 (Agente venditore di hamburger: CONSENTI): consente all'istanza dell'agente Concierge per gli acquisti di richiamare l'agente venditore di hamburger.
- Pizza Seller Agent (DENIED by Default): intenzionalmente escluso dalle regole della policy. In modalità
ENFORCE(failOpen: false), qualsiasi tentativo da parte di Concierge di richiamare Pizza Seller verrà terminato immediatamente nel perimetro del gateway conHTTP 403 Forbidden.
Formulate Concierge Agent Identity
# 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}"
Manifest di aggiornamento con le regole 1 e 2
Per aggiornare in sicurezza la policy di accesso senza sovrascrivere le regole esistenti, definisci il manifest consolidato completo contenente la Regola 1 (API di Google principali) e la Regola 2 (Burger Seller Agent):
# create consolidated policy manifest with Rule 1 and Rule 2
cat > cfg/uap-rules-consolidated.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}')"
}
}
},
{
"description": "Rule 2: Allow Purchasing Concierge to invoke Burger Seller Agent via Central Gateway",
"effect": "ALLOW",
"principals": [
"${CONCIERGE_SPIFFE_PRINCIPAL}",
"principal://agents.global.org-${ORG_ID}.system.id.goog/attribute.agentIdentity/projects/${PROJECT_NUMBER_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}",
"principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.agentIdentity/projects/${PROJECT_NUMBER_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}"
],
"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
Applica policy di accesso aggiornata
Applica il manifest delle regole consolidate in modo dichiarativo utilizzando --details-rules:
# update IAM access policy with consolidated manifest (Rule 1 + Rule 2)
gcloud iam access-policies update ${UAP_POLICY_NAME} \
--details-rules=cfg/uap-rules-consolidated.json \
--project=${PROJECT_GOVERNANCE} \
--location=global
Verifica i dettagli della policy di accesso IAM
# inspect updated access policy
gcloud iam access-policies describe ${UAP_POLICY_NAME} \
--project=${PROJECT_GOVERNANCE} \
--location=global
Esempio di output:
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
La configurazione delle policy è terminata. Passa alla sezione Testa e verifica le policy di governance.
10. Verifica le policy
Testa e verifica le policy di governance tramite Cloud Logging
In questa sezione, testerai le interazioni tra agenti (A2A) tra progetti in Agent Runtime Laboratorio AI, osserverai il blocco effettivo del perimetro HTTP 403 Forbidden in modalità ENFORCE rigorosa, modificherai le Unified Access Policies in tempo reale e convaliderai l'approvazione immediata degli ordini.
Passaggio 1: apri il Laboratorio AI di Agent Runtime in PROJECT_CONCIERGE
- Apri la console Google Cloud.
- Nella barra del selettore di progetti in alto, passa a
PROJECT_CONCIERGE. - Nel menu di navigazione, vai a Agent Platform > Agenti > Deployment.
- Fai clic su
purchasing-concierge-adk. - Seleziona Playground per aprire l'interfaccia di chat interattiva sul lato destro dello schermo.
Passaggio 2: testa l'ordine di un hamburger (corrispondenza con la regola 2 -> 200 OK)
Nella finestra della chat di Playground, invia il seguente prompt per l'ordine:
I would like 10 Classic Cheeseburgers. Place this order now.
Se è necessaria una risposta di conferma, invia la seguente risposta:
Confirmed, please place the order.
In alternativa, esegui il test in modo programmatico da Cloud Shell/terminale:
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)
"
Se è necessaria una risposta di conferma, utilizza questo 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'])
"
Cosa succede dietro le quinte:
- Rilevamento dinamico: durante l'avvio della sessione, il Purchasing Concierge ha eseguito una query sul Central Agent Registry in
PROJECT_GOVERNANCE(tramitecore-gapi-servicestramite l'Agent Gateway autorizzato dalla Regola 1) per rilevare l'endpoint mTLS regionale perburger-seller-agent. - Risoluzione dell'intent e chiamata A2A: Gemini all'interno del Concierge per gli acquisti analizza l'intent di ordinazione di cibo e chiama l'agente di Burger Seller tramite un RPC in uscita a
https://${REGION}-aiplatform.mtls.googleapis.com/.../reasoningEngines/${BURGER_ENGINE_ID}. - Intercettazione del gateway e propagazione SPIFFE: il traffico in uscita viene acquisito da
agent_gateway_confige indirizzato all'Agent Gateway centrale inPROJECT_GOVERNANCE, con l'identità SPIFFE crittografica di Concierge (principal://...). - Valutazione della policy IAP v2: l'Agent Gateway centrale richiama l'estensione dell'autorizzazione IAP (
authzExtension). IAP v2 valuta la regola 2 nella policy Unified Access Policies IAM. Poiché il chiamante corrisponde a${CONCIERGE_SPIFFE_PRINCIPAL}e la destinazione corrisponde aburger-seller-agent, IAP restituisceALLOW(granted: true). - Esecuzione tra progetti: l'Agent Gateway invia la richiesta autorizzata tra progetti a
PROJECT_SELLERS, dove il motore di ragionamento di Burger Seller elabora l'ordine e restituisce la conferma.
Risposta prevista:
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
Passaggio 3: esamina gli audit log di Agent Gateway e IAP v2 (HTTP 200/ALLOWED)
Esegui query sui log delle richieste di Agent Gateway in 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
)"
I log dovrebbero acquisire il traffico in uscita proveniente da entrambi i progetti spoke (PROJECT_CONCIERGE e PROJECT_SELLERS) con campi di uscita per le chiamate di ragionamento di Gemini (generateContent), la telemetria di Cloud Trace (/v1/traces) e le ricerche delle credenziali IAM, intercettate e autorizzate in modo trasparente dalla Regola 1 (core-gapi-services).
Esegui una query sugli audit log di accesso ai dati di Cloud Audit Logs di IAP v2 per verificare la versione della policy 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
)"
Esempio di output:
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
Passaggio 4: testa l'ordine della pizza (rifiuto predefinito -> HTTP 403 Forbidden APPLICATO)
Nella stessa finestra di chat di Playground, invia il seguente prompt per l'ordine della pizza:
I would like 10 BBQ Chicken Pizzas. Place this order now.
Se è necessaria una risposta di conferma, invia la seguente risposta:
Confirmed, please place the order.
In alternativa, esegui il test in modo programmatico da Cloud Shell/terminale:
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)
"
Se è necessaria una risposta di conferma, utilizza questo 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'])
"
Risposta prevista:
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.
Cosa succede dietro le quinte:
- Rilevamento dinamico: il Concierge per gli acquisti ha risolto l'endpoint
pizza-seller-agentdal registro centrale degli agenti durante l'avvio. - Risoluzione dell'intent e chiamata A2A: Gemini all'interno del Concierge per gli acquisti tenta di inviare la richiesta di ordine della pizza all'endpoint del venditore di pizza in
PROJECT_SELLERS. - Intercettazione del gateway: l'RPC in uscita viene acquisita da
agent_gateway_confige indirizzata all'Agent Gateway centrale. - Valutazione delle policy di IAP v2 (negazione predefinita): l'Agent Gateway centrale richiama IAP v2. Poiché nella policy di accesso unificato non esiste alcuna regola corrispondente a
pizza-seller-agent, IAP restituisceDENY(granted: false). - Blocco del perimetro rigoroso: poiché l'estensione Authz è in modalità di applicazione forzata (
failOpen: false), l'Agent Gateway termina immediatamente la connessione in uscita e restituisceHTTP 403 Forbidden. Il traffico non lascia mai il gateway e non raggiunge maiPROJECT_SELLERS.
Passaggio 5: esamina i log di Agent Gateway per individuare le richieste bloccate (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
)"
Esempio di output del log di negazione:
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
Esegui una query sugli audit log di controllo dell'accesso ai dati di IAP v2 per la decisione di negazione:
# 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
)"
Esempio di output dell'audit log negato:
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
Passaggio 6: concedi dinamicamente l'accesso in uscita all'agente Pizza
Crea un nuovo cfg/uap-rules-update-3.json per includere la Regola 1 (API di base), la Regola 2 (Agente di vendita di hamburger) e ora la Regola 3 (Agente di vendita di pizza)
# 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
Applica l'aggiornamento della policy in tempo reale:
# 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
Passaggio 7: esegui di nuovo una query su Pizza Agent (esito positivo immediato 200 OK)
Nella finestra di chat di Playground, invia di nuovo il prompt per l'ordine della pizza:
I would like 10 BBQ Chicken Pizzas. Place this order now.
Se è necessaria una risposta di conferma, invia la seguente risposta:
Confirmed, please place the order.
In alternativa, esegui il test in modo programmatico da Cloud Shell/terminale:
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)
"
Se è necessaria una risposta di conferma, utilizza questo 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'])
"
Risposta prevista:
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**
Cosa succede dietro le quinte:
- Aggiornamento dinamico delle policy: l'aggiornamento delle Unified Access Policies IAM ha effetto immediato nel motore di valutazione IAP, senza tempi di inattività e senza rifare il deployment dei container.
- Chiamata A2A: il Concierge invia la richiesta tramite il Central Agent Gateway.
- Valutazione della policy di IAP v2 (approvazione): IAP v2 corrisponde alla Regola 3, verifica l'identità del chiamante e l'espressione CEL di destinazione e restituisce
ALLOW(granted: true). - Esecuzione tra progetti: l'Agent Gateway centrale inoltra il traffico autorizzato a
PROJECT_SELLERS, dove il venditore di pizza elabora l'ordine.
Passaggio 8: esamina i log di Agent Gateway per le richieste di pizza concesse
# 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
)"
Esempio di output del log di concessione:
TIME METHOD STATUS AUTHZ URL
HH:MM:SS POST 200 ALLOWED https://aiplatform.mtls.googleapis.com/v1beta1/projects/${PROJECT_SELLERS}/locations/global/publishers/google/models/gemini-3.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 questo si concludono i test e la verifica… Passa alla sezione Esegui la pulizia.
11. Esegui la pulizia
Per evitare che al tuo account Google Cloud vengano addebitati costi relativi alle risorse utilizzate in questo codelab, esegui i passaggi di eliminazione in ordine rigorosamente inverso rispetto alle dipendenze:
1. Esegui la pulizia dei deployment del motore di ragionamento
Esegui lo script cleanup_old_deployments.py incluso in entrambi i progetti di runtime per eliminare i motori di ragionamento e attendere le operazioni a lunga esecuzione:
# 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}
In alternativa, puoi elencare ed eliminare i motori di ragionamento in linea:
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. Elimina i servizi 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. Elimina l'associazione della policy di accesso unificato IAM e la policy di accesso
# 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. Elimina Agent Gateway e le policy di sicurezza
# 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. Rimuovi le associazioni IAM tra progetti e il ruolo personalizzato
# 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
Se hai assegnato roles/iam.accessPolicyAdmin e roles/resourcemanager.projectIamAdmin durante la fase di configurazione, rimuovili dal tuo account utente attivo per ripristinare il privilegio minimo:
# 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. Ripristina l'audit logging dei dati e i vincoli delle policy dell'organizzazione
# 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. Ripristina i vincoli delle policy dell'organizzazione
# 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. Elimina il bucket di gestione temporanea GCS condiviso e gli artefatti locali
# 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
Con questo si conclude la parte di pulizia… Passiamo alla Conclusione.
12. Conclusione
Complimenti! Hai eseguito il deployment e la governance di un'architettura Agent-to-Agent (A2A) multi-progetto su Google Cloud utilizzando Vertex AI Agent Runtime, Central Agent Gateway, Agent Registry e le Unified Access Policies (UAP) IAM.
Riepilogo dei concetti chiave
- Perimetro di uscita centralizzato: i container di runtime spoke (
PROJECT_CONCIERGE,PROJECT_SELLERS) vengono instradati tramite un Agent Gateway centrale inPROJECT_GOVERNANCEutilizzandoagentGatewayConfig. - Governance dichiarativa (UAP): le associazioni frammentate per risorsa sono state sostituite con un'unica policy di accesso IAM controllabile, valutata nel gateway da IAP v2.
- Identità crittografica: applicazione del traffico in uscita con privilegio minimo utilizzando le identità SPIFFE dei container (
principal://...) anziché chiavi di lunga durata. - Service Discovery dinamico: gli Agent Endpoint peer vengono risolti in fase di runtime tramite l'Agent Registry centrale, eliminando gli URL e gli ID progetto impostati come hardcoded.
- Agilità delle policy di runtime: transizione di
pizza-seller-agentda Negazione predefinita (403 Forbidden) a Consentito (200 OK) in tempo reale tramite l'aggiornamento delle policy, senza riavvii dei container.

Cosmopup dice: "Gli agenti sono fantastici: fanno tutto il lavoro tra i progetti mentre io mi concentro sul mio obiettivo principale: fare un pisolino!"
Passaggi successivi e documentazione
- Panoramica di Gemini Enterprise Agent Platform
- Configura ed esegui il deployment di Agent Gateway
- Approfondimento sull'identità dell'agente e sull'attestazione SPIFFE
- IAM Unified Access Policies e attributi CEL
- Panoramica del catalogo dei servizi di Agent Registry
- Guardrail di Model Armor e Sensitive Data Protection
- Interfacce Private Service Connect (PSC-I) con Agent Gateway