Scentralizowane zarządzanie bramą agentów z Agent Registry w wielu projektach na potrzeby Agent Runtime

1. Wprowadzenie

Wraz z wdrażaniem generatywnej AI w organizacjach architektonicznych systemy szybko ewoluują od samodzielnych, monolitycznych czatbotów do rozproszonych systemów wieloagentowych (A2A). W tych nowoczesnych topologiach agenty orkiestrujące wysokiego poziomu koordynują złożone przepływy pracy, delegując zadania do wyspecjalizowanych agentów roboczych, serwerów narzędzi MCP (Model Context Protocol) i baz danych backendu w niezależnych projektach Google Cloud.

Jednak korzystanie z systemów z wieloma agentami na dużą skalę wiąże się z poważnymi wyzwaniami w zakresie bezpieczeństwa, zarządzania i operacji:

  • Shadow Agent i rozrastanie się narzędzi: gdy zespoły deweloperskie wdrażają agentów w izolowanych projektach bez centralnego katalogu, organizacje tracą wgląd w to, jakie narzędzia i podagenty istnieją.
  • Niemonitorowany ruch wychodzący między projektami: zezwolenie agentom na bezpośrednie, niesprawdzone trasy sieciowe stwarza ryzyko wydobycia danych i pomija zabezpieczenia.
  • Niestabilne integracje zakodowane na stałe: zakodowanie na stałe adresów URL agentów podrzędnych i identyfikatorów silnika wnioskowania tworzy niestabilne zależności, które ulegają przerwaniu podczas uaktualniania lub ponownego wdrażania.
  • Brak tożsamości o najmniejszych uprawnieniach: współdzielone konta usługi nie zapewniają kryptograficznego zaprzeczenia na poziomie poszczególnych instancji agenta.

Aby rozwiązać te problemy, Gemini Enterprise Agent Platform udostępnia ujednoliconą platformę sterującą zarządzaniem i łącznością, która składa się z 4 głównych filarów:

  1. Brama agenta (networkservices.googleapis.com): zarządzany regionalny serwer proxy sieci i egzekwowania zasad. Działa w AGENT_TO_ANYWHEREtrybie ruchu wychodzącego, przechwytuje ruch wychodzący agenta, przekazuje ocenę autoryzacji do rozszerzeń zabezpieczeń i kieruje żądania przez granice projektu.
  2. Agent Registry (agentregistry.googleapis.com): pojedynczy katalog usług dla przedsiębiorstw. Zapewnia scentralizowany, sprawdzony katalog wszystkich dostępnych narzędzi, serwerów MCP i agentów równorzędnych w organizacji, umożliwiając dynamiczne automatyczne wykrywanie w czasie działania bez zakodowanych na stałe punktów końcowych.
  3. Agent Identity & IAP v2 Governance (iap.googleapis.com & iam.googleapis.com): kryptograficzne ramy tożsamości i dostępu. Agenci wykonawczy otrzymują unikalne, poświadczone identyfikatory URN maszyny SPIFFE (principal://...). Ruch wychodzący jest oceniany na podstawie scentralizowanych zasad dostępu ujednoliconego IAM (UAP / IAP v2), które weryfikują uniwersalne uprawnienie iap.googleapis.com/resources.egressViaIAP za pomocą rozbudowanych warunków katalogu w języku Common Expression Language (CEL) (destination.agent_registry.*).
  4. Agent Runtime (silniki rozumowania): w pełni zarządzana, bezserwerowa platforma wykonawcza dla aplikacji agentowych opartych na języku Python, która zawiera natywne powiązania konfiguracji (agent_gateway_config) z centralnymi bramami.

Scenariusz biznesowy w ramach laboratorium kodu: zakup żywności i napojów w wielu projektach

W tym ćwiczeniu utworzysz i będziesz zarządzać rzeczywistym ekosystemem zakupów obejmującym wiele projektów, który będzie się składać z 3 różnych projektów Google Cloud:

  • Projekt centralnego zarządzania (PROJECT_GOVERNANCE): należy do centralnego działu IT i zespołu ds. bezpieczeństwa. Zawiera centralną bramę agentów, centralny rejestr agentów i ujednolicone zasady dostępu IAM.
  • Projekt koordynatora konsumentów (PROJECT_CONCIERGE): należy do zespołu ds. zamówień i zawiera agenta obsługi zakupów, który dynamicznie wykrywa dostawców i kieruje zamówienia klientów.
  • Projekt dostawcy domeny (PROJECT_SELLERS): należy do zewnętrznych dostawców lub dostawców z poszczególnych działów. Zawiera agenta sprzedawcy burgerówagenta sprzedawcy pizzy.

figure1

Rys. 1. Architektura scentralizowanego zarządzania wieloma projektami

Dlaczego warto stosować scentralizowane zarządzanie w wielu projektach?

W dużych organizacjach zespoły ds. usług i grupy zajmujące się nauką o danych tworzą agenty AI w dziesiątkach niezależnych projektów Google Cloud. Przyznanie każdemu zespołowi bezpośredniej kontroli nad rejestracją narzędzi, trasami sieci wychodzącej i zabezpieczeniami powoduje niekontrolowane rozrastanie się narzędzi, niespójne zasady DLP, niemonitorowany ruch wychodzący z VPC i rozproszone dzienniki kontrolne.

Centralne zarządzanie w wielu projektach oddziela tworzenie zasad od wykonywania działań przez agenta:

  • Centralne zespoły IT i SecOps tworzą zasady zabezpieczeń, sprawdzają narzędzia i monitorują ruch wychodzący w ramach jednego scentralizowanego projektu zarządzania.
  • Zespoły ds. produktów i aplikacji skupiają się wyłącznie na logice biznesowej w niezależnych Agent Runtime Projects, które są bezpośrednio powiązane z centralną bramą bez obciążenia operacyjnego związanego z zarządzaniem lokalnymi sieciami VPC, połączeniami wzajemnymi czy rozproszonymi silnikami zasad.

figure2

Rys. 2. Trzypoziomowa architektura zarządzania projektami i jej granice

Dwupoziomowy model określania zakresu tożsamości w ujednoliconych zasadach dostępu

Gdy agenci komunikują się za pomocą centralnej bramy agentów, Identity-Aware Proxy (IAP w wersji 2) ocenia dostęp na podstawie tożsamości agenta wywołującego – kryptograficznie potwierdzonej tożsamości opartej na SPIFFE, wydawanej automatycznie do kontenera środowiska wykonawczego – w porównaniu z globalnymi zasadami dostępu IAM:

  • Poziom 1. Podstawowe interfejsy Cloud APIs Google Cloud (o dużej szczegółowości za pomocą principalSet:// w regule 1): autoryzacja ruchu wychodzącego w całym projekcie, która umożliwia wszystkim środowiskom wykonawczym Agent Runtime w projektach typu hub and spoke dostęp do standardowych interfejsów API Google (aiplatform, iamcredentials, telemetry, agentregistry) na potrzeby wykrywania, generowania tokenów i wnioskowania.
  • Poziom 2. Narzędzia biznesowe i usługi A2A (precyzyjne za pomocą principal:// w regułach 2 i 3): ścisły dostęp o najmniejszych uprawnieniach powiązany z poszczególnymi instancjami Reasoning Engine, egzekwowany za pomocą warunków języka CEL (Common Expression Language) kierowanych na konkretne zarejestrowane usługi Agent Registry (destination.agent_registry.agent.name).

Co utworzysz

  • Centralna brama agentów (centralized-agw) w PROJECT_GOVERNANCE
  • Rozszerzenie usługi autoryzacji IAP w wersji 2 i zasady autoryzacji w trybie ścisłego WYMAGANIA (failOpen: false)
  • Ujednolicone zasady dostępu dotyczące podstawowych uprawnień (uap-rules.json) i powiązanie zasad projektu
  • Uprawnienia konta usługi w wielu projektach (ar_agw_cross_project_sa)
  • Wspólny centralny zasobnik przejściowy Google Cloud Storage (GCS)
  • Agenci sprzedający burgery i pizzę w PROJECT_SELLERS
  • Agent obsługi zakupów z dynamicznym automatycznym wykrywaniem interfejsu REST w PROJECT_CONCIERGE
  • Rejestracje usług w centralnym rejestrze agentów z adresami URL mTLS obejmującymi wiele projektów
  • Dynamiczne aktualizacje zasad ruchu wychodzącego IAP w wersji 2 z weryfikacją na żywo i audytami Cloud Logging

figure3

Ilustracja 3. Sekwencja implementacji krok po kroku

Czego się dowiesz

  • Konfigurowanie uprawnień agenta usługi w wielu projektach na potrzeby scentralizowanych bram
  • Jak kierować ruch wychodzący Agent Runtime przez centralną Bramę agentów w środowiskach obejmujących wiele projektów
  • Delegowanie autoryzacji bramy agentów do Identity-Aware Proxy (IAP w wersji 2) za pomocą Service Extensions (iapPolicyVersion: "V2")
  • Tworzenie i powiązywanie zasad ujednoliconego dostępu IAM (UAP) z regułami języka CEL (Common Expression Language) regulującymi zarejestrowane miejsca docelowe Agent Registry (destination.agent_registry.*)
  • Jak wyeliminować zakodowane na stałe identyfikatory agentów i adresy URL za pomocą automatycznego wykrywania w czasie działania w Agent Registry
  • Jak testować blokowanie w ramach prawdziwego modelu zabezpieczeń typu zero-trust (HTTP 403 Forbidden) i weryfikować aktualizacje zasad na żywo w Cloud Logging

Wymagania

  • 3 projekty Google Cloud z włączonymi rozliczeniami:
    • PROJECT_GOVERNANCE: centralne zasady zarządzania, bramy, rejestru i dostępu IAM
    • PROJECT_CONCIERGE: agent aranżujący usługę konsjerża zakupowego
    • PROJECT_SELLERS: agenci sprzedaży specjalizujący się w burgerach i pizzy
  • Użytkownik uprawnień lub konto usługi z uprawnieniami roles/owner lub administracyjnymi we wszystkich 3 projektach.
  • Organizacja Google Cloud (w przypadku mapowania domeny zaufania SPIFFE)
  • Google Cloud Shell lub komputer lokalny z zainstalowanym interfejsem gcloud CLI, python (3.11+) i uv

To koniec wprowadzenia. Przejdźmy teraz do sekcji Konfiguracja i środowisko.

2. Konfiguracja

Chociaż ta architektura obejmuje 3 różne projekty Google Cloud, możesz wykonać 100% poleceń wdrażania w terminalu, pobierania repozytorium i operacji przygotowania z pojedynczego terminala Cloud Shell ustawionego na PROJECT_GOVERNANCE. Każdy skrypt wdrażania i każde polecenie gcloud jest kierowane na odpowiedni projekt docelowy za pomocą flag interfejsu CLI (--project).

Zacznij od uzyskania dostępu do wiersza poleceń projektu w chmurze Google Cloud:

Określanie kontekstu projektu

# 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

Ustawianie zmiennych środowiskowych powłoki

Wpisz identyfikatory projektu.

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

Te zmienne powłoki zostaną wygenerowane automatycznie.

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

Tworzenie lokalnego katalogu plików konfiguracyjnych

# create config folder
mkdir -p cfg

Przypisywanie roli administratora zasad dostępu do ujednoliconych zasad dostępu

# 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

Włączanie logów kontrolnych dostępu do danych Cloud w przypadku IAP w wersji 2

Domyślnie Google Cloud wyłącza logi kontrolne dostępu do danych, aby zapobiec nieoczekiwanym kosztom przechowywania. IAP w wersji 2 emituje decyzje dotyczące autoryzacji (granted=true i granted=false) jako logi kontrolne dostępu do danych, więc włącz logowanie ADMIN_READ, DATA_READ i DATA_WRITE w przypadku iap.googleapis.com w 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)"

Włączanie wymaganych interfejsów Google Cloud API

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

Sprawdzanie włączenia interfejsu API we wszystkich projektach

Upewnij się, że we wszystkich 3 projektach (PROJECT_GOVERNANCE, PROJECT_CONCIERGEPROJECT_SELLERS) są włączone dokładnie te same interfejsy API. Zapewni to spójność działania i zapobiegnie błędom generowania tokenów w czasie działania, błędom katalogowania schematów lub utracie danych telemetrycznych.

Aby sprawdzić, czy interfejsy API są identyczne we wszystkich 3 projektach, uruchom w Cloud Shell ten skrypt weryfikacyjny:

# 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

Przykładowe dane wyjściowe weryfikacji:

Wszystkie interfejsy API powinny być włączone.

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

Konfigurowanie zasad organizacji

Domyślne zasady organizacji Google Cloud wymuszają ograniczenia, które ograniczają powiązania zasad dostępu IAM w wersji 3 z zasobami (constraints/iam.managed.disableAccessPolicyBinding).

Zastąp odziedziczone ograniczenia zasad organizacji na poziomie projektu, ustawiając wyraźnie wartość enforce: false, aby zezwolić na dostęp.

# 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

To już koniec konfiguracji. Przejdź do sekcji Rejestrowanie podstawowych interfejsów API Google.

3. Agent Registry

Rejestrowanie usługi punktu końcowego podstawowych interfejsów API Google

Brama agentów wymaga zarejestrowania adresów URL interfejsu API Google w Central Agent Registry, aby agenty skonfigurowane za pomocą agent_gateway_config mogły bezpiecznie kierować ruch wychodzący do podstawowych usług backendu Google Cloud (takich jak aiplatform, IAM Credentials i Telemetry).

Tworzenie core-gapi-services w rejestrze agentów

# 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

Przechwytywanie identyfikatora zasobu punktu końcowego interfejsów API podstawowych funkcji

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

Różnice między principalSetprincipal w tożsamości agenta

W usłudze Google Cloud IAM i na platformie agentów Gemini Enterprise tożsamości maszyn wydane dla kontenerów agentów wykonujących zadania używają kryptograficznie potwierdzonych identyfikatorów URN SPIFFE, które są oceniane przez Identity-Aware Proxy (IAP w wersji 2). Podczas konfigurowania ujednoliconych zasad dostępu IAM możesz kierować je na konkretny pojedynczy principal lub na principalSet oparty na atrybutach:

Wymiar

principal:// (Pojedyncza tożsamość maszyny)

principalSet:// (grupa oparta na atrybutach)

Składnia uprawnień

principal://...

principalSet://...

Szczegółowość

Szczegółowy (na poziomie instancji): identyfikuje pojedynczą, konkretną instancję kontenera Reasoning Engine.

Ogólne (na poziomie projektu): identyfikuje wszystkie silniki rozumowania, które mają wspólny atrybut projektu.

Wzorzec URN

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}

Przypadek użycia w Agent Platform

Poziom 2 (narzędzia biznesowe i A2A): autoryzowanie konkretnych agentów orkiestracji do wywoływania narzędzi domeny docelowej (np. agent obsługi zakupów → sprzedawca burgerów).

Poziom 1 (infrastruktura podstawowa): przyznanie wszystkim agentom w projekcie dostępu wychodzącego do interfejsów API Google Cloud (core-gapi-services).

Wpływ na cykl życia

Jeśli agent zostanie usunięty i utworzony ponownie, jego nowy identyfikator wyszukiwarki wymaga zaktualizowanego powiązania zasad uprawnień.

Automatycznie stosowane do nowo wdrażanych agentów w tym projekcie bez dodatkowych aktualizacji IAM.

Deklaratywne zarządzanie za pomocą ujednoliconych zasad dostępu (UAP / IAP v2)

W starszej wersji IAP v1 zasady ruchu wychodzącego były dołączane bezpośrednio do poszczególnych zasobów Agent Registry za pomocą gcloud beta iap web add-iam-policy-binding. W sekcji IAP w wersji 2 i Ujednolicone zasady dostępu (UAP) powiązania z poszczególnymi zasobami są eliminowane na rzecz jednej, scentralizowanej zasady dostępu IAM (cfg/uap-rules.json).

Podstawowa autoryzacja ruchu wychodzącego dla core-gapi-services zostanie skonfigurowana jako Reguła 1 w Ujednoliconych zasadach dostępu w sekcji 5, co zapewni, że wszystkie kontenery agentów będą miały podstawowe trasy ruchu wychodzącego przed wdrożeniem.

Szczegółowe informacje techniczne o identyfikatorach podmiotów zabezpieczeń i mechanizmach tożsamości zadań znajdziesz w tych artykułach:

Na tym kończy się rejestracja punktu końcowego podstawowych interfejsów API. Przejdź do sekcji Wdrażanie scentralizowanej bramy agenta.

4. Brama agentów

Wdrażanie scentralizowanej bramy agentów

Wdróż scentralizowaną bramę agentów (centralized-agw) w trybie ruchu wychodzącego AGENT_TO_ANYWHERE w projekcie $PROJECT_GOVERNANCE.

Definiowanie manifestu konfiguracji bramy

Utwórz cfg/${AGW_NAME}.yaml do zarządzania ruchem wychodzącym:

# 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

Importowanie konfiguracji bramy agenta

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

Weryfikowanie szczegółów bramy agentów

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

Przykładowe dane wyjściowe:

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'

Wdrożenie bramy zostało zakończone. Przejdź do sekcji Konfigurowanie autoryzacji.

5. Autoryzacja

Konfigurowanie autoryzacji bramy agentów i podstawowego UAP

Brama agentów zabezpiecza i kontroluje ruch wychodzący narzędzi i agentów za pomocą zasad autoryzacji (networksecurity.authzPolicies) zintegrowanych z ujednoliconymi zasadami dostępu (UAP) Identity-Aware Proxy (IAP w wersji 2).

Omówienie architektury autoryzacji

figure4

Rys. 4. Omówienie architektury autoryzacji

Architektura autoryzacji składa się z 3 połączonych warstw:

  1. Rozszerzenie usługi IAP (authzExtension): zasób regionalny skonfigurowany z wartościami service: iap.googleapis.com, metadata: iapPolicyVersion: "V2"failOpen: false na potrzeby ścisłego egzekwowania zasady zero trust w ramach perymetru.
  2. Zasady autoryzacji bramy (authzPolicy): zasób regionalny kierowany na bramę agenta z policyProfile: REQUEST_AUTHZaction: CUSTOM, który przekazuje sprawdzanie autoryzacji do rozszerzenia autoryzacji IAP.
  3. Ujednolicona polityka dostępu i powiązanie IAM (accessPolicypolicyBinding): zasób globalny IAM w wersji 3 oceniany przez IAP. Weryfikuje uniwersalne uprawnienie iap.googleapis.com/resources.egressViaIAP na podstawie tożsamości SPIFFE wywołującego i warunków katalogu CEL.

Krok 1. Utwórz i zaimportuj rozszerzenie autoryzacji IAP w wersji 2

Utwórz plik manifestu rozszerzenia usługi z parametrami iapPolicyVersion: "V2"failOpen: false w trybie ścisłego egzekwowania ENFORCE:

# 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

Zaimportuj rozszerzenie autoryzacji:

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

Sprawdź, czy rozszerzenie Authz jest aktywne:

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

Przykładowe dane wyjściowe:

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

Krok 2. Utwórz i zaimportuj zasady autoryzacji bramy

Utwórz konfigurację zasady autoryzacji, która jest dołączona do bramy agenta i przekazuje weryfikację żądań do rozszerzenia autoryzacji IAP:

# create authz policy manifest
cat > cfg/${AGW_NAME}-authz-policy-profile-iap.yaml << EOF
name: ${AGW_NAME}-authz-policy-profile-iap
target:
  resources:
    - "projects/${PROJECT_GOVERNANCE}/locations/${REGION}/agentGateways/${AGW_NAME}"
policyProfile: REQUEST_AUTHZ
action: CUSTOM
customProvider:
  authzExtension:
    resources:
      - "projects/${PROJECT_GOVERNANCE}/locations/${REGION}/authzExtensions/${AGW_NAME}-svc-ext-authz-iap"
EOF

Zaimportuj zasadę autoryzacji:

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

Sprawdź aktywną zasadę autoryzacji:

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

Krok 3. Utwórz początkową ujednoliconą zasadę dostępu (reguła 1: podstawowe interfejsy API Google)

Utwórz cfg/uap-rules.json z regułą 1, która zezwala 3 projektom principalSet na dostęp do 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

Krok 4. Utwórz i powiąż zasadę dostępu uprawnień

Utwórz globalną zasadę dostępu uprawnień:

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

Powiąż zasadę dostępu z 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

Sprawdź, czy powiązanie zasad jest aktywne:

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

Przykładowe dane wyjściowe:

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}

Wychodzący ruch z podstawowych interfejsów Google Cloud API jest teraz bezpiecznie autoryzowany we wszystkich 3 projektach w trybie ścisłymENFORCE.

Na tym kończy się konfiguracja autoryzacji bramy. Przejdź do sekcji Konfigurowanie uprawnień obejmujących wiele projektów.

6. Uprawnienia obejmujące wiele projektów

Konfigurowanie uprawnień w różnych projektach

W tej topologii obejmującej wiele projektów środowiska wykonawcze agentów znajdują się w projektach typu spoke (PROJECT_CONCIERGEPROJECT_SELLERS), a centralna Brama agentów i Agent Registry znajdują się w projekcie PROJECT_GOVERNANCE.

Projekty Google Cloud są odizolowanymi obszarami zabezpieczeń, dlatego dostęp między projektami musi być wyraźnie przyznany w 2 warstwach operacyjnych:

  1. Płaszczyzna sterowania (czas wdrażania): podczas wdrażania kontenera agenta skonfigurowanego za pomocą --agent-gateway-config agent usługi Agent Runtime Service Agent (service-@gcp-sa-aiplatform.iam.gserviceaccount.com) projektu sieci lokalnej musi dołączyć kontener do centralnej bramy. Tworzymy minimalną rolę niestandardową (ar_agw_cross_project_sa), która przyznaje uprawnienia networkservices.agentGateways.use, get i operations.get w PROJECT_GOVERNANCE.
  2. Płaszczyzna danych (wykonywanie w czasie działania):
    • Odkrywanie katalogu: tożsamości węzłów muszą mieć roles/agentregistry.viewerPROJECT_GOVERNANCE, aby dynamicznie rozwiązywać punkty końcowe agenta docelowego.
    • Wywoływanie celu: agent Concierge potrzebuje roles/aiplatform.userPROJECT_SELLERS, aby wykonywać zapytania w silnikach rozumowania sprzedawcy.

Tworzenie niestandardowej roli uprawnień w 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"

Przypisywanie roli niestandardowej do agentów usługi 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

To kończy konfigurację uprawnień obejmujących wiele projektów. Przejdź do sekcji Wdrażanie agentów sprzedaży i obsługi.

7. Agent Runtime

Wdrażanie agentów sprzedaży i usług concierge

Kod aplikacji z wieloma agentami i skrypty wdrażania użyte w tym ćwiczeniu są przechowywane w zdalnym repozytorium Google Cloud na GitHubie. Poniższe kroki spowodują sklonowanie repozytorium lokalnie, skopiowanie niezbędnych plików do bieżącej struktury katalogów roboczych, usunięcie plików tymczasowych i zainstalowanie zależności za pomocą polecenia uv.

Pobieranie artefaktów zdalnych

# 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

Tworzenie udostępnionego centralnego zasobnika tymczasowego

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

Jak działa powiązanie bramy agenta z wieloma projektami

W tym kroku wdrożysz agenty sprzedawcy w projekcie typu spoke (PROJECT_SELLERS) i skonfigurujesz je tak, aby kierowały ruch wychodzący przez centralną bramę agentów w projekcie 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)

Ponieważ reguła 1 została ustanowiona wcześniej w naszych ujednoliconych zasadach dostępu, żądania inicjowania kontenera do interfejsów API Google Cloud są dozwolone przez bramę bez przerw.

Wdrażanie agentów sprzedających burgery i pizzę w 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}

Weryfikacja routingu w Seller Gateway

# retrieve deployed seller reasoning engine IDs
export BURGER_ENGINE_ID=$(grep BURGER_SELLER_AGENT_ID cross-project-multiagent/burger_agent.env | awk -F'/' '{print $NF}')
export PIZZA_ENGINE_ID=$(grep PIZZA_SELLER_AGENT_ID cross-project-multiagent/pizza_agent.env | awk -F'/' '{print $NF}')

echo "Burger Engine ID: ${BURGER_ENGINE_ID}"
echo "Pizza Engine ID:  ${PIZZA_ENGINE_ID}"
# inspect runtime configuration for both Seller Agents
for ENGINE_ID in ${BURGER_ENGINE_ID} ${PIZZA_ENGINE_ID}; do
  curl -s -X GET "https://${REGION}-aiplatform.googleapis.com/v1beta1/projects/${PROJECT_SELLERS}/locations/${REGION}/reasoningEngines/${ENGINE_ID}" \
    -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
    -H "Content-Type: application/json" \
    | jq '{displayName: .displayName, identityType: .spec.identityType, effectiveIdentity: .spec.effectiveIdentity, agentGatewayConfig: .spec.deploymentSpec.agentGatewayConfig}'
done

Wdróż agenta Purchasing Concierge w 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}

Weryfikowanie routingu bramy płatności

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

Dane wyjściowe powinny zawierać tożsamość środowiska wykonawczego agenta Concierge i projekt oraz powiązanie z bramą agentów projektu Governance.

{
  "displayName": "purchasing-concierge-adk",
  "identityType": "AGENT_IDENTITY",
  "effectiveIdentity": "agents.global.org-${ORG_ID}.system.id.goog/resources/aiplatform/projects/${PROJECT_CONCIERGE}/locations/us-central1/reasoningEngines/${CONCIERGE_ENGINE_ID}",
  "agentGatewayConfig": {
    "agentToAnywhereConfig": {
      "agentGateway": "projects/${PROJECT_GOVERNANCE}/locations/us-central1/agentGateways/centralized-agw"
    }
  }
}

To wszystko, jeśli chodzi o wdrażanie agentów. Przejdźmy teraz do sekcji Rejestrowanie agentów w centralnym rejestrze agentów.

8. Rejestr obejmujący wiele projektów

Rejestrowanie agentów w centralnym rejestrze agentów

Zarejestruj wszystkich 3 agentów w centralnym rejestrze agentów w PROJECT_GOVERNANCE za pomocą regionalnych punktów końcowych mTLS w różnych projektach i numerycznych numerów projektów.

Rejestrowanie usług jako agentów innych niż A2A w 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

Przechwytywanie identyfikatorów rejestru agentów

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

Na tym kończy się konfiguracja rejestru. Przejdź do sekcji Konfigurowanie zasad ruchu wychodzącego A2A.

9. Zasady UAP

Konfigurowanie zasad ruchu wychodzącego A2A w ujednoliconej zasadzie dostępu

W architekturze domyślnego odrzucania bramy agenta w trybie ścisłym WYMAGAJ:

  1. Reguła 1 (podstawowe interfejsy Google Cloud API): umożliwia kontenerom agentów we wszystkich 3 projektach dostęp do core-gapi-services.
  2. Reguła 2 (Agent sprzedawcy burgerów: ZEZWALAJ): zezwala instancji agenta obsługi zakupów na wywoływanie agenta sprzedawcy burgerów.
  3. Agent sprzedawcy pizzy (DOMYŚLNIE ODRZUCONY): celowo pominięty w regułach zasad. W trybie ENFORCE (failOpen: false) każda próba wywołania sprzedawcy pizzy przez Concierge zostanie natychmiast przerwana na obrzeżach bramy z kodem HTTP 403 Forbidden.

Formułowanie tożsamości agenta usługi 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}"

Aktualizacja pliku manifestu za pomocą reguł 1 i 2

Utwórz nowy cfg/uap-rules-update-2.json, aby uwzględnić Regułę 1 (interfejsy Core API) i teraz Regułę 2 (agent sprzedawcy burgerów):

# 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

Zastosuj zaktualizowane zasady dostępu

# 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

Sprawdzanie szczegółów zasady dostępu uprawnień

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

Przykładowe dane wyjściowe:

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

To kończy konfigurację zasad. Przejdź do sekcji Testowanie i weryfikowanie zasad zarządzania.

10. Sprawdzanie zasad

Testowanie i weryfikowanie zasad zarządzania za pomocą Cloud Logging

W tej sekcji przetestujesz interakcje między agentami w różnych projektach (A2A) w Agent Runtime AI Playground, zaobserwujesz HTTP 403 Forbidden blokowanie w czasie rzeczywistym w ścisłym trybie ENFORCE, zmodyfikujesz na żywo ujednolicone zasady dostępu i sprawdzisz natychmiastowe zatwierdzanie zamówień.

Krok 1. Otwórz Agent Runtime AI Playground w PROJECT_CONCIERGE

  1. Otwórz konsolę Google Cloud.
  2. Na pasku selektora projektów u góry przełącz na PROJECT_CONCIERGE.
  3. W menu nawigacyjnym kliknij Agent Platform > Agenci > Wdrożenia.
  4. Kliknij purchasing-concierge-adk.
  5. Kliknij Laboratorium, aby otworzyć interaktywny interfejs czatu po prawej stronie ekranu.

Krok 2. Przetestuj zamówienie burgera (dopasowanie do reguły 2 –> 200 OK)

W oknie czatu Playground prześlij ten prompt zamówienia:

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

Jeśli wymagana jest odpowiedź z potwierdzeniem, prześlij tę odpowiedź:

Confirmed, please place the order.

Możesz też przetestować programowo w Cloud Shell lub terminalu:

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

Jeśli potrzebujesz odpowiedzi z potwierdzeniem, użyj tego polecenia:

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

Co się dzieje za kulisami:

  1. Dynamiczne wykrywanie: podczas uruchamiania sesji usługa Purchasing Concierge wysłała zapytanie do Centralnego rejestru agentów w PROJECT_GOVERNANCE (za pomocą core-gapi-services przez Bramę agentów autoryzowaną przez regułę 1), aby wykryć regionalny punkt końcowy mTLS dla burger-seller-agent.
  2. Rozpoznawanie intencji i wywoływanie A2A: Gemini w ramach agenta obsługi zakupów analizuje intencję zamówienia jedzenia i wywołuje agenta sprzedawcy burgerów za pomocą wychodzącego wywołania RPC do https://${REGION}-aiplatform.mtls.googleapis.com/.../reasoningEngines/${BURGER_ENGINE_ID}.
  3. Przechwytywanie bramy i propagacja SPIFFE: ruch wychodzący jest przechwytywany przez agent_gateway_config i kierowany do centralnej bramy agenta w PROJECT_GOVERNANCE, przenosząc kryptograficzną tożsamość SPIFFE usługi Concierge (principal://...).
  4. Ocena zasad IAP w wersji 2: centralna brama agenta wywołuje rozszerzenie autoryzacji IAP (authzExtension). IAP w wersji 2 ocenia regułę 2 w ujednoliconych zasadach dostępu IAM. Ponieważ wywołujący pasuje do ${CONCIERGE_SPIFFE_PRINCIPAL}, a element docelowy pasuje do burger-seller-agent, interfejs IAP zwraca wartość ALLOW (granted: true).
  5. Wykonywanie w różnych projektach: brama agenta przekazuje autoryzowane żądanie do PROJECT_SELLERS w innym projekcie, gdzie silnik wnioskowania sprzedawcy burgerów przetwarza zamówienie i zwraca potwierdzenie.

Oczekiwana odpowiedź:

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

Krok 3. Sprawdź dzienniki kontrolne bramy agenta i IAP w wersji 2 (HTTP 200 / ALLOWED)

Wykonaj zapytanie o logi żądań bramy agenta w 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
  )"

Logi powinny rejestrować ruch wychodzący pochodzący z obu projektów sieci (PROJECT_CONCIERGEPROJECT_SELLERS) z polami wyjścia dla wywołań rozumowania Gemini (generateContent), telemetrii Cloud Trace (/v1/traces) i wyszukiwania danych logowania IAM, które są w sposób przejrzysty przechwytywane i autoryzowane przez regułę 1 (core-gapi-services).

Aby sprawdzić wersję zasady, wyślij zapytanie do logów kontrolnych Cloud dotyczących dostępu do danych IAP w wersji 2: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
  )"

Przykładowe dane wyjściowe:

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

Krok 4. Testowanie zamówienia pizzy (domyślne odrzucanie –> HTTP 403 Zabroniony WYMAGANE)

W tym samym oknie czatu Playground prześlij prompta z zamówieniem pizzy:

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

Jeśli wymagana jest odpowiedź z potwierdzeniem, prześlij tę odpowiedź:

Confirmed, please place the order.

Możesz też przetestować programowo w Cloud Shell lub terminalu:

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

Jeśli potrzebujesz odpowiedzi z potwierdzeniem, użyj tego polecenia:

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

Oczekiwana odpowiedź:

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.

Co się dzieje za kulisami:

  1. Dynamiczne wykrywanie: agent obsługi zakupów rozwiązał problem z punktem końcowym pizza-seller-agent z centralnego rejestru agentów podczas uruchamiania.
  2. Rozpoznawanie intencji i wywoływanie A2A: Gemini w ramach usługi Purchasing Concierge próbuje wysłać żądanie zamówienia pizzy do punktu końcowego sprzedawcy pizzy w PROJECT_SELLERS.
  3. Przechwytywanie bramy: wychodzące wywołanie RPC jest przechwytywane przez agent_gateway_config i kierowane do centralnej bramy agenta.
  4. Ocena zasad IAP w wersji 2 (domyślne odrzucanie): centralna brama agenta wywołuje IAP w wersji 2. Ponieważ w zasadach ujednoliconego dostępu nie ma żadnej reguły pasującej do pizza-seller-agent, IAP zwraca DENY (granted: false).
  5. Ścisła blokada perymetryczna: ponieważ rozszerzenie autoryzacji jest w trybie WYMUSZANIA (failOpen: false), centralna brama agenta natychmiast zamyka połączenie wychodzące i zwraca kod HTTP 403 Forbidden. Ruch nigdy nie opuszcza bramy i nie dociera do PROJECT_SELLERS.

Krok 5. Sprawdź dzienniki bramy agenta pod kątem zablokowanych żądań (HTTP 403 / DENIED)

# query Agent Gateway logs for blocked 403 requests
gcloud logging read "
  logName=\"projects/${PROJECT_GOVERNANCE}/logs/networkservices.googleapis.com%2Fgateway_requests\"
  AND httpRequest.status=403
" \
  --project="${PROJECT_GOVERNANCE}" \
  --limit=5 \
  --format="table(
    timestamp.date('%H:%M:%S'):label=TIME,
    httpRequest.requestMethod:label=METHOD,
    httpRequest.status:label=STATUS,
    jsonPayload.authzPolicyInfo.result:label=AUTHZ,
    httpRequest.requestUrl:label=URL
  )"

Przykładowe dane wyjściowe logu odrzucenia:

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

Wyślij zapytanie do logów kontrolnych dostępu do danych IAP w wersji 2 o decyzję o odmowie:

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

Przykładowe dane wyjściowe odrzuconego logu kontrolnego:

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

Krok 6. Dynamiczne przyznawanie dostępu wychodzącego agentowi Pizza Agent

Utwórz nowy cfg/uap-rules-update-3.json, aby uwzględnić regułę 1 (podstawowe interfejsy API), regułę 2 (agent sprzedający burgery) i teraz regułę 3 (agent sprzedający pizzę).

# 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

Zastosuj aktualizację zasad na żywo:

# 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

Krok 7. Ponowne zapytanie do agenta Pizza (natychmiastowa odpowiedź 200 OK)

W oknie czatu Playground ponownie prześlij prompta dotyczącego zamówienia pizzy:

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

Jeśli wymagana jest odpowiedź z potwierdzeniem, prześlij tę odpowiedź:

Confirmed, please place the order.

Możesz też przetestować programowo w Cloud Shell lub terminalu:

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

Jeśli potrzebujesz odpowiedzi z potwierdzeniem, użyj tego polecenia:

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

Oczekiwana odpowiedź:

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

Co się dzieje za kulisami:

  1. Dynamiczne odświeżanie zasad: aktualizacja ujednoliconych zasad dostępu IAM zaczyna obowiązywać natychmiast w silniku oceny IAP bez przestojów i bez ponownego wdrażania kontenerów.
  2. Wywołanie A2A: agent obsługi wysyła żądanie przez centralną bramę agenta.
  3. Ocena zasad IAP w wersji 2 (zatwierdzenie): usługa IAP w wersji 2 dopasowuje regułę 3, weryfikuje tożsamość wywołującego i wyrażenie CEL docelowe oraz zwraca wartość ALLOW (granted: true).
  4. Wykonywanie w ramach różnych projektów: centralna brama agenta przekazuje autoryzowany ruch do PROJECT_SELLERS, gdzie sprzedawca pizzy przetwarza zamówienie.

Krok 8. Sprawdź dzienniki bramy agenta pod kątem przyznanych próśb o pizzę

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

Przykładowe dane wyjściowe logu przyznania:

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

Testowanie i weryfikacja zostały zakończone. Przejdź do sekcji Czyszczenie.

11. Czyszczenie

Aby uniknąć obciążenia konta Google Cloud opłatami za zasoby użyte w tym laboratorium, wykonaj czynności związane z usuwaniem w ścisłej odwrotnej kolejności zależności:

1. Usuwanie wdrożeń silnika rozumowania

Uruchom dołączony skrypt cleanup_old_deployments.py w obu projektach środowiska wykonawczego, aby usunąć silniki wnioskowania i poczekać na zakończenie długotrwałych operacji:

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

Możesz też wyświetlić i usunąć silniki wnioskowania w tekście:

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. Usuwanie usług 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. Usuwanie powiązania ujednoliconej zasady dostępu IAM i zasady dostępu

# 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. Usuwanie bramy agenta i zasad zabezpieczeń

# 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. Usuwanie międzyprojektowych powiązań uprawnień i roli niestandardowych

# 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

Jeśli podczas konfiguracji zostały przypisane uprawnienia roles/iam.accessPolicyAdminroles/resourcemanager.projectIamAdmin, usuń je z konta aktywnego użytkownika, aby przywrócić zasadę najmniejszych uprawnień:

# 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. Przywracanie logowania danych kontrolnych i ograniczeń zasad organizacji

# 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. Przywracanie ograniczeń zasad organizacji

# 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. Usuwanie udostępnionego zasobnika GCS i lokalnych artefaktów

# 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

To koniec części poświęconej czyszczeniu. Przejdźmy teraz do podsumowania.

12. Podsumowanie

Gratulacje! Masz wdrożoną i zarządzaną architekturę Agent-to-Agent (A2A) w wielu projektach w Google Cloud przy użyciu Agent Runtime Vertex AI, centralnej Bramy agentów, Agent Registry i Ujednoliconych zasad dostępu IAM (UAP).

Podsumowanie najważniejszych pojęć

  • Scentralizowany obwód wychodzący: kontenery środowiska wykonawczego w sieciach typu hub-and-spoke (PROJECT_CONCIERGE, PROJECT_SELLERS) kierowane przez centralną bramę agenta w regionie PROJECT_GOVERNANCE za pomocą agentGatewayConfig.
  • Deklaratywne zarządzanie (UAP): zastąpienie rozproszonych powiązań z poszczególnymi zasobami jedną, podlegającą audytowi zasadą dostępu IAM, która jest oceniana w bramie przez IAP w wersji 2.
  • Tożsamość kryptograficzna: wymuszanie ruchu wychodzącego z jak najmniejszymi uprawnieniami przy użyciu tożsamości SPIFFE kontenera (principal://...) zamiast kluczy o długim okresie ważności.
  • Dynamiczne wykrywanie usług: rozwiązywanie punktów końcowych agentów równorzędnych w czasie działania za pomocą Central Agent Registry, co eliminuje zakodowane na stałe adresy URL i identyfikatory projektów.
  • Elastyczność zasad w czasie działania: w czasie rzeczywistym zmieniono pizza-seller-agent z domyślnego odrzucania (403 Forbidden) na zezwolenie (200 OK) za pomocą aktualizacji zasad bez ponownego uruchamiania kontenera.

cosmopup

Cosmopup mówi: „Agenci są świetni – wykonują całą pracę związaną z różnymi projektami, a ja mogę się skupić na moim głównym celu: drzemce”.

Dalsze kroki i dokumentacja