1. Introduction
À mesure que les entreprises adoptent l'IA générative, les architectures évoluent rapidement, passant de chatbots monolithiques autonomes à des systèmes multi-agents distribués (Agent-to-Agent / A2A). Dans ces topologies modernes, les agents orchestrateurs de haut niveau coordonnent des workflows métier complexes en déléguant des tâches à des agents worker de domaine spécialisés, à des serveurs d'outils MCP (Model Context Protocol) et à des bases de données d'entreprise de backend dans des projets Google Cloud indépendants.
Toutefois, l'exploitation de systèmes multi-agents à grande échelle pose des problèmes critiques de sécurité, de gouvernance et d'exploitation :
- Prolifération des agents et des outils fantômes : lorsque les équipes de développement déploient des agents dans des projets isolés sans catalogue centralisé, les organisations perdent la visibilité sur les outils et les sous-agents existants.
- Sortie inter-projets non surveillée : autoriser les agents à emprunter des itinéraires réseau directs et non inspectés crée des risques d'exfiltration de données et contourne les périmètres de sécurité.
- Intégrations codées en dur fragiles : le codage en dur des URL des agents en aval et des ID du moteur de raisonnement crée des dépendances fragiles qui se rompent lors des mises à niveau ou des redéploiements.
- Absence d'identité appliquant le principe de moindre privilège : les comptes de service partagés ne permettent pas de fournir une non-répudiation cryptographique au niveau de chaque instance d'agent.
Pour relever ces défis, la Gemini Enterprise Agent Platform fournit un plan de contrôle unifié de la gouvernance et de la connectivité, composé de quatre piliers principaux :
- Passerelle de l'agent (
networkservices.googleapis.com) : proxy géré d'application des règles et de réseau régional. En mode sortieAGENT_TO_ANYWHERE, il intercepte le trafic sortant de l'agent, délègue les évaluations d'autorisation aux extensions de sécurité et achemine les requêtes à travers les périmètres du projet. - Agent Registry (
agentregistry.googleapis.com) : catalogue de services unique pour les entreprises. Il fournit un répertoire centralisé et validé de tous les outils, serveurs MCP et agents pairs disponibles dans l'organisation, ce qui permet une découverte automatique et dynamique de l'exécution sans aucun point de terminaison codé en dur. - Gouvernance de l'identité de l'agent et de l'IAP v2 (
iap.googleapis.cometiam.googleapis.com) : framework cryptographique d'identité et d'accès. Les agents d'exécution reçoivent des URN de machine SPIFFE uniques et attestées (principal://...). La sortie sortante est évaluée par rapport aux stratégies d'accès unifiées IAM (UAP / IAP v2) centralisées, qui vérifient l'autorisation universelleiap.googleapis.com/resources.egressViaIAPà l'aide de conditions de catalogue CEL (Common Expression Language) enrichies (destination.agent_registry.*). - Agent Runtime (moteurs de raisonnement) : plate-forme d'exécution sans serveur entièrement gérée pour les applications agentiques basées sur Python, avec des liaisons de configuration natives (
agent_gateway_config) aux passerelles centrales.
Scénario d'atelier de programmation : achats de produits alimentaires et de boissons multiprojets
Dans cet atelier de programmation, vous allez créer et gérer un écosystème d'achat multiprojets réel couvrant trois projets Google Cloud distincts :
- Projet de gouvernance centralisée (
PROJECT_GOVERNANCE) : appartient aux équipes informatiques et SecOps centrales, et héberge l'Agent Gateway central, l'Agent Registry central et les Règles d'accès unifiées IAM. - Projet Consumer Orchestrator (
PROJECT_CONCIERGE) : appartient à l'équipe chargée des achats et héberge l'agent de concierge d'achat, qui découvre dynamiquement les fournisseurs et achemine les commandes des clients. - Projet de fournisseur de domaine (
PROJECT_SELLERS) : appartient à des fournisseurs externes ou à des services, et héberge les agents de vente de burgers et de pizzas.
Fig. 1. Architecture de gouvernance centralisée multiprojet
Pourquoi une gouvernance centralisée entre les projets ?
Dans les grandes entreprises, les équipes produit et les groupes de data science créent des agents d'IA dans des dizaines de projets Google Cloud indépendants. En donnant à chaque équipe un contrôle direct sur l'enregistrement des outils, les routes réseau de sortie et les mesures de sécurité, on crée une prolifération d'outils non vérifiés, des règles de protection contre la perte de données incohérentes, une sortie VPC non surveillée et des journaux d'audit fragmentés.
La gouvernance centralisée multi-projets sépare la création de règles de l'exécution des agents :
- Les équipes IT et SecOps centrales créent des règles de sécurité, valident les outils et surveillent les sorties dans un seul projet de gouvernance centralisée.
- Les équipes produit et application se concentrent uniquement sur la logique métier dans leurs projets d'exécution d'agent indépendants, en se liant directement à la passerelle centrale sans la surcharge opérationnelle liée à la gestion des VPC locaux, des interconnexions ou des moteurs de règles fragmentés.
Fig. 2. Architecture et limites de la gouvernance multiprojets à trois niveaux
Modèle de portée d'identité à deux niveaux dans les règles d'accès unifiées
Lorsque les agents communiquent via l'Agent Gateway central, Identity-Aware Proxy (IAP v2) évalue l'accès en fonction de l'identité de l'agent de l'appelant (une identité basée sur SPIFFE, attestée de manière cryptographique et émise automatiquement pour le conteneur d'exécution) par rapport à une règle d'accès IAM globale :
- Niveau 1 : API Google Cloud de base (autorisation d'accès sortant à l'échelle du projet,
principalSet://dans la règle 1) : autorisation d'accès sortant à l'échelle du projet permettant à tous les environnements d'exécution d'agent des projets spokes d'accéder aux API Google standards (aiplatform,iamcredentials,telemetry,agentregistry) pour la découverte, la génération de jetons et l'inférence. - Niveau 2 : Outils professionnels et services A2A (accès précis via
principal://dans les règles 2 et 3) : accès strict au moindre privilège lié à des instances Reasoning Engine individuelles, appliqué avec des conditions CEL (Common Expression Language) ciblant des services Agent Registry spécifiques enregistrés (destination.agent_registry.agent.name).
Objectif de l'atelier
- Passerelle Agent Gateway centralisée (
centralized-agw) dansPROJECT_GOVERNANCE - Extension du service d'autorisation IAP v2 et règle d'autorisation en mode STRICT ENFORCE (
failOpen: false) - Règle d'accès unifiée IAM de base (
uap-rules.json) et liaison de stratégie de projet - Autorisations IAM des agents de service interprojets (
ar_agw_cross_project_sa) - Bucket de préproduction Google Cloud Storage (GCS) central partagé
- Agents de vente de burgers et de pizzas isolés dans
PROJECT_SELLERS - Agent de conciergerie pour les achats avec autodiscovery REST dynamique dans
PROJECT_CONCIERGE - Enregistrements de services dans Central Agent Registry avec des URL mTLS multiprojets
- Mises à jour dynamiques des règles de sortie IAP v2 avec validation en direct et audits Cloud Logging
Fig. 3. Séquence d'implémentation étape par étape
Objectifs
- Configurer les autorisations IAM de l'agent de service multiprojet pour les passerelles centralisées
- Comment acheminer la sortie Agent Runtime via une passerelle Agent Gateway centrale dans des environnements multiprojets
- Déléguer l'autorisation Agent Gateway à Identity-Aware Proxy (IAP v2) à l'aide des Service Extensions (
iapPolicyVersion: "V2") - Créer et associer des règles CEL (Common Expression Language) avec des stratégies d'accès unifiées IAM régissant les destinations enregistrées dans Agent Registry (
destination.agent_registry.*) - Éliminer les ID et URL d'agent codés en dur à l'aide de la découverte automatique au moment de l'exécution par rapport à Agent Registry
- Tester le blocage du périmètre zéro trust réel (
HTTP 403 Forbidden) et vérifier les mises à jour des règles en direct dans Cloud Logging
Ce dont vous avez besoin
- Trois projets Google Cloud avec la facturation activée :
PROJECT_GOVERNANCE: gouvernance centralisée, passerelle, registre et stratégies d'accès IAMPROJECT_CONCIERGE: agent d'orchestration du service de conciergerie pour les achatsPROJECT_SELLERS: agents vendeurs spécialisés dans les burgers et les pizzas
- Un compte de service ou un utilisateur IAM disposant des autorisations
roles/ownerou d'autorisations d'administrateur pour les trois projets - Une organisation Google Cloud (pour le mappage du domaine de confiance SPIFFE)
- Google Cloud Shell ou une machine locale avec
gcloudCLI,python(3.11+) etuvinstallés
La partie d'introduction est terminée. Passons à la section Configuration et environnement.
2. Configuration
Bien que cette architecture s'étende sur trois projets Google Cloud distincts, vous pouvez exécuter 100% des commandes de déploiement de terminal, des téléchargements de dépôt et des opérations de préparation à partir d'un seul terminal Cloud Shell défini sur PROJECT_GOVERNANCE. Chaque script de déploiement et chaque commande gcloud cible explicitement le projet de destination approprié via des options de CLI (--project).
Commencez par accéder à la ligne de commande de votre projet Google Cloud :
- Cloud Shell à l'adresse
shell.cloud.google.com, ou - Un terminal local avec
gcloudCLI installé
Définir le contexte de votre projet
# 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
Mettre à jour la CLI gcloud (recommandé)
# update gcloud components
gcloud components update --quiet
Définir des variables d'environnement de shell
Saisissez les identifiants spécifiques à votre projet.
# 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"
Ces variables shell seront dérivées automatiquement.
# 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}"
Créer un répertoire local pour les fichiers de configuration
# create config folder
mkdir -p cfg
Attribuer le rôle d'administrateur des règles d'accès pour les règles d'accès unifiées
# 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
Activer les journaux d'audit des accès aux données Cloud pour IAP v2
Par défaut, Google Cloud désactive les journaux d'audit des accès aux données pour éviter des frais de stockage imprévus. Étant donné qu'IAP v2 émet des décisions d'autorisation (granted=true et granted=false) en tant que journaux d'audit des accès aux données, activez la journalisation ADMIN_READ, DATA_READ et DATA_WRITE pour iap.googleapis.com dans 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)"
Activer les API Google Cloud requises
# 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
Valider l'activation de l'API dans tous les projets
En vous assurant que les mêmes API sont activées dans les trois projets (PROJECT_GOVERNANCE, PROJECT_CONCIERGE et PROJECT_SELLERS), vous garantissez la cohérence opérationnelle et évitez les échecs de création de jetons d'exécution, les erreurs de catalogage de schéma ou les pertes de données de télémétrie.
Exécutez le script de validation suivant dans Cloud Shell pour vérifier la parité des API dans les trois projets :
# 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
Exemple de résultat de validation :
Toutes les API devraient être activées.
✅ All 30 required APIs are ENABLED and synchronized across all three projects.
Configurer des règles d'administration
Les règles d'administration Google Cloud par défaut appliquent des contraintes qui limitent les liaisons de stratégie d'accès IAM v3 aux ressources (constraints/iam.managed.disableAccessPolicyBinding).
Remplacez les restrictions héritées des règles d'administration au niveau du projet en définissant explicitement enforce: false sur "Autoriser".
# 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 partie configuration est terminée. Passons à la section Enregistrer les API Google Core.
3. Agent Registry
Enregistrer le service de point de terminaison des API Google Core
Agent Gateway nécessite que les URL des API Google soient enregistrées dans le registre central des agents afin que les agents configurés avec agent_gateway_config puissent acheminer le trafic sortant de manière sécurisée vers les services de backend Google Cloud principaux (tels que aiplatform, les identifiants IAM et la télémétrie).
Créer core-gapi-services dans 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
ID de ressource du point de terminaison des API Core de Capture
# 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}"
Comprendre la différence entre principalSet et principal dans Agent Identity
Dans Google Cloud IAM et Gemini Enterprise Agent Platform, les identités machine attribuées aux conteneurs d'agent en cours d'exécution utilisent des URN SPIFFE attestées de manière cryptographique, évaluées par Identity-Aware Proxy (IAP v2). Lorsque vous configurez des règles d'accès unifiées IAM, vous pouvez cibler un principal unique spécifique ou un principalSet basé sur des attributs :
Dimension |
|
|
Syntaxe IAM |
|
|
Précision | Précision fine (au niveau de l'instance) : identifie une instance de conteneur Reasoning Engine spécifique. | Précision approximative (au niveau du projet) : identifie tous les moteurs de raisonnement partageant un attribut de projet commun. |
Format URN |
|
|
Cas d'utilisation dans Agent Platform | Niveau 2 (Outils Business et A2A) : autorisation d'agents orchestrateurs spécifiques à appeler des outils de domaine cible (par exemple, Concierge d'achat → Vendeur de burgers). | Niveau 1 (infrastructure de base) : accordez à tous les agents d'un projet un accès sortant aux API Google Cloud ( |
Impact sur le cycle de vie | Si un agent est supprimé et recréé, son nouvel ID de moteur nécessite une liaison de stratégie IAM mise à jour. | Elle s'applique automatiquement aux agents nouvellement déployés dans ce projet, sans nécessiter de mises à jour IAM supplémentaires. |
Gouvernance déclarative avec les règles d'accès unifiées (UAP / IAP v2)
Dans l'ancienne version 1 d'IAP, les règles de sortie étaient associées directement à des ressources Agent Registry individuelles à l'aide de gcloud beta iap web add-iam-policy-binding. Sous IAP v2 et stratégies d'accès unifiées, les liaisons par ressource sont supprimées au profit d'une stratégie d'accès IAM unique et centralisée (cfg/uap-rules.json).
L'autorisation de sortie de base pour core-gapi-services sera configurée en tant que Règle 1 dans la règle d'accès unifiée de la section 5. Cela garantit que tous les conteneurs d'agent disposent de routes de sortie de base avant le déploiement.
Pour en savoir plus sur les identifiants de compte principal et le fonctionnement de Workload Identity, consultez les ressources suivantes :
- Google Cloud IAM : Identifiants principaux et ensembles de principaux
- Fonctionnement de l'identité de l'agent
- Configurer les règles d'accès unifiées IAM pour Agent Gateway
L'enregistrement du point de terminaison des API principales est terminé. Passons à la section Déployer la passerelle d'agent centralisée.
4. Agent Gateway
Déployer une passerelle Agent Gateway centralisée
Déployez la passerelle Agent Gateway centralisée (centralized-agw) en mode sortie AGENT_TO_ANYWHERE dans le projet $PROJECT_GOVERNANCE.
Définir le fichier manifeste de configuration de la passerelle
Créez cfg/${AGW_NAME}.yaml pour la gouvernance du trafic de sortie :
# 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
Importer la configuration de l'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}
Vérifier les détails de l'Agent Gateway
# show agent gateway status
gcloud network-services agent-gateways describe ${AGW_NAME} \
--location=${REGION} \
--project=${PROJECT_GOVERNANCE}
Exemple de résultat :
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'
Le déploiement de la passerelle est terminé. Passons à la section Configurer l'autorisation.
5. Autorisation
Configurer l'autorisation de l'Agent Gateway et l'UAP de base
Agent Gateway sécurise et régit le trafic sortant des outils et des agents à l'aide de Règles d'autorisation (networksecurity.authzPolicies) intégrées aux Règles d'accès unifiées (RAU) d'Identity-Aware Proxy (IAP v2).
Présentation de l'architecture d'autorisation
Fig. 4. Présentation de l'architecture d'autorisation
L'architecture d'autorisation est composée de trois couches interconnectées :
- Extension de service IAP (
authzExtension) : ressource régionale configurée avecservice: iap.googleapis.com,metadata: iapPolicyVersion: "V2"etfailOpen: falsepour une application stricte du zéro confiance au niveau du périmètre. - Règle d'autorisation de passerelle (
authzPolicy) : ressource régionale ciblant votre Agent Gateway avecpolicyProfile: REQUEST_AUTHZetaction: CUSTOM, en acheminant les vérifications d'autorisation vers l'extension d'autorisation IAP. - Liaison et stratégie d'accès unifiées IAM (
accessPolicyetpolicyBinding) : ressource IAM v3 globale évaluée par IAP. Il vérifie l'autorisation universelleiap.googleapis.com/resources.egressViaIAPpar rapport aux identités SPIFFE de l'appelant et aux conditions du catalogue CEL.
Étape 1 : Créez et importez l'extension d'autorisation IAP v2
Créez le fichier manifeste de l'extension de service avec iapPolicyVersion: "V2" et failOpen: false en mode ENFORCE strict :
# 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
Importez l'extension d'autorisation :
# 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}
Vérifiez que l'extension Authz est active :
# describe authz extension
gcloud service-extensions authz-extensions describe ${AGW_NAME}-svc-ext-authz-iap \
--location=${REGION} \
--project=${PROJECT_GOVERNANCE}
Exemple de résultat :
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
Étape 2 : Créer et importer la règle d'autorisation de passerelle
Créez une configuration de règle d'autorisation qui s'associe à l'Agent Gateway et délègue la validation des requêtes à l'extension IAP Authz :
# create authz policy manifest
cat > cfg/${AGW_NAME}-authz-policy-profile-iap.yaml << EOF
name: ${AGW_NAME}-authz-policy-profile-iap
target:
resources:
- "projects/${PROJECT_GOVERNANCE}/locations/${REGION}/agentGateways/${AGW_NAME}"
policyProfile: REQUEST_AUTHZ
action: CUSTOM
customProvider:
authzExtension:
resources:
- "projects/${PROJECT_GOVERNANCE}/locations/${REGION}/authzExtensions/${AGW_NAME}-svc-ext-authz-iap"
EOF
Importez la règle d'autorisation :
# 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}
Vérifiez la règle d'autorisation active :
# describe authz policy
gcloud beta network-security authz-policies describe ${AGW_NAME}-authz-policy-profile-iap \
--location=${REGION} \
--project=${PROJECT_GOVERNANCE}
Étape 3 : Créer la règle d'accès unifiée initiale (Règle 1 : API Google principales)
Créez cfg/uap-rules.json avec la règle 1 autorisant les trois principalSet de projet à atteindre 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
Étape 4 : Créez et associez la stratégie d'accès IAM
Créez la stratégie d'accès 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
Associez la règle d'accès à 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
Vérifiez que l'association de règles est active :
# verify policy binding
gcloud iam policy-bindings describe ${UAP_BINDING_NAME} \
--project=${PROJECT_GOVERNANCE} \
--location=global
Exemple de résultat :
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}
L'accès sortant aux API Google Cloud de base est désormais autorisé de manière sécurisée pour les trois projets en mode ENFORCE strict.
La configuration de l'autorisation de la passerelle est terminée. Passons à la section Configurer les autorisations IAM multiprojets.
6. IAM entre plusieurs projets
Configurer les autorisations IAM multiprojets
Dans cette topologie multiprojet, les Agent Runtimes résident dans les projets spokes (PROJECT_CONCIERGE et PROJECT_SELLERS), tandis que l'Agent Gateway central et l'Agent Registry résident dans PROJECT_GOVERNANCE.
Étant donné que les projets Google Cloud sont des périmètres de sécurité isolés, l'accès inter-projets doit être accordé de manière explicite sur deux couches opérationnelles :
- Plan de contrôle (au moment du déploiement) : lorsque vous déployez un conteneur d'agent configuré avec
--agent-gateway-config, l'agent de service d'exécution de l'agent (service-) du projet spoke doit associer le conteneur à la passerelle centrale. Nous créons un rôle personnalisé minimal (@gcp-sa-aiplatform.iam.gserviceaccount.com ar_agw_cross_project_sa) qui accordenetworkservices.agentGateways.use,getetoperations.getdansPROJECT_GOVERNANCE. - Plan de données (exécution du runtime) :
- Découverte du catalogue : les identités Spoke ont besoin de
roles/agentregistry.viewerdansPROJECT_GOVERNANCEpour résoudre dynamiquement les points de terminaison de l'agent cible. - Invocation cible : l'agent Concierge a besoin de
roles/aiplatform.userdansPROJECT_SELLERSpour exécuter des requêtes sur les moteurs de raisonnement du marchand.
- Découverte du catalogue : les identités Spoke ont besoin de
Créer un rôle IAM personnalisé dans 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"
Attribuer un rôle personnalisé aux agents de service 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
La configuration IAM interprojets est terminée. Passons à la section Déployer les agents Seller et Concierge.
7. Agent Runtime
Déployer des agents vendeurs et de conciergerie
Le code de base de l'application multi-agents et les scripts de déploiement utilisés pour cet atelier de programmation sont conservés dans un dépôt GitHub Google Cloud distant. Les étapes suivantes cloneront le dépôt en local, copieront les fichiers nécessaires dans la structure du répertoire de travail actuel, effectueront le nettoyage des fichiers temporaires et installeront les dépendances avec uv.
Récupérer des artefacts distants
# 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
Créer un bucket de préproduction central partagé
# 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"
Fonctionnement de la liaison de passerelle Agent Gateway multiprojet
Dans cette étape, vous allez déployer les agents du vendeur dans le projet spoke (PROJECT_SELLERS) tout en les configurant pour qu'ils acheminent le trafic de sortie via l'Agent Gateway central dans 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)
Étant donné que la règle 1 a été établie plus tôt dans notre Unified Access Policy, les requêtes d'initialisation de conteneur adressées aux API Google Cloud sont autorisées via la passerelle sans interruption.
Déployer des agents vendeurs de burgers et de pizzas sur 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}
Valider le routage de la passerelle du marchand
# 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
Déployer l'agent Purchasing Concierge sur 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}
Valider le routage de la passerelle d'achat
# 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}'
Le résultat doit afficher l'identité et le projet d'exécution de l'agent Concierge, ainsi que la liaison à l'Agent Gateway du projet de gouvernance.
{
"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"
}
}
}
Les déploiements d'agents sont terminés. Passons à la section Enregistrer les agents dans le registre central des agents.
8. Registre interprojets
Enregistrer des agents dans le registre central des agents
Enregistrez les trois agents dans l'Agent Registry central de PROJECT_GOVERNANCE à l'aide de points de terminaison mTLS régionaux interprojets et de numéros de projet.
Enregistrer des services en tant qu'agents non A2A dans 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
Capturer les ID Agent Registry sous-jacents
# 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}"
La configuration du registre est terminée. Passons à la section Configurer les règles de sortie A2A.
9. Règles du PAU
Configurer des règles de sortie A2A dans la règle d'accès unifiée
Dans l'architecture Default Deny de la passerelle d'agent en mode ENFORCE strict :
- Règle 1 (API Google Cloud de référence) : autorise les conteneurs d'agents dans les trois projets à atteindre
core-gapi-services. - Règle 2 (Agent de vente de burgers : AUTORISER) : autorise spécifiquement l'instance de l'agent de concierge d'achat à appeler l'agent de vente de burgers.
- Agent de vente de pizzas (REFUSÉ par défaut) : intentionnellement exclu des règles du règlement. En mode
ENFORCE(failOpen: false), toute tentative du concierge d'appeler le vendeur de pizzas sera immédiatement interrompue au niveau de la passerelle avecHTTP 403 Forbidden.
Formuler l'identité de l'agent 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}"
Mettre à jour le fichier manifeste avec les règles 1 et 2
Créez un cfg/uap-rules-update-2.json pour inclure la Règle 1 (API Core) et la Règle 2 (Agent 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
Appliquer la stratégie d'accès mise à jour
# 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
Vérifier les détails de la stratégie d'accès IAM
# inspect updated access policy
gcloud iam access-policies describe ${UAP_POLICY_NAME} \
--project=${PROJECT_GOVERNANCE} \
--location=global
Exemple de résultat :
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 configuration des règles est terminée. Passons à la section Tester et valider les règles de gouvernance.
10. Valider les règles
Tester et valider les règles de gouvernance via Cloud Logging
Dans cette section, vous allez tester les interactions Agent-to-Agent (A2A) entre projets dans l'IA Playground Agent Runtime, observer le blocage HTTP 403 Forbidden réel du périmètre en mode strict ENFORCE, modifier les Règles d'accès unifiées en direct et valider l'approbation immédiate des commandes.
Étape 1 : Ouvrez le playground d'IA Agent Runtime dans PROJECT_CONCIERGE
- Ouvrez la console Google Cloud.
- Dans la barre de sélection de projet en haut de l'écran, passez à
PROJECT_CONCIERGE. - Dans le menu de navigation, accédez à Agent Platform > Agents > Déploiements.
- Cliquez sur
purchasing-concierge-adk. - Sélectionnez Playground pour ouvrir l'interface de chat interactive sur la droite de l'écran.
Étape 2 : Testez la commande de burger (correspondance avec la règle 2 → 200 OK)
Dans la fenêtre de chat de Playground, envoyez le prompt de commande suivant :
I would like 10 Classic Cheeseburgers. Place this order now.
Si une réponse de confirmation est nécessaire, envoyez la réponse suivante :
Confirmed, please place the order.
Vous pouvez également effectuer des tests par programmation à partir de Cloud Shell / du 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)
"
Si une réponse de confirmation est nécessaire, utilisez cette commande :
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'])
"
Que se passe-t-il en arrière-plan ?
- Découverte dynamique : au démarrage de la session, le service Purchasing Concierge a interrogé le registre central des agents dans
PROJECT_GOVERNANCE(viacore-gapi-servicespar le biais de la passerelle d'agent autorisée par la règle 1) pour découvrir le point de terminaison mTLS régional pourburger-seller-agent. - Résolution de l'intention et invocation A2A : Gemini intégré au service de conciergerie d'achat analyse l'intention de commande de nourriture et invoque l'agent Burger Seller via un RPC sortant vers
https://${REGION}-aiplatform.mtls.googleapis.com/.../reasoningEngines/${BURGER_ENGINE_ID}. - Interception de la passerelle et propagation SPIFFE : le trafic de sortie est capturé par
agent_gateway_configet dirigé vers la passerelle d'agent central dansPROJECT_GOVERNANCE, en transportant l'identité SPIFFE cryptographique du concierge (principal://...). - Évaluation des règles IAP v2 : l'Agent Gateway central appelle l'extension d'autorisation IAP (
authzExtension). IAP v2 évalue la règle 2 de la stratégie d'accès unifiée IAM. Étant donné que l'appelant correspond à${CONCIERGE_SPIFFE_PRINCIPAL}et que la cible correspond àburger-seller-agent, IAP renvoieALLOW(granted: true). - Exécution inter-projets : l'Agent Gateway sert de proxy pour la requête autorisée inter-projets dans
PROJECT_SELLERS, où le moteur de raisonnement du vendeur de burgers traite la commande et renvoie une confirmation.
Réponse attendue :
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
Étape 3 : Inspectez les journaux d'audit Agent Gateway et IAP v2 (HTTP 200 / AUTORISÉ)
Interrogez les journaux des requêtes Agent Gateway dans 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
)"
Les journaux doivent capturer le trafic sortant provenant des projets spokes (PROJECT_CONCIERGE et PROJECT_SELLERS) avec des champs de sortie pour les appels de raisonnement Gemini (generateContent), la télémétrie Cloud Trace (/v1/traces) et les recherches d'identifiants IAM, qui sont interceptés et autorisés de manière transparente par la règle 1 (core-gapi-services).
Interrogez les journaux d'audit Cloud Logging d'accès aux données IAP v2 pour vérifier la version de la règle 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
)"
Exemple de résultat :
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
Étape 4 : Tester la commande de pizza (refus par défaut -> HTTP 403 interdit APPLIQUÉ)
Dans la même fenêtre de chat Playground, envoyez le prompt suivant pour commander une pizza :
I would like 10 BBQ Chicken Pizzas. Place this order now.
Si une réponse de confirmation est nécessaire, envoyez la réponse suivante :
Confirmed, please place the order.
Vous pouvez également effectuer des tests par programmation à partir de Cloud Shell / du 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)
"
Si une réponse de confirmation est nécessaire, utilisez cette commande :
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'])
"
Réponse attendue :
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.
Que se passe-t-il en arrière-plan ?
- Découverte dynamique : le service de conciergerie des achats a résolu le point de terminaison
pizza-seller-agentà partir du registre central des agents au démarrage. - Résolution de l'intention et invocation A2A : Gemini dans le concierge d'achat tente d'envoyer la demande de commande de pizza au point de terminaison du vendeur de pizzas dans
PROJECT_SELLERS. - Interception de la passerelle : le RPC sortant est capturé par
agent_gateway_configet dirigé vers la passerelle Agent Gateway centrale. - Évaluation des règles IAP V2 (refus par défaut) : la passerelle Central Agent Gateway appelle IAP V2. Comme aucune règle ne correspond à
pizza-seller-agentdans la règle d'accès unifiée, IAP renvoieDENY(granted: false). - Blocage strict du périmètre : comme l'extension Authz est en mode ENFORCE (
failOpen: false), la passerelle d'agent central met immédiatement fin à la connexion sortante et renvoieHTTP 403 Forbidden. Le trafic ne quitte jamais la passerelle et n'atteint jamaisPROJECT_SELLERS.
Étape 5 : Inspecter les journaux de la passerelle de l'agent pour les requêtes bloquées (HTTP 403 / REFUSÉ)
# 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
)"
Exemple de résultat de journal refusé :
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
Interrogez les journaux d'audit des accès aux données IAP v2 pour connaître la décision de refus :
# 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
)"
Exemple de résultat de journal d'audit refusé :
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
Étape 6 : Accorder dynamiquement l'accès à la sortie à l'agent Pizza
Créez de nouveaux cfg/uap-rules-update-3.json pour inclure la Règle 1 (API Core), la Règle 2 (Agent de vente de burgers) et maintenant la Règle 3 (Agent de vente 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
Appliquez la mise à jour de la règle en direct :
# 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
Étape 7 : Interroger à nouveau l'agent Pizza (succès immédiat 200 OK)
Dans la fenêtre de chat de l'atelier, renvoyez le prompt de commande de pizza :
I would like 10 BBQ Chicken Pizzas. Place this order now.
Si une réponse de confirmation est nécessaire, envoyez la réponse suivante :
Confirmed, please place the order.
Vous pouvez également effectuer des tests par programmation à partir de Cloud Shell / du 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)
"
Si une réponse de confirmation est nécessaire, utilisez cette commande :
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'])
"
Réponse attendue :
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**
Que se passe-t-il en arrière-plan ?
- Actualisation dynamique des stratégies : la mise à jour de la stratégie d'accès unifiée IAM prend effet immédiatement dans le moteur d'évaluation IAP, sans temps d'arrêt et sans redéployer de conteneurs.
- Invocation A2A : le Concierge envoie la requête via l'Agent Gateway central.
- Évaluation de la stratégie IAP v2 (approbation) : IAP v2 correspond à la règle 3, valide l'identité de l'appelant et l'expression CEL cible, et renvoie
ALLOW(granted: true). - Exécution inter-projets : l'Agent Gateway central sert de proxy pour le trafic autorisé dans
PROJECT_SELLERS, où le vendeur de pizzas traite la commande.
Étape 8 : Inspecter les journaux de l'Agent Gateway pour les demandes de pizza accordées
# 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
)"
Exemple de résultat de journal d'accès accordé :
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
Les tests et la validation sont terminés. Passons à la section Nettoyage.
11. Nettoyage
Pour éviter que les ressources utilisées dans cet atelier de programmation soient facturées sur votre compte Google Cloud, exécutez les étapes de suppression dans l'ordre inverse des dépendances :
1. Nettoyer les déploiements Reasoning Engine
Exécutez le script cleanup_old_deployments.py inclus dans les deux projets d'exécution pour supprimer les moteurs de raisonnement et attendre la fin de leurs opérations de longue durée :
# 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}
Vous pouvez également lister et supprimer les moteurs de raisonnement en ligne :
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. Supprimer les services 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. Supprimer une liaison de stratégie d'accès unifiée IAM et une stratégie d'accès
# 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. Supprimer l'Agent Gateway et les règles de sécurité
# 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. Supprimer les liaisons IAM et le rôle personnalisé inter-projets
# 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 vous avez attribué les rôles roles/iam.accessPolicyAdmin et roles/resourcemanager.projectIamAdmin lors de la phase de configuration, supprimez-les de votre compte utilisateur actif pour rétablir le principe de moindre privilège :
# 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. Rétablir la journalisation des données d'audit et les contraintes liées aux règles d'administration
# 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. Rétablir les contraintes liées aux règles d'administration
# 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. Supprimer le bucket de préproduction GCS partagé et les artefacts locaux
# 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
La partie sur le nettoyage est terminée. Passons à la conclusion !
12. Conclusion
Félicitations ! Vous avez déployé et géré une architecture Agent-to-Agent (A2A) multiprojets sur Google Cloud à l'aide de Vertex AI Agent Runtime, de Central Agent Gateway, d'Agent Registry et des stratégies d'accès unifiées (UAP) IAM.
Résumé des concepts clés
- Périmètre de sortie centralisé : conteneurs d'exécution de spokes routés (
PROJECT_CONCIERGE,PROJECT_SELLERS) via une passerelle Agent Gateway centrale dansPROJECT_GOVERNANCEà l'aide deagentGatewayConfig. - Gouvernance déclarative (UAP) : les liaisons fragmentées par ressource ont été remplacées par une stratégie d'accès IAM unique et auditable, évaluée au niveau de la passerelle par IAP v2.
- Identité cryptographique : sortie avec le moindre privilège appliqué à l'aide des identités SPIFFE de conteneur (
principal://...) plutôt que des clés à longue durée de vie. - Découverte dynamique des services : les points de terminaison des agents pairs sont résolus au moment de l'exécution via le registre d'agents centraux, ce qui élimine les URL et les ID de projet codés en dur.
- Agilité des règles d'exécution : la valeur
pizza-seller-agentest passée de "Refus par défaut" (403 Forbidden) à "Autorisé" (200 OK) en temps réel via une mise à jour des règles, sans redémarrage des conteneurs.

Cosmopup : "Les agents sont géniaux. Ils s'occupent de toutes les tâches interprojets pendant que je me concentre sur mon objectif principal : faire la sieste !"
Étapes suivantes et documentation
- Présentation de Gemini Enterprise Agent Platform
- Configurer et déployer Agent Gateway
- Analyse approfondie de l'identité de l'agent et de l'attestation SPIFFE
- Règles d'accès unifiées IAM et attributs CEL
- Présentation du catalogue de services du registre d'agents
- Garde-fous Model Armor et protection des données sensibles
- Interfaces Private Service Connect (PSC-I) avec Agent Gateway