Zentrale Governance mit Agent Gateway und projektübergreifender Agent Registry für Agent Runtime

1. Einführung

Im Zuge der Einführung generativer KI in Unternehmen entwickeln sich die Architekturen rasant von eigenständigen, monolithischen Chatbots zu verteilten Multi-Agenten-Systemen (Agent-to-Agent / A2A). In diesen modernen Topologien koordinieren übergeordnete Orchestrator-Agenten komplexe Geschäftsworkflows, indem sie Aufgaben an spezialisierte Domain-Worker-Agenten, MCP-Tool-Server (Model Context Protocol) und Backend-Unternehmensdatenbanken in unabhängigen Google Cloud-Projekten delegieren.

Der Betrieb von Multi-Agenten-Systemen in großem Maßstab bringt jedoch erhebliche Herausforderungen in Bezug auf Sicherheit, Governance und Betrieb mit sich:

  • Schatten-Agenten und Tool-Wildwuchs: Wenn Entwicklungsteams Agenten in isolierten Projekten ohne zentralen Katalog bereitstellen, verlieren Organisationen den Überblick darüber, welche Tools und Sub-Agenten vorhanden sind.
  • Unüberwachter projektübergreifender ausgehender Traffic: Wenn KI-Agenten direkte, nicht geprüfte Netzwerkrouten nutzen können, besteht das Risiko einer Daten-Exfiltration und Sicherheitsperimeter werden umgangen.
  • Anfällige hartcodierte Integrationen: Das Hartcodieren von URLs nachgelagerter Agenten und Reasoning Engine-IDs führt zu anfälligen Abhängigkeiten, die bei Upgrades oder erneuten Bereitstellungen zu Fehlern führen können.
  • Fehlende Identität mit geringsten Berechtigungen: Geteilte Dienstkonten bieten keine kryptografische Nichtabstreitbarkeit auf der Ebene einzelner Agenteninstanzen.

Die Gemini Enterprise Agent Platform bietet eine einheitliche Governance- und Konnektivitätssteuerungsebene, die aus vier Kernbereichen besteht:

  1. Agent Gateway (networkservices.googleapis.com): Ein verwalteter, regionaler Proxy für die Netzwerk- und Richtlinienerzwingung. Im AGENT_TO_ANYWHERE-Modus für ausgehenden Traffic fängt er ausgehenden Agent-Traffic ab, delegiert Autorisierungsprüfungen an Sicherheitserweiterungen und leitet Anfragen über Projektperimeter hinweg weiter.
  2. Agent Registry (agentregistry.googleapis.com): Der zentrale Service Catalog für Unternehmen. Sie bietet ein zentrales, geprüftes Verzeichnis aller verfügbaren Tools, MCP-Server und Peer-Agenten im gesamten Unternehmen und ermöglicht so eine dynamische automatische Erkennung zur Laufzeit ohne hartcodierte Endpunkte.
  3. Agent Identity & IAP v2 Governance (iap.googleapis.com und iam.googleapis.com): Ein kryptografisches Identitäts- und Zugriffsframework. Ausführende Agents erhalten eindeutige, attestierte SPIFFE-Maschinen-URNs (principal://...). Ausgehender Traffic wird anhand zentraler IAM Unified Access Policies (UAP/IAP v2) ausgewertet, wobei die universelle Berechtigung iap.googleapis.com/resources.egressViaIAP mithilfe umfangreicher Common Expression Language (CEL) Katalogbedingungen (destination.agent_registry.*) überprüft wird.
  4. Agent Runtime (Reasoning Engines): Eine vollständig verwaltete, serverlose Ausführungsplattform für Python-basierte agentische Anwendungen mit nativen Konfigurationsbindungen (agent_gateway_config) an zentrale Gateways.

Das Codelab-Geschäftsszenario: Multi-Projekt-Einkauf von Lebensmitteln und Getränken

In diesem Codelab erstellen und verwalten Sie ein reales, projektübergreifendes Einkaufssystem, das sich über drei verschiedene Google Cloud-Projekte erstreckt:

  • Zentrales Governance-Projekt (PROJECT_GOVERNANCE): Gehört der zentralen IT und SecOps und hostet das zentrale Agent Gateway, die zentrale Agent Registry und die einheitlichen IAM-Zugriffsrichtlinien.
  • Consumer Orchestrator Project (PROJECT_CONCIERGE): Gehört dem Beschaffungsteam und hostet den Purchasing Concierge Agent, der dynamisch Anbieter findet und Kundenbestellungen weiterleitet.
  • Domain Vendor Project (PROJECT_SELLERS): Gehört externen oder abteilungsinternen Anbietern und hostet den Burger Seller Agent und den Pizza Seller Agent.

figure1

Abbildung 1: Zentralisierte Governance-Architektur für mehrere Projekte

Warum projektübergreifende zentralisierte Governance?

In großen Unternehmen erstellen Produktteams und Data-Science-Gruppen KI-Agenten in Dutzenden von unabhängigen Google Cloud-Projekten. Wenn jedes Team die direkte Kontrolle über die Toolregistrierung, ausgehende Netzwerkrouten und Sicherheitsmaßnahmen hat, führt dies zu einer unkontrollierten Toolverbreitung, inkonsistenten DLP-Richtlinien, unüberwachtem ausgehendem VPC-Traffic und fragmentierten Audit-Logs.

Die projektübergreifende zentrale Governance trennt die Richtlinienerstellung von der Ausführung durch den KI-Agenten:

  • Zentrale IT- und SecOps-Teams erstellen Sicherheitsrichtlinien, prüfen Tools und überwachen ausgehenden Traffic in einem einzigen zentralen Governance-Projekt.
  • Produkt- und Anwendungsteams konzentrieren sich in ihren unabhängigen Agent Runtime-Projekten ausschließlich auf die Geschäftslogik und binden diese direkt an das zentrale Gateway an. So entfällt der operative Aufwand für die Verwaltung lokaler VPCs, Interconnects oder fragmentierter Policy Engines.

figure2

Abb. 2: Dreistufige projektübergreifende Governance-Architektur und -Grenzen

Zweistufiges Identitätsbereichsmodell in Unified Access Policies

Wenn Agenten über das Central Agent Gateway kommunizieren, wertet Identity-Aware Proxy (IAP v2) den Zugriff anhand der Agentenidentität des Aufrufers aus. Dies ist eine kryptografisch bestätigte, SPIFFE-basierte Identität, die dem Laufzeitcontainer automatisch ausgestellt wird. Der Zugriff wird anhand einer globalen IAM-Zugriffsrichtlinie geprüft:

  • Stufe 1: Google Cloud-Basis-APIs (grob über principalSet:// in Regel 1): Projektweite Autorisierung für ausgehenden Traffic, die allen Agent-Laufzeiten in Spoke-Projekten den Zugriff auf Standard-Google-APIs (aiplatform, iamcredentials, telemetry, agentregistry) für die Erkennung, Tokengenerierung und Inferenz ermöglicht.
  • Stufe 2: Geschäftstools und A2A-Dienste (feingranular über principal:// in Regel 2 und 3): Strikter Zugriff mit den geringsten Berechtigungen, der an einzelne Reasoning Engine-Instanzen gebunden ist und mit CEL-Bedingungen (Common Expression Language) erzwungen wird, die auf bestimmte registrierte Agent Registry-Dienste (destination.agent_registry.agent.name) abzielen.

Was Sie erstellen

  • Zentrales Agent Gateway (centralized-agw) in PROJECT_GOVERNANCE
  • IAP v2-Autorisierungsdienst-Erweiterung und Autorisierungsrichtlinie im strengen ENFORCE-Modus (failOpen: false)
  • Grundlegende IAM Unified Access Policy (uap-rules.json) und Projektrichtlinienbindung
  • Projektübergreifende IAM-Berechtigungen für Dienst-Agents (ar_agw_cross_project_sa)
  • Freigegebener zentraler Google Cloud Storage-Staging-Bucket (GCS)
  • Isolierte Burger- und Pizzaverkäufer-Agents in PROJECT_SELLERS
  • Concierge-Agent für Einkäufe mit dynamischer REST-Autodiscovery in PROJECT_CONCIERGE
  • Dienstregistrierungen in Central Agent Registry mit projektübergreifenden mTLS-URLs
  • Dynamische Aktualisierungen der IAP v2-Richtlinie für ausgehenden Traffic mit Live-Überprüfung und Cloud Logging-Audits

figure3

Abb. 3: Schrittweise Implementierung

Lerninhalte

  • Projektübergreifende IAM-Berechtigungen für Dienst-Agents für zentralisierte Gateways konfigurieren
  • Ausgehenden Traffic der Agent Runtime über ein zentrales Agent Gateway in Umgebungen mit mehreren Projekten weiterleiten
  • Agent Gateway-Autorisierung mit Service Extensions (iapPolicyVersion: "V2") an Identity-Aware Proxy (IAP v2) delegieren
  • IAM Unified Access Policies (UAP) mit CEL-Regeln (Common Expression Language) erstellen und binden, die für registrierte Agent Registry-Ziele (destination.agent_registry.*) gelten
  • Hardcodierte Agent-IDs und URLs mithilfe der automatischen Laufzeiterkennung in der Agent Registry eliminieren
  • Wie Sie die Zero-Trust-Blockierung (HTTP 403 Forbidden) testen und Live-Richtlinienaktualisierungen in Cloud Logging prüfen

Voraussetzungen

  • 3 Google Cloud-Projekte mit aktivierter Abrechnung:
    • PROJECT_GOVERNANCE: Zentrale Governance, Gateway, Registry und IAM-Zugriffsrichtlinien
    • PROJECT_CONCIERGE: Orchestrator-Agent für den Einkaufs-Concierge
    • PROJECT_SELLERS: Verkäuferagenten, die auf Burger und Pizza spezialisiert sind
  • Ein IAM-Nutzer oder ein Dienstkonto mit roles/owner- oder Administratorberechtigungen für alle drei Projekte
  • Eine Google Cloud-Organisation (für die Zuordnung von SPIFFE-Vertrauensdomänen)
  • Google Cloud Shell oder einen lokalen Computer mit installierter gcloud-Befehlszeile, python (3.11+) und uv

Damit ist die Einführung abgeschlossen. Als Nächstes folgt der Abschnitt Einrichtung und Umgebung.

2. Einrichtung

Obwohl diese Architektur drei verschiedene Google Cloud-Projekte umfasst, können Sie alle Terminalbereitstellungsbefehle, Repository-Downloads und Staging-Vorgänge über ein einziges Cloud Shell-Terminal ausführen, das auf PROJECT_GOVERNANCE festgelegt ist. Jedes Bereitstellungsskript und jeder gcloud-Befehl zielt explizit über CLI-Flags (--project) auf das entsprechende Zielprojekt ab.

Rufen Sie zuerst die Befehlszeile Ihres Google Cloud-Projekts auf:

Projektkontext festlegen

# 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
# update gcloud components
gcloud components update --quiet

Shell-Umgebungsvariablen festlegen

Geben Sie Ihre projektspezifischen Kennungen ein.

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

Diese Shell-Variablen werden automatisch abgeleitet.

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

Lokales Verzeichnis für Konfigurationsdateien erstellen

# create config folder
mkdir -p cfg

Rolle „Access Policy Admin“ für Unified Access Policies zuweisen

# 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

Cloud-Audit-Datenzugriffslogs für IAP v2 aktivieren

In Google Cloud sind Audit-Logs zum Datenzugriff standardmäßig deaktiviert, um unbeabsichtigte Speicherkosten zu vermeiden. Da IAP v2 Autorisierungsentscheidungen (granted=true und granted=false) als Audit-Logs zum Datenzugriff ausgibt, aktivieren Sie das Logging für ADMIN_READ, DATA_READ und DATA_WRITE für 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)"

Erforderliche Google Cloud APIs aktivieren

# enable google apis (agent platform & security bundle, part 1)
for PROJ in ${PROJECT_GOVERNANCE} ${PROJECT_CONCIERGE} ${PROJECT_SELLERS}; do
  gcloud services enable \
    agentregistry.googleapis.com \
    aiplatform.googleapis.com \
    apphub.googleapis.com \
    apptopology.googleapis.com \
    cloudapiregistry.googleapis.com \
    cloudtrace.googleapis.com \
    compute.googleapis.com \
    dataform.googleapis.com \
    iam.googleapis.com \
    agentidentity.googleapis.com \
    iap.googleapis.com \
    logging.googleapis.com \
    modelarmor.googleapis.com \
    monitoring.googleapis.com \
    networksecurity.googleapis.com \
    networkservices.googleapis.com \
    notebooks.googleapis.com \
    observability.googleapis.com \
    --project=${PROJ}
done
# enable google apis (agent platform bundle, part 2)
for PROJ in ${PROJECT_GOVERNANCE} ${PROJECT_CONCIERGE} ${PROJECT_SELLERS}; do
  gcloud services enable \
    securitycenter.googleapis.com \
    saasservicemgmt.googleapis.com \
    storage.googleapis.com \
    telemetry.googleapis.com \
    texttospeech.googleapis.com \
    --project=${PROJ}
done
# enable google apis (foundational & agent runtime build bundle, part 3)
for PROJ in ${PROJECT_GOVERNANCE} ${PROJECT_CONCIERGE} ${PROJECT_SELLERS}; do
  gcloud services enable \
    artifactregistry.googleapis.com \
    cloudbuild.googleapis.com \
    cloudresourcemanager.googleapis.com \
    iamcredentials.googleapis.com \
    serviceusage.googleapis.com \
    run.googleapis.com \
    orgpolicy.googleapis.com \
    --project=${PROJ}
done

API-Aktivierung in allen Projekten prüfen

Wenn Sie dafür sorgen, dass in allen drei Projekten (PROJECT_GOVERNANCE, PROJECT_CONCIERGE und PROJECT_SELLERS) genau dieselben APIs aktiviert sind, wird die betriebliche Konsistenz gewährleistet und es werden Fehler bei der Token-Erstellung zur Laufzeit, Fehler bei der Schemakatalogisierung oder Telemetrieausfälle vermieden.

Führen Sie das folgende Validierungsskript in Cloud Shell aus, um die API-Parität in allen drei Projekten zu prüfen:

# 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

Beispiel für eine Validierungsausgabe:

Alle APIs sollten aktiviert sein.

✅ All 30 required APIs are ENABLED and synchronized across all three projects.

Organisationsrichtlinien konfigurieren

In den Standardrichtlinien für Google Cloud-Organisationen werden Einschränkungen erzwungen, die IAM v3-Zugriffsrichtlinienbindungen an Ressourcen (constraints/iam.managed.disableAccessPolicyBinding) einschränken.

Überschreiben Sie alle übernommenen Einschränkungen der Organisationsrichtlinie auf Projektebene, indem Sie enforce: false explizit auf „Zulassen“ setzen.

# 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

Damit ist die Einrichtung abgeschlossen. Als Nächstes folgt der Abschnitt Wichtige Google APIs registrieren.

3. Agent Registry

Core Google APIs Endpoint Service registrieren

Das Agent Gateway erfordert, dass Google API-URLs in der Central Agent Registry registriert sind, damit mit agent_gateway_config konfigurierte Agents ausgehenden Traffic sicher an wichtige Google Cloud-Backend-Dienste (wie aiplatform, IAM-Anmeldedaten und Telemetrie) weiterleiten können.

core-gapi-services in Agent Registry erstellen

# 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

Ressourcen-ID des API-Endpunkts der Capture Core APIs

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

Unterschied zwischen principalSet und principal bei der KI-Agentenidentität

In Google Cloud IAM und der Gemini Enterprise Agent Platform verwenden Maschinenidentitäten, die für ausführende Agent-Container ausgestellt werden, kryptografisch bestätigte SPIFFE-URNs, die von Identity-Aware Proxy (IAP v2) ausgewertet werden. Beim Konfigurieren von IAM Unified Access Policies können Sie entweder eine bestimmte einzelne principal oder eine attributbasierte principalSet als Ziel festlegen:

Dimension

principal:// (Einzelne Maschinenidentität)

principalSet:// (attributbasierte Gruppe)

IAM-Syntax

principal://...

principalSet://...

Detaillierungsgrad

Detailliert (auf Instanzebene): Identifiziert eine einzelne, spezifische Reasoning Engine-Containerinstanz.

Grobkörnig (auf Projektebene): Identifiziert alle Reasoning Engines, die ein gemeinsames Projektattribut haben.

URN-Muster

principal://agents.global.org-${ORG_ID}.system.id.goog/resources/aiplatform/projects/${PROJECT_NUMBER}/locations/${REGION}/reasoningEngines/${ENGINE_ID}

principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJECT_NUMBER}

Anwendungsfall in der Agent Platform

Stufe 2 (Business Tools und A2A): Bestimmte Orchestrator-Agents werden autorisiert, Tools der Zieldomain aufzurufen (z.B. Einkaufs-Concierge $\rightarrow$ Burger-Verkäufer).

Stufe 1 (Grundlegende Infrastruktur): Gewährt allen Agents in einem Projekt ausgehenden Zugriff auf Google Cloud APIs (core-gapi-services).

Auswirkungen auf den Lebenszyklus

Wenn ein Agent gelöscht und neu erstellt wird, ist für seine neue Engine-ID eine aktualisierte IAM-Richtlinienbindung erforderlich.

Wird automatisch auf neu bereitgestellte KI-Agenten in diesem Projekt angewendet, ohne dass zusätzliche IAM-Updates erforderlich sind.

Deklarative Governance mit Unified Access Policies (UAP/IAP v2)

In der Legacy-Version von IAP v1 wurden Richtlinien für ausgehenden Traffic direkt an einzelne Agent Registry-Ressourcen mit gcloud beta iap web add-iam-policy-binding angehängt. Unter IAP v2 und Unified Access Policies werden Bindungen pro Ressource zugunsten einer einzelnen, zentralen IAM-Zugriffsrichtlinie (cfg/uap-rules.json) eliminiert.

Die grundlegende Autorisierung für ausgehenden Traffic für core-gapi-services wird als Regel 1 in der Unified Access Policy in Abschnitt 5 konfiguriert. Dadurch wird sichergestellt, dass alle Agent-Container vor der Bereitstellung grundlegende Routen für ausgehenden Traffic haben.

Ausführliche technische Informationen zu Hauptkonto-IDs und zur Funktionsweise von Workload Identity finden Sie hier:

Damit ist die Registrierung des API-Endpunkts für die Core APIs abgeschlossen. Als Nächstes folgt der Abschnitt Zentrales Agent-Gateway bereitstellen.

4. Agent Gateway

Zentrales Agent Gateway bereitstellen

Stellen Sie das zentrale Agent Gateway (centralized-agw) im Modus für ausgehenden Traffic (AGENT_TO_ANYWHERE) im Projekt $PROJECT_GOVERNANCE bereit.

Gateway-Konfigurationsmanifest definieren

Erstellen Sie cfg/${AGW_NAME}.yaml für die Governance von ausgehendem Traffic:

# 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

Konfiguration des KI-Agenten-Gateways importieren

# import and create agent gateway
gcloud network-services agent-gateways import ${AGW_NAME} \
  --source="cfg/${AGW_NAME}.yaml" \
  --location=${REGION} \
  --project=${PROJECT_GOVERNANCE}

Details zum KI-Agenten-Gateway prüfen

# show agent gateway status
gcloud network-services agent-gateways describe ${AGW_NAME} \
  --location=${REGION} \
  --project=${PROJECT_GOVERNANCE}

Beispielausgabe:

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'

Damit ist die Gateway-Bereitstellung abgeschlossen. Weiter geht es mit dem Abschnitt Autorisierung konfigurieren.

5. Autorisierung

Autorisierung für KI-Agenten-Gateway und grundlegende UAP konfigurieren

Das Agent Gateway sichert und steuert den ausgehenden Tool- und Agenten-Traffic mithilfe von Autorisierungsrichtlinien (networksecurity.authzPolicies), die in Unified Access Policies (UAP) von Identity-Aware Proxy (IAP v2) integriert sind.

Übersicht über die Autorisierungsarchitektur

figure4

Abb. 4: Übersicht über die Autorisierungsarchitektur

Die Autorisierungsarchitektur besteht aus drei miteinander verbundenen Ebenen:

  1. IAP-Service Extension (authzExtension): Regionale Ressource, die mit service: iap.googleapis.com, metadata: iapPolicyVersion: "V2" und failOpen: false für die strikte Durchsetzung von Zero-Trust-Perimetern konfiguriert ist.
  2. Gateway-Autorisierungsrichtlinie (authzPolicy): Regionale Ressource, die mit policyProfile: REQUEST_AUTHZ und action: CUSTOM auf Ihr Agent Gateway abzielt und Autorisierungsprüfungen an die IAP-Autorisierungserweiterung weiterleitet.
  3. IAM Unified Access Policy & Binding (accessPolicy & policyBinding): Globale IAM v3-Ressource, die von IAP ausgewertet wird. Die universelle Berechtigung iap.googleapis.com/resources.egressViaIAP wird anhand der SPIFFE-Identitäten des Aufrufers und der CEL-Katalogbedingungen geprüft.

Schritt 1: IAP v2-Authz-Erweiterung erstellen und importieren

Erstellen Sie das Diensterweiterungsmanifest mit iapPolicyVersion: "V2" und failOpen: false im strikten ENFORCE-Modus:

# 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

Importieren Sie die Autorisierungserweiterung:

# 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}

Prüfen Sie, ob die Authz-Erweiterung aktiv ist:

# describe authz extension
gcloud service-extensions authz-extensions describe ${AGW_NAME}-svc-ext-authz-iap \
  --location=${REGION} \
  --project=${PROJECT_GOVERNANCE}

Beispielausgabe:

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

Schritt 2: Gateway-Autorisierungsrichtlinie erstellen und importieren

Erstellen Sie eine Autorisierungsrichtlinien-Konfiguration, die an das Agent-Gateway angehängt wird und die Anfrageprüfung an die IAP-Authz-Erweiterung delegiert:

# 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

Importieren Sie die Autorisierungsrichtlinie:

# 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}

Prüfen Sie die aktive Autorisierungsrichtlinie:

# describe authz policy
gcloud beta network-security authz-policies describe ${AGW_NAME}-authz-policy-profile-iap \
  --location=${REGION} \
  --project=${PROJECT_GOVERNANCE}

Schritt 3: Erste Unified Access Policy erstellen (Regel 1: Core Google APIs)

Erstellen Sie cfg/uap-rules.json mit Regel 1, die die drei Projekt-principalSets autorisiert, core-gapi-services zu erreichen:

# 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

Schritt 4: IAM-Zugriffsrichtlinie erstellen und binden

Erstellen Sie die globale IAM-Zugriffsrichtlinie:

# create global IAM access policy
gcloud iam access-policies create ${UAP_POLICY_NAME} \
  --details-rules=cfg/uap-rules.json \
  --project=${PROJECT_GOVERNANCE} \
  --location=global

Binden Sie die Zugriffsrichtlinie an 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

Prüfen Sie, ob die Richtlinienbindung aktiv ist:

# verify policy binding
gcloud iam policy-bindings describe ${UAP_BINDING_NAME} \
  --project=${PROJECT_GOVERNANCE} \
  --location=global

Beispielausgabe:

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}

Der ausgehende Traffic der grundlegenden Google Cloud API ist jetzt in allen drei Projekten im strikten ENFORCE-Modus sicher autorisiert.

Damit ist die Einrichtung der Gateway-Autorisierung abgeschlossen. Als Nächstes folgt der Abschnitt Projektübergreifende IAM-Berechtigungen konfigurieren.

6. Projektübergreifendes IAM

Projektübergreifende IAM-Berechtigungen konfigurieren

In dieser Topologie mit mehreren Projekten befinden sich die Agent Runtimes in Spoke-Projekten (PROJECT_CONCIERGE und PROJECT_SELLERS), während sich das zentrale Agent Gateway und die Agent Registry in PROJECT_GOVERNANCE befinden.

Da Google Cloud-Projekte isolierte Sicherheitsbereiche sind, muss der projektübergreifende Zugriff explizit auf zwei Betriebsebenen gewährt werden:

  1. Steuerungsebene (Bereitstellungszeit): Wenn Sie einen Agent-Container bereitstellen, der mit --agent-gateway-config konfiguriert ist, muss der Agent Runtime-Dienst-Agent (service-@gcp-sa-aiplatform.iam.gserviceaccount.com) des Spoke-Projekts den Container an das zentrale Gateway anhängen. Wir erstellen eine minimale benutzerdefinierte Rolle (ar_agw_cross_project_sa), die networkservices.agentGateways.use, get und operations.get in PROJECT_GOVERNANCE gewährt.
  2. Datenebene (Laufzeitausführung):
    • Katalogerkennung: Spoke-Identitäten benötigen roles/agentregistry.viewer in PROJECT_GOVERNANCE, um Ziel-Agent-Endpunkte dynamisch aufzulösen.
    • Zielaufruf: Der Concierge-Agent benötigt roles/aiplatform.user in PROJECT_SELLERS, um Abfragen an die Reasoning Engines des Verkäufers auszuführen.

Benutzerdefinierte IAM-Rolle in PROJECT_GOVERNANCE erstellen

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

Benutzerdefinierte Rolle den Agent Runtime-Dienst-Agents zuweisen

# 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

Damit ist die projektübergreifende IAM-Einrichtung abgeschlossen. Als Nächstes folgt der Abschnitt Verkäufer- und Concierge-Agenten bereitstellen.

7. Agent Runtime

Verkäufer- und Concierge-Agenten bereitstellen

Die Codebasis und die Bereitstellungsskripts für die Multi-Agenten-Anwendung, die in diesem Codelab verwendet werden, werden in einem Remote-Google Cloud-GitHub-Repository verwaltet. In den folgenden Schritten wird das Repository lokal geklont, die erforderlichen Dateien werden in die aktuelle Arbeitsverzeichnisstruktur kopiert, temporäre Dateien werden bereinigt und Abhängigkeiten werden mit uv installiert.

Remote-Artefakte abrufen

# 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

Gemeinsamen zentralen Staging-Bucket erstellen

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

Funktionsweise der projektübergreifenden Agent-Gateway-Bindung

In diesem Schritt stellen Sie die Verkäufer-Agenten im Spoke-Projekt (PROJECT_SELLERS) bereit und konfigurieren sie so, dass ausgehender Traffic über das zentrale Agenten-Gateway in PROJECT_GOVERNANCE geleitet wird:

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

Da Regel 1 zuvor in unserer Unified Access Policy festgelegt wurde, werden Containerinitialisierungsanfragen an Google Cloud APIs ohne Unterbrechung über das Gateway zugelassen.

Burger- und Pizzaverkäufer-Agenten in PROJECT_SELLERS bereitstellen

# 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}

Routing des Verkäufer-Gateways validieren

# 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

Purchasing Concierge-Agent in PROJECT_CONCIERGE bereitstellen

# 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}

Routing des Einkaufs-Gateways validieren

# 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}'

In der Ausgabe sollten die Concierge-Agent-Agent Runtime-Identität und das Projekt sowie die Bindung an das Agent-Gateway des Governance-Projekts angezeigt werden.

{
  "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"
    }
  }
}

Damit sind die Agentenbereitstellungen abgeschlossen. Als Nächstes folgt der Abschnitt Agenten in der zentralen Agent Registry registrieren.

8. Projektübergreifende Registry

KI-Agenten in der zentralen Agent Registry registrieren

Registrieren Sie alle drei Agenten in der Central Agent Registry in PROJECT_GOVERNANCE mit projektübergreifenden regionalen mTLS-Endpunkten und numerischen Projektnummern.

Dienste als Nicht-A2A-Agenten in der Agent Registry registrieren

# 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

Zugrunde liegende Agent Registry-IDs erfassen

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

Damit ist die Registry-Konfiguration abgeschlossen. Weiter geht es mit dem Abschnitt Richtlinien für ausgehenden A2A-Traffic konfigurieren.

9. UAP-Richtlinien

A2A-Richtlinien für ausgehenden Traffic in Unified Access Policy konfigurieren

In der Default Deny-Architektur des KI-Agenten-Gateways im strikten ENFORCE-Modus:

  1. Regel 1 (Google Cloud APIs-Baseline): Ermöglicht Agent-Containern in allen drei Projekten, core-gapi-services zu erreichen.
  2. Regel 2 (Burger Seller Agent: ALLOW): Erlaubt der Purchasing Concierge Agent-Instanz, den Burger Seller Agent aufzurufen.
  3. Pizza Seller Agent (standardmäßig ABGELEHNT): Wurde absichtlich aus den Richtlinienregeln ausgeschlossen. Im ENFORCE-Modus (failOpen: false) wird jeder Versuch des Concierge, den Pizza Seller aufzurufen, sofort am Gateway-Perimeter mit HTTP 403 Forbidden beendet.

Identität des Concierge-Agenten formulieren

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

Update-Manifest mit Regel 1 und 2 aktualisieren

Wenn Sie die Zugriffsrichtlinie sicher aktualisieren möchten, ohne vorhandene Regeln zu überschreiben, definieren Sie das vollständige konsolidierte Manifest mit Regel 1 (Core Google APIs) und Regel 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

Aktualisierte Zugriffsrichtlinie anwenden

Wenden Sie das konsolidierte Regelmanifest deklarativ mit --details-rules an:

# 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

Details zur IAM-Zugriffsrichtlinie prüfen

# inspect updated access policy
gcloud iam access-policies describe ${UAP_POLICY_NAME} \
  --project=${PROJECT_GOVERNANCE} \
  --location=global

Beispielausgabe:

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

Damit ist die Einrichtung der Richtlinie abgeschlossen. Als Nächstes folgt der Abschnitt Governance-Richtlinien testen und prüfen.

10. Richtlinien prüfen

Governance-Richtlinien über Cloud Logging testen und prüfen

In diesem Abschnitt testen Sie projektübergreifende Agent-to-Agent-Interaktionen (A2A) im Agent Runtime AI Playground, beobachten die tatsächliche Blockierung von HTTP 403 Forbidden im strikten ENFORCE-Modus, ändern die Unified Access Policy live und prüfen die sofortige Genehmigung von Bestellungen.

Schritt 1: Agent Runtime AI Playground in PROJECT_CONCIERGE öffnen

  1. Öffnen Sie die Google Cloud Console.
  2. Wechseln Sie in der oberen Projektauswahlleiste zu PROJECT_CONCIERGE.
  3. Rufen Sie im Navigationsmenü Agent Platform > Agents > Deployments auf.
  4. Klicken Sie auf purchasing-concierge-adk.
  5. Wählen Sie Playground aus, um die interaktive Chatoberfläche auf der rechten Seite des Bildschirms zu öffnen.

Schritt 2: Burgerbestellung testen (Regel 2-Übereinstimmung -> 200 OK)

Geben Sie im Chatfenster des Playgrounds den folgenden Prompt ein:

I would like 10 Classic Cheeseburgers. Place this order now.

Wenn eine Bestätigung erforderlich ist, senden Sie die folgende Antwort:

Confirmed, please place the order.

Alternativ können Sie den Test programmatisch über Cloud Shell / das Terminal ausführen:

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

Wenn eine Bestätigungsantwort erforderlich ist, verwenden Sie diesen Befehl:

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

Was passiert hinter den Kulissen:

  1. Dynamische Erkennung: Beim Start der Sitzung hat der Purchasing Concierge die Central Agent Registry in PROJECT_GOVERNANCE (über core-gapi-services über das Agent Gateway, autorisiert durch Regel 1) abgefragt, um den regionalen mTLS-Endpunkt für burger-seller-agent zu ermitteln.
  2. Intent-Auflösung und A2A-Aufruf: Gemini im Purchasing Concierge parst den Intent für die Essensbestellung und ruft den Burger Seller Agent über einen ausgehenden RPC an https://${REGION}-aiplatform.mtls.googleapis.com/.../reasoningEngines/${BURGER_ENGINE_ID} auf.
  3. Gateway-Abfangen und SPIFFE-Weitergabe: Ausgehender Traffic wird von agent_gateway_config erfasst und an das Central Agent Gateway in PROJECT_GOVERNANCE weitergeleitet. Dabei wird die kryptografische SPIFFE-Identität des Concierge (principal://...) mitgeführt.
  4. IAP v2-Richtlinienbewertung: Das Central Agent Gateway ruft die IAP-Autorisierungserweiterung (authzExtension) auf. IAP v2 wertet Regel 2 in der IAM Unified Access Policy aus. Da der Aufrufer mit ${CONCIERGE_SPIFFE_PRINCIPAL} und das Ziel mit burger-seller-agent übereinstimmt, gibt IAP ALLOW (granted: true) zurück.
  5. Projektübergreifende Ausführung: Das Agent Gateway leitet die autorisierte Anfrage projektübergreifend an PROJECT_SELLERS weiter, wo die Reasoning Engine des Burgerverkäufers die Bestellung verarbeitet und eine Bestätigung zurückgibt.

Erwartete Antwort:

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

Schritt 3: Agent Gateway- und IAP v2-Audit-Logs prüfen (HTTP 200 / ALLOWED)

Fragen Sie die Anfrageprotokolle des KI-Agenten-Gateways in PROJECT_GOVERNANCE ab:

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

Die Logs sollten ausgehenden Traffic von beiden Spoke-Projekten (PROJECT_CONCIERGE und PROJECT_SELLERS) mit Feldern für ausgehenden Traffic erfassen, z. B. Gemini-Reasoning-Aufrufe (generateContent), Cloud Trace-Telemetrie (/v1/traces) und IAM-Anmeldedatenabfragen, die transparent von Regel 1 (core-gapi-services) abgefangen und autorisiert werden.

Fragen Sie die Cloud-Audit-Datenzugriffslogs von IAP v2 ab, um die Richtlinienversion POLICY_VERSION_V2 zu prüfen:

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

Beispielausgabe:

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

Schritt 4: Pizzabestellung testen (Standardablehnung -> HTTP 403 Forbidden ERZWUNGEN)

Geben Sie im selben Playground-Chatfenster den folgenden Prompt für eine Pizzabestellung ein:

I would like 10 BBQ Chicken Pizzas. Place this order now.

Wenn eine Bestätigung erforderlich ist, senden Sie die folgende Antwort:

Confirmed, please place the order.

Alternativ können Sie den Test programmatisch über Cloud Shell / das Terminal ausführen:

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

Wenn eine Bestätigungsantwort erforderlich ist, verwenden Sie diesen Befehl:

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

Erwartete Antwort:

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.

Was passiert hinter den Kulissen:

  1. Dynamische Erkennung: Der Purchasing Concierge hat den Endpunkt pizza-seller-agent beim Start aus der Central Agent Registry aufgelöst.
  2. Intent-Auflösung und A2A-Aufruf: Gemini im Einkaufs-Concierge versucht, die Anfrage für die Pizzabestellung an den Pizzaverkäufer-Endpunkt in PROJECT_SELLERS zu senden.
  3. Gateway-Abfangen: Der ausgehende RPC wird von agent_gateway_config erfasst und an das Central Agent Gateway weitergeleitet.
  4. IAP v2-Richtlinienbewertung (Standardablehnung): Das Central Agent Gateway ruft IAP v2 auf. Da in der Unified Access Policy keine Regel vorhanden ist, die mit pizza-seller-agent übereinstimmt, gibt IAP DENY (granted: false) zurück.
  5. Strikte Perimeter-Blockierung: Da sich die Autorisierungserweiterung im ERZWINGEN-Modus (failOpen: false) befindet, beendet das zentrale Agent-Gateway die ausgehende Verbindung sofort und gibt HTTP 403 Forbidden zurück. Der Traffic verlässt das Gateway nie und erreicht PROJECT_SELLERS nie.

Schritt 5: Agent Gateway-Protokolle auf blockierte Anfragen (HTTP 403 / DENIED) prüfen

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

Beispiel für die Ausgabe eines Logs mit abgelehnten Anfragen:

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

Fragen Sie die Audit-Logs zum Datenzugriff von IAP v2 nach der Entscheidung „Abgelehnt“ ab:

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

Beispiel für die Ausgabe eines Audit-Logs zu Richtlinienverstößen:

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

Schritt 6: Dem Pizza-Agenten dynamisch Zugriff auf ausgehenden Traffic gewähren

Erstellen Sie eine neue cfg/uap-rules-update-3.json, die Regel 1 (Core APIs), Regel 2 (Burger Seller Agent) und jetzt auch Regel 3 (Pizza Seller Agent) enthält.

# 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

Wenden Sie die Richtlinienaktualisierung live an:

# 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

Schritt 7: Pizza-Agent noch einmal abfragen (sofortige Erfolgsmeldung „200 OK“)

Senden Sie im Chatfenster des Playground den Prompt für die Pizzabestellung noch einmal:

I would like 10 BBQ Chicken Pizzas. Place this order now.

Wenn eine Bestätigung erforderlich ist, senden Sie die folgende Antwort:

Confirmed, please place the order.

Alternativ können Sie den Test programmatisch über Cloud Shell / das Terminal ausführen:

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

Wenn eine Bestätigungsantwort erforderlich ist, verwenden Sie diesen Befehl:

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

Erwartete Antwort:

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**

Was passiert hinter den Kulissen:

  1. Dynamische Richtlinienaktualisierung: Die Aktualisierung der IAM Unified Access Policy wird sofort in der IAP-Bewertungs-Engine wirksam, ohne Ausfallzeiten und ohne dass Container neu bereitgestellt werden müssen.
  2. A2A-Aufruf: Der Concierge leitet die Anfrage über das zentrale Agent Gateway weiter.
  3. IAP v2-Richtlinienbewertung (Genehmigung): IAP v2 entspricht Regel 3, überprüft die Identität des Aufrufers und den Ziel-CEL-Ausdruck und gibt ALLOW (granted: true) zurück.
  4. Projektübergreifende Ausführung: Das Central Agent Gateway leitet den autorisierten Traffic an PROJECT_SELLERS weiter, wo der Pizzaverkäufer die Bestellung verarbeitet.

Schritt 8: Agent-Gateway-Logs auf genehmigte Pizza-Anfragen prüfen

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

Beispiel für die Ausgabe eines Logs mit gewährter Berechtigung:

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

Damit sind die Tests und die Überprüfung abgeschlossen. Als Nächstes folgt der Abschnitt Bereinigen.

11. Bereinigen

Damit Ihrem Google Cloud-Konto die in diesem Codelab verwendeten Ressourcen nicht in Rechnung gestellt werden, führen Sie die Schritte zum Löschen in umgekehrter Reihenfolge aus:

1. Reasoning Engine-Bereitstellungen bereinigen

Führen Sie das enthaltene cleanup_old_deployments.py-Script in beiden Laufzeitprojekten aus, um die Reasoning Engines zu löschen, und warten Sie, bis die Vorgänge mit langer Ausführungszeit abgeschlossen sind:

# 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}

Alternativ können Sie Reasoning Engines inline auflisten und löschen:

uv run --directory ./cross-project-multiagent python -c '
import vertexai
import os
from vertexai.preview import reasoning_engines

region = os.environ.get("REGION", "us-central1")
for proj in [os.environ.get("PROJECT_CONCIERGE"), os.environ.get("PROJECT_SELLERS")]:
    if not proj:
        continue
    print(f"Cleaning reasoning engines in {proj}...")
    vertexai.init(project=proj, location=region)
    for eng in reasoning_engines.ReasoningEngine.list():
        print(f"  Deleting {eng.resource_name} ({eng.display_name})...")
        eng.delete()
'

2. Agent Registry-Dienste löschen

# delete agent registry services in Central Governance Project
for SERVICE in burger-seller-agent pizza-seller-agent purchasing-concierge-adk core-gapi-services; do
  gcloud agent-registry services delete ${SERVICE} \
    --project=${PROJECT_GOVERNANCE} \
    --location=${REGION} \
    --quiet || true
done

3. IAM Unified Access Policy-Bindung und Zugriffsrichtlinie löschen

# 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. Agent-Gateway und Sicherheitsrichtlinien löschen

# 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. Projektübergreifende IAM-Bindungen und benutzerdefinierte Rolle entfernen

# 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

Wenn Sie während der Einrichtungsphase roles/iam.accessPolicyAdmin und roles/resourcemanager.projectIamAdmin zugewiesen haben, entfernen Sie sie aus Ihrem aktiven Nutzerkonto, um das Prinzip der geringsten Berechtigung wiederherzustellen:

# 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. Audit-Daten-Logging und Einschränkungen für Organisationsrichtlinien zurücksetzen

# 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. Einschränkungen für Organisationsrichtlinien zurücksetzen

# 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. Freigegebenen GCS-Staging-Bucket und lokale Artefakte löschen

# 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

Damit ist der Bereinigungsteil abgeschlossen. Als Nächstes folgt das Fazit.

12. Fazit

Glückwunsch! Sie haben eine projektübergreifende KI-Agent-to-KI-Agent-Architektur (A2A) in Google Cloud mit Vertex AI Agent Runtime, Central Agent Gateway, Agent Registry und IAM Unified Access Policies (UAP) bereitgestellt und verwaltet.

Zusammenfassung der wichtigsten Konzepte

  • Zentraler Perimeter für ausgehenden Traffic: Weitergeleitete Spoke-Laufzeitcontainer (PROJECT_CONCIERGE, PROJECT_SELLERS) über ein zentrales Agent Gateway in PROJECT_GOVERNANCE mit agentGatewayConfig.
  • Deklarative Governance (UAP): Fragmentierte Bindungen pro Ressource wurden durch eine einzige, prüfbare IAM-Zugriffsrichtlinie ersetzt, die am Gateway von IAP v2 ausgewertet wird.
  • Kryptografische Identität: Erzwingung des Prinzips der geringsten Berechtigung für ausgehenden Traffic mithilfe von SPIFFE-Identitäten (principal://...) anstelle von langlebigen Schlüsseln.
  • Dynamische Service Discovery: Peer-Agent-Endpunkte werden zur Laufzeit über die Central Agent Registry aufgelöst, sodass keine hartcodierten URLs und Projekt-IDs mehr erforderlich sind.
  • Agilität der Laufzeitrichtlinie: pizza-seller-agent wurde in Echtzeit über ein Richtlinienupdate von „Standardmäßig ablehnen“ (403 Forbidden) auf „Zulassen“ (200 OK) umgestellt, ohne dass Container neu gestartet werden mussten.

cosmopup

Cosmopup sagt: „KI-Agenten sind großartig – sie erledigen die gesamte projektübergreifende Arbeit, während ich mich auf mein Hauptziel konzentriere: ein Nickerchen!“

Nächste Schritte und Dokumentation