Governança centralizada do Gateway de Agente com o Agent Registry entre projetos para o Agent Runtime

1. Introdução

À medida que as empresas adotam a IA generativa, as arquiteturas evoluem rapidamente de chatbots autônomos e monolíticos para sistemas distribuídos de vários agentes (agente para agente / A2A). Nessas topologias modernas, os agentes orquestradores de alto nível coordenam fluxos de trabalho complexos delegando tarefas a agentes de trabalho especializados em domínios, servidores de ferramentas do Protocolo de Contexto de Modelo (MCP) e bancos de dados empresariais de back-end em projetos independentes do Google Cloud.

No entanto, operar sistemas multiagentes em grande escala apresenta desafios críticos de segurança, governança e operação:

  • Proliferação de agentes e ferramentas secundárias:quando as equipes de desenvolvimento implantam agentes em projetos isolados sem um catálogo centralizado, as organizações perdem a visibilidade das ferramentas e dos subagentes existentes.
  • Saída entre projetos não monitorada:permitir que os agentes tenham rotas de rede diretas e não inspecionadas cria riscos de exfiltração de dados e ignora os perímetros de segurança.
  • Integrações fixadas no código frágeis:fixar no código URLs de agentes downstream e IDs do Reasoning Engine cria dependências frágeis que são interrompidas durante upgrades ou novas implantações.
  • Falta de identidade com privilégio mínimo:as contas de serviço compartilhadas não oferecem não repúdio criptográfico no nível da instância do agente individual.

Para resolver esses desafios, a Gemini Enterprise Agent Platform oferece um plano de controle unificado de governança e conectividade composto por quatro pilares principais:

  1. Gateway do agente (networkservices.googleapis.com):um proxy gerenciado de rede regional e aplicação de políticas. Operando no modo de saída AGENT_TO_ANYWHERE, ele intercepta o tráfego de saída do agente, delega avaliações de autorização a extensões de segurança e roteia solicitações em perímetros de projetos.
  2. Agent Registry (agentregistry.googleapis.com):o único catálogo de serviços empresariais. Ele oferece um diretório centralizado e verificado de todas as ferramentas, servidores MCP e agentes semelhantes disponíveis na organização, permitindo a descoberta automática dinâmica de tempo de execução sem endpoints codificados.
  3. Governança de identidade do agente e IAP v2 (iap.googleapis.com e iam.googleapis.com):uma estrutura criptográfica de identidade e acesso. Os agentes de execução recebem URNs de máquina SPIFFE exclusivos e atestados (principal://...). O egress de saída é avaliado em relação às políticas de acesso unificado (UAP / IAP v2) do IAM centralizadas, verificando a permissão universal iap.googleapis.com/resources.egressViaIAP usando condições avançadas do catálogo da Common Expression Language (CEL) (destination.agent_registry.*).
  4. Ambiente de execução do agente (mecanismos de inferência):uma plataforma de execução sem servidor totalmente gerenciada para aplicativos de agente baseados em Python, com vinculações de configuração nativas (agent_gateway_config) a gateways centrais.

Codelab: cenário de negócios: compra de alimentos e bebidas em vários projetos

Neste codelab, você vai criar e governar um ecossistema de compras de vários projetos do mundo real que abrange três projetos distintos do Google Cloud:

  • Projeto de governança central (PROJECT_GOVERNANCE): de propriedade da TI central e da SecOps, hospedando o Gateway de Agente central, o Agent Registry central e as Políticas de Acesso Unificadas do IAM.
  • Projeto do orquestrador do consumidor (PROJECT_CONCIERGE): de propriedade da equipe de compras, hospeda o agente concierge de compras, que descobre dinamicamente os fornecedores e encaminha os pedidos dos clientes.
  • Projeto do fornecedor de domínio (PROJECT_SELLERS): de propriedade de fornecedores externos ou departamentais, hospedando o agente de vendas de hambúrguer e o agente de vendas de pizza.

figure1

Figura 1. Arquitetura de governança centralizada de vários projetos

Por que a governança centralizada entre projetos?

Em grandes empresas, as equipes de produtos e os grupos de ciência de dados criam agentes de IA em dezenas de projetos independentes do Google Cloud. Dar a cada equipe controle direto sobre o registro de ferramentas, rotas de rede de saída e proteções de segurança cria uma proliferação de ferramentas não verificadas, políticas de DLP inconsistentes, saída de VPC não monitorada e registros de auditoria fragmentados.

A governança centralizada entre projetos separa a criação de políticas da execução do agente:

  • A TI central e o SecOps criam políticas de segurança, avaliam ferramentas e monitoram a saída em um único projeto de governança centralizada.
  • As equipes de produtos e aplicativos se concentram apenas na lógica de negócios nos projetos do Agent Runtime independentes, vinculando-se diretamente ao gateway central sem o overhead operacional de gerenciar VPCs locais, interconexões ou Policy Engines fragmentados.

figure2

Fig. 2. Arquitetura e limites de governança de três níveis entre projetos

Modelo de escopo de identidade de duas camadas em políticas de acesso unificadas

Quando os agentes se comunicam pelo Gateway de Agente Central, o Identity-Aware Proxy (IAP v2) avalia o acesso com base na Identidade do Agente do chamador, uma identidade criptograficamente atestada e baseada em SPIFFE emitida automaticamente para o contêiner de execução, em relação a uma política de acesso global do IAM:

  • Nível 1: APIs do Cloud básicas do Google Cloud (granulares via principalSet:// na Regra 1): autorização de saída em todo o projeto, permitindo que todos os tempos de execução do agente em projetos de spoke alcancem as APIs padrão do Google (aiplatform, iamcredentials, telemetry, agentregistry) para descoberta, geração de tokens e inferência.
  • Nível 2: ferramentas comerciais e serviços A2A (refinado via principal:// nas regras 2 e 3): acesso estrito de menor privilégio vinculado a instâncias individuais do Reasoning Engine, aplicado com condições da Common Expression Language (CEL) segmentando serviços específicos registrados no Agent Registry (destination.agent_registry.agent.name).

O que você vai criar

  • Gateway de agente centralizado (centralized-agw) em PROJECT_GOVERNANCE
  • Extensão do serviço de autorização da IAP v2 e política de autorização no modo ESTRICT ENFORCE (failOpen: false)
  • Política de acesso unificada do IAM fundamental (uap-rules.json) e vinculação de política do projeto
  • Permissões do IAM de agente de serviço entre projetos (ar_agw_cross_project_sa)
  • Bucket de preparação central compartilhada do Google Cloud Storage (GCS)
  • Agentes isolados de venda de hambúrgueres e pizzas em PROJECT_SELLERS
  • Agente de concierge de compras com autodescoberta dinâmica de REST em PROJECT_CONCIERGE
  • Registros de serviço no Central Agent Registry com URLs mTLS entre projetos
  • Atualizações dinâmicas da política de saída do IAP v2 com verificação em tempo real e auditorias do Cloud Logging

figure3

Figura 3. Sequência de implementação detalhada

Conteúdo do laboratório

  • Como configurar permissões do IAM do agente de serviço entre projetos para gateways centralizados
  • Como rotear a saída do Agent Runtime por um Gateway de Agente central em ambientes de vários projetos
  • Como delegar a autorização do Gateway de Agente ao Identity-Aware Proxy (IAP v2) usando Service Extensions (iapPolicyVersion: "V2")
  • Como criar e vincular políticas de acesso unificado (UAP, na sigla em inglês) do IAM com regras da Common Expression Language (CEL) que regem destinos registrados do Agent Registry (destination.agent_registry.*)
  • Como eliminar IDs e URLs de agentes codificados usando a descoberta automática de tempo de execução no Agent Registry
  • Como testar o bloqueio de confiança zero de perímetro real (HTTP 403 Forbidden) e verificar atualizações de políticas ativas no Cloud Logging

O que é necessário

  • Três projetos do Google Cloud com o faturamento ativado:
    • PROJECT_GOVERNANCE: políticas de governança central, gateway, registro e acesso do IAM
    • PROJECT_CONCIERGE: agente orquestrador do concierge de compras
    • PROJECT_SELLERS: agentes de vendas especializados em hambúrgueres e pizzas
  • Um usuário do IAM ou uma conta de serviço com permissões roles/owner ou administrativas em todos os três projetos
  • Uma organização do Google Cloud (para mapeamento de domínio de confiança do SPIFFE)
  • Google Cloud Shell ou uma máquina local com a CLI gcloud, python (3.11 ou mais recente) e uv instalados

Isso conclui a parte de introdução. Em seguida, vamos para a seção Configuração e ambiente.

2. Configuração

Embora essa arquitetura abranja três projetos distintos do Google Cloud, é possível executar 100% dos comandos de implantação do terminal, downloads de repositório e operações de preparo em um único terminal do Cloud Shell definido como PROJECT_GOVERNANCE. Todos os scripts de implantação e comandos gcloud têm como destino explícito o projeto de destino adequado usando flags da CLI (--project).

Comece acessando a linha de comando do projeto na nuvem do Google Cloud:

Definir o contexto do projeto

# 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

Definir variáveis de ambiente shell

Insira os identificadores específicos do projeto.

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

Essas variáveis de shell serão derivadas automaticamente.

# 2. Regional & Gateway Settings
export REGION="us-central1"
export AGW_NAME="centralized-agw"
export UAP_POLICY_NAME="uap-policy-${AGW_NAME}"
export UAP_BINDING_NAME="uap-binding-${AGW_NAME}"

# 3. Retrieve Project Numbers
export PROJECT_NUMBER_GOVERNANCE=$(gcloud projects describe ${PROJECT_GOVERNANCE} --format="value(projectNumber)")
export PROJECT_NUMBER_CONCIERGE=$(gcloud projects describe ${PROJECT_CONCIERGE} --format="value(projectNumber)")
export PROJECT_NUMBER_SELLERS=$(gcloud projects describe ${PROJECT_SELLERS} --format="value(projectNumber)")

# 4. Obtain Organization ID
export ORG_ID=$(gcloud projects get-ancestors ${PROJECT_GOVERNANCE} --format="value(id, type)" | grep organization | awk '{print $1}')

# 5. Set Application Default Credentials (ADC) Quota Project
gcloud auth application-default set-quota-project ${PROJECT_GOVERNANCE}

echo "Governance Project: ${PROJECT_GOVERNANCE} (${PROJECT_NUMBER_GOVERNANCE})"
echo "Concierge Project:  ${PROJECT_CONCIERGE} (${PROJECT_NUMBER_CONCIERGE})"
echo "Sellers Project:    ${PROJECT_SELLERS} (${PROJECT_NUMBER_SELLERS})"
echo "Organization ID:    ${ORG_ID}"
echo "UAP Policy Name:    ${UAP_POLICY_NAME}"
echo "UAP Binding Name:   ${UAP_BINDING_NAME}"

Criar diretório local para arquivos de configuração

# create config folder
mkdir -p cfg

Atribuir o papel de administrador da política de acesso para políticas de acesso unificadas

# 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

Ativar os registros de acesso a dados de auditoria do Cloud para o IAP v2

Por padrão, o Google Cloud desativa os registros de auditoria de acesso a dados para evitar custos de armazenamento não intencionais. Como o IAP v2 emite decisões de autorização (granted=true e granted=false) como registros de auditoria de acesso a dados, ative o registro em ADMIN_READ, DATA_READ e DATA_WRITE para iap.googleapis.com em 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)"

ativar as APIs obrigatórias do Google Cloud

# 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

Validar a ativação da API em todos os projetos

Garantir que todos os três projetos (PROJECT_GOVERNANCE, PROJECT_CONCIERGE e PROJECT_SELLERS) tenham exatamente as mesmas APIs ativadas estabelece consistência operacional e evita falhas na geração de tokens de tempo de execução, erros de catalogação de esquemas ou interrupções de telemetria.

Execute o seguinte script de validação no Cloud Shell para verificar a paridade de API nos três projetos:

# 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

Exemplo de saída da validação:

Todas as APIs vão aparecer ativadas.

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

Configurar políticas da organização

As políticas padrão da organização do Google Cloud aplicam restrições que limitam as vinculações de políticas de acesso do IAM v3 a recursos (constraints/iam.managed.disableAccessPolicyBinding).

Substitua as restrições de política da organização herdadas no nível do projeto definindo explicitamente enforce: false como "permitir".

# disable iam v3 constraint (allow v3 access policies)
gcloud org-policies set-policy /dev/stdin << EOF
name: projects/${PROJECT_NUMBER_GOVERNANCE}/policies/iam.managed.disableAccessPolicyBinding
spec:
  rules:
  - enforce: false
EOF
# verify org policy constraints on project
gcloud org-policies describe iam.managed.disableAccessPolicyBinding \
  --project=${PROJECT_GOVERNANCE} --effective

Com isso, concluímos a parte de configuração. Agora, vamos para a seção Registrar APIs principais do Google.

3. Agent Registry

Registrar o serviço de endpoint das APIs principais do Google

O Gateway de Agente exige que os URLs das APIs do Google sejam registrados no Central Agent Registry para que os agentes configurados com agent_gateway_config possam rotear o tráfego de saída com segurança para os serviços de back-end principais do Google Cloud, como aiplatform, credenciais do IAM e telemetria.

Criar core-gapi-services no Agent Registry

# register core google api endpoints in agent registry with standard and :443 port variants
gcloud agent-registry services create core-gapi-services \
  --project=${PROJECT_GOVERNANCE} \
  --location=${REGION} \
  --display-name="gapi.core.services" \
  --description="Core Google Cloud APIs and Service Endpoints" \
  --endpoint-spec-type=no-spec \
  --interfaces=protocolBinding=JSONRPC,url=https://telemetry.googleapis.com \
  --interfaces=protocolBinding=JSONRPC,url=https://telemetry.mtls.googleapis.com \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com:443 \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com:443 \
  --interfaces=protocolBinding=JSONRPC,url=https://aiplatform.googleapis.com \
  --interfaces=protocolBinding=JSONRPC,url=https://aiplatform.googleapis.com:443 \
  --interfaces=protocolBinding=JSONRPC,url=https://aiplatform.mtls.googleapis.com \
  --interfaces=protocolBinding=JSONRPC,url=https://aiplatform.mtls.googleapis.com:443 \
  --interfaces=protocolBinding=JSONRPC,url=https://cloudresourcemanager.googleapis.com \
  --interfaces=protocolBinding=JSONRPC,url=https://iamcredentials.googleapis.com \
  --interfaces=protocolBinding=JSONRPC,url=https://iamcredentials.mtls.googleapis.com \
  --interfaces=protocolBinding=JSONRPC,url=https://agentregistry.googleapis.com \
  --interfaces=protocolBinding=JSONRPC,url=https://agentregistry.mtls.googleapis.com \
  --interfaces=protocolBinding=JSONRPC,url=https://agentregistry.googleapis.com:443 \
  --interfaces=protocolBinding=JSONRPC,url=https://agentregistry.mtls.googleapis.com:443

Capturar o ID do recurso do endpoint das APIs principais

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

Entender principalSet e principal na identidade do agente

No IAM do Google Cloud e na plataforma de agentes do Gemini Enterprise, as identidades de máquina emitidas para contêineres de agentes em execução usam URNs do SPIFFE atestados criptograficamente avaliados pelo Identity-Aware Proxy (IAP v2). Ao configurar políticas de acesso unificado do IAM, é possível segmentar um único principal específico ou um principalSet baseado em atributos:

Dimensão

principal:// (identidade de máquina única)

principalSet:// (grupo com base em atributos)

Sintaxe do IAM

principal://...

principalSet://...

Granularidade

Granular (no nível da instância): identifica uma única instância específica do contêiner do Reasoning Engine.

Granularidade grosseira (nível do projeto): identifica todos os mecanismos de inferência que compartilham um atributo comum do projeto.

Padrão de 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}

Caso de uso na Agent Platform

Nível 2 (ferramentas comerciais e A2A): autorização de agentes orquestradores específicos para invocar ferramentas de domínio de destino (por exemplo, concierge de compras $\rightarrow$ vendedor de hambúrgueres).

Nível 1 (infraestrutura básica): conceder a todos os agentes em um projeto acesso de saída às APIs do Google Cloud (core-gapi-services).

Impacto no ciclo de vida

Se um agente for excluído e recriado, o novo ID do mecanismo vai exigir uma vinculação de política do IAM atualizada.

É aplicada automaticamente a agentes recém-implantados nesse projeto sem atualizações adicionais do IAM.

Governança declarativa com políticas de acesso unificadas (UAP / IAP v2)

No IAP v1 legada, as políticas de saída eram anexadas diretamente a recursos individuais do Agent Registry usando gcloud beta iap web add-iam-policy-binding. Em IAP v2 e políticas de acesso unificado, as vinculações por recurso são eliminadas em favor de uma única política de acesso do IAM centralizada (cfg/uap-rules.json).

A autorização de saída fundamental para core-gapi-services será configurada como Regra 1 na política de acesso unificado na seção 5, garantindo que todos os contêineres de agente tenham rotas de saída fundamentais estabelecidas antes da implantação.

Para mais detalhes técnicos sobre identificadores principais e mecanismos de identidade da carga de trabalho, consulte:

Isso conclui o registro do endpoint das APIs principais. Em seguida, vamos para a seção Implantar o Gateway de Agente centralizado.

4. Gateway de Agente

Implantar o gateway de agente centralizado

Implante o Gateway de Agente centralizado (centralized-agw) no modo de saída AGENT_TO_ANYWHERE dentro do projeto $PROJECT_GOVERNANCE.

Definir o manifesto de configuração do gateway

Crie cfg/${AGW_NAME}.yaml para governança de tráfego de saída:

# 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

Importar configuração do gateway de agente

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

Verificar detalhes do Gateway de Agente

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

Exemplo de resposta:

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'

Isso conclui a implantação do gateway. Em seguida, acesse a seção Configurar autorização.

5. Autorização

Configurar a autorização do gateway de agente e o UAP básico

O Gateway de Agente protege e governa o tráfego de saída de ferramentas e agentes usando políticas de autorização (networksecurity.authzPolicies) integradas às políticas de acesso unificado (UAP) do Identity-Aware Proxy (IAP v2).

Visão geral da arquitetura de autorização

figure4

Figura 4. Visão geral da arquitetura de autorização

A arquitetura de autorização é composta de três camadas interconectadas:

  1. Extensão de serviço do IAP (authzExtension): recurso regional configurado com service: iap.googleapis.com, metadata: iapPolicyVersion: "V2" e failOpen: false para aplicação estrita de zero trust no perímetro.
  2. Política de autorização do gateway (authzPolicy): recurso regional que segmenta seu Gateway de Agente com policyProfile: REQUEST_AUTHZ e action: CUSTOM, encaminhando as verificações de autorização para a extensão de autorização do IAP.
  3. Política e vinculação de acesso unificado do IAM (accessPolicy e policyBinding): recurso global do IAM v3 avaliado pelo IAP. Ele verifica a permissão universal iap.googleapis.com/resources.egressViaIAP em relação às identidades SPIFFE do caller e às condições do catálogo CEL.

Etapa 1: criar e importar a extensão Authz do IAP v2

Crie o manifesto da extensão de serviço com iapPolicyVersion: "V2" e failOpen: false no modo ENFORCE estrito:

# 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

Importe a extensão de autorização:

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

Verifique se a extensão Authz está ativa:

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

Exemplo de resposta:

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

Etapa 2: criar e importar a política de autorização do gateway

Crie uma configuração de política de autorização que se conecte ao Gateway de Agente e delegue a verificação de solicitações à extensão Authz do 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

Importe a política de autorização:

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

Verifique a política de autorização ativa:

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

Etapa 3: criar a política de acesso unificado inicial (regra 1: APIs principais do Google)

Crie cfg/uap-rules.json com a regra 1, autorizando os três principalSets do projeto a alcançar 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

Etapa 4: criar e vincular a política de acesso do IAM

Crie a política de acesso global do IAM:

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

Vincule a política de acesso a PROJECT_GOVERNANCE:

# bind access policy to governance project
gcloud iam policy-bindings create ${UAP_BINDING_NAME} \
  --policy="projects/${PROJECT_GOVERNANCE}/locations/global/accessPolicies/${UAP_POLICY_NAME}" \
  --target-resource="//cloudresourcemanager.googleapis.com/projects/${PROJECT_GOVERNANCE}" \
  --project=${PROJECT_GOVERNANCE} \
  --location=global

Verifique se a vinculação de política está ativa:

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

Exemplo de resposta:

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}

A saída da API do Google Cloud fundamental agora é autorizada com segurança em todos os três projetos no modo estrito ENFORCE.

Isso conclui a configuração de autorização do gateway. Em seguida, acesse a seção Configurar permissões do IAM entre projetos.

6. IAM entre projetos

Configurar permissões do IAM entre projetos

Nessa topologia de vários projetos, os Agent Runtimes residem em projetos de spoke (PROJECT_CONCIERGE e PROJECT_SELLERS), enquanto o Gateway de Agente central e o Agent Registry residem em PROJECT_GOVERNANCE.

Como os projetos do Google Cloud são perímetros de segurança isolados, o acesso entre projetos precisa ser concedido explicitamente em duas camadas operacionais:

  1. Plano de controle (tempo de implantação): ao implantar um contêiner de agente configurado com --agent-gateway-config, o Agent Runtime Service Agent (service-@gcp-sa-aiplatform.iam.gserviceaccount.com) do projeto spoke precisa anexar o contêiner ao gateway central. Criamos um papel personalizado mínimo (ar_agw_cross_project_sa) que concede networkservices.agentGateways.use, get e operations.get em PROJECT_GOVERNANCE.
  2. Plano de dados (execução de ambiente de execução):
    • Descoberta de catálogo:as identidades do spoke precisam de roles/agentregistry.viewer em PROJECT_GOVERNANCE para resolver os endpoints do agente de destino de forma dinâmica.
    • Invocação de destino:o agente do Concierge precisa de roles/aiplatform.user em PROJECT_SELLERS para executar consultas nos mecanismos de raciocínio do vendedor.

Criar um papel personalizado do IAM em 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"

Atribuir papel personalizado aos agentes de serviço do 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

Isso conclui a configuração do IAM entre projetos. Em seguida, acesse a seção Implantar agentes de vendedor e concierge.

7. Agent Runtime

Implantar agentes de vendas e concierge

O codebase do aplicativo multiagente e os scripts de implantação usados neste codelab são mantidos em um repositório remoto do GitHub do Google Cloud. As etapas a seguir vão clonar o repositório localmente, copiar os arquivos necessários para a estrutura do diretório de trabalho atual, limpar os arquivos temporários e instalar as dependências com uv.

Buscar artefatos remotos

# clone remote repository to temp local dir
git clone https://github.com/GoogleCloudPlatform/cloud-networking-solutions.git ./temp_agw_cuj_arun_multiproject
# copy multi-agent application files to current working directory
cp -r temp_agw_cuj_arun_multiproject/codelabs/agw-cuj-arun-multiproject ./cross-project-multiagent
# remove temporary directory
rm -rf temp_agw_cuj_arun_multiproject
# install dependencies
uv sync --directory ./cross-project-multiagent

Criar bucket de preparo central compartilhado

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

Como funciona a vinculação do Gateway de Agente entre projetos

Nesta etapa, você vai implantar os agentes de vendedor no projeto spoke (PROJECT_SELLERS) e configurá-los para rotear a saída pelo gateway de agente central em 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)

Como a Regra 1 foi estabelecida anteriormente na nossa política de acesso unificado, as solicitações de inicialização de contêineres para APIs do Google Cloud são permitidas pelo gateway sem interrupção.

Implantar agentes de venda de hambúrgueres e pizzas no 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}

Validar o roteamento do 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

Implantar o agente de concierge de compras no 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}

Validar o roteamento do gateway de compra

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

A saída precisa mostrar a identidade e o projeto de tempo de execução do agente do Concierge e a vinculação ao gateway de agente do projeto de governança.

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

Isso conclui as implantações de agentes. Em seguida, vamos para a seção Registrar agentes no Central Agent Registry.

8. Registro entre projetos

Registrar agentes no Central Agent Registry

Registre os três agentes no registro central de agentes em PROJECT_GOVERNANCE usando endpoints regionais de mTLS entre projetos e números de projetos numéricos.

Registrar serviços como agentes não A2A no 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

Capturar IDs do Agent Registry subjacentes

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

Concluímos a configuração do registro. Agora vamos para a seção Configurar políticas de saída A2A.

9. Políticas da UAP

Configurar políticas de saída A2A na política de acesso unificada

Na arquitetura Default Deny do Agent Gateway no modo ENFORCE estrito:

  1. Regra 1 (APIs básicas do Google Cloud): permite que contêineres de agentes em todos os três projetos alcancem core-gapi-services.
  2. Regra 2 (agente de vendas de hambúrgueres: ALLOW): permite que a instância do agente de concierge de compras invoque especificamente o agente de vendas de hambúrgueres.
  3. Agente de vendas de pizza (NEGADO por padrão): intencionalmente deixado de fora das regras da política. No modo ENFORCE (failOpen: false), qualquer tentativa do Concierge de invocar o vendedor de pizza será encerrada imediatamente no perímetro do gateway com HTTP 403 Forbidden.

Formular a identidade do agente de concierge

# formulate the exact SPIFFE machine identity for the Concierge Agent
export CONCIERGE_SPIFFE_PRINCIPAL="principal://agents.global.org-${ORG_ID}.system.id.goog/resources/aiplatform/projects/${PROJECT_NUMBER_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}"
echo "Concierge SPIFFE Principal: ${CONCIERGE_SPIFFE_PRINCIPAL}"

Atualizar o manifesto com as regras 1 e 2

Crie novas cfg/uap-rules-update-2.json para incluir a Regra 1 (APIs principais) e agora a Regra 2 (agente de vendas de hambúrgueres):

# 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

Aplicar política de acesso atualizada

# 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

Verificar detalhes da política de acesso do IAM

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

Exemplo de resposta:

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

Isso conclui a configuração da política. Em seguida, acesse a seção Testar e verificar políticas de governança.

10. Verificar políticas

Testar e verificar políticas de governança usando o Cloud Logging

Nesta seção, você vai testar interações entre projetos de agente para agente (A2A) no playground de IA do Agent Runtime, observar o bloqueio de perímetro real HTTP 403 Forbidden no modo estrito ENFORCE, modificar a política de acesso unificado ao vivo e validar a aprovação imediata de pedidos.

Etapa 1: abrir o playground de IA do Agent Runtime em PROJECT_CONCIERGE

  1. Abra o Console do Google Cloud.
  2. Na barra do seletor de projetos na parte de cima, mude para PROJECT_CONCIERGE.
  3. No menu de navegação, acesse Agent Platform > Agentes > Implantações.
  4. Clique em purchasing-concierge-adk.
  5. Selecione Playground para abrir a interface de chat interativa no lado direito da tela.

Etapa 2: testar o pedido de hambúrguer (correspondência da regra 2 -> 200 OK)

Na janela de chat do Playground, envie o seguinte comando de pedido:

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

Se for necessário enviar uma resposta de confirmação, envie o seguinte:

Confirmed, please place the order.

Como alternativa, teste de forma programática no Cloud Shell / terminal:

uv run --directory ./cross-project-multiagent python -c "
import vertexai
from vertexai.preview import reasoning_engines
vertexai.init(project='${PROJECT_CONCIERGE}', location='${REGION}')
agent = reasoning_engines.ReasoningEngine('projects/${PROJECT_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}')
response = agent.query(input={'message': 'I would like 22 Spicy Cajun Burgers please. Place this order now.'})
print(response)
"

Se uma resposta de confirmação for necessária, use este comando:

uv run --directory ./cross-project-multiagent python -c "
import vertexai
from vertexai.preview import reasoning_engines
vertexai.init(project='${PROJECT_CONCIERGE}', location='${REGION}')
agent = reasoning_engines.ReasoningEngine('projects/${PROJECT_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}')
response = agent.query(input='Yes please place the order now.')
print(response['text'])
"

O que acontece nos bastidores:

  1. Descoberta dinâmica:durante a inicialização da sessão, o Concierge de Compras consultou o Agent Registry Central em PROJECT_GOVERNANCE (via core-gapi-services pelo Gateway de Agente autorizado pela Regra 1) para descobrir o endpoint mTLS regional de burger-seller-agent.
  2. Resolução de intent e invocação de A2A:o Gemini no Purchasing Concierge analisa a intent de pedido de comida e invoca o agente Burger Seller usando uma RPC de saída para https://${REGION}-aiplatform.mtls.googleapis.com/.../reasoningEngines/${BURGER_ENGINE_ID}.
  3. Interceptação do gateway e propagação do SPIFFE:o tráfego de saída é capturado por agent_gateway_config e direcionado ao Gateway de Agente central em PROJECT_GOVERNANCE, carregando a identidade criptográfica do SPIFFE do Concierge (principal://...).
  4. Avaliação da política do IAP v2:o Gateway de Agente central invoca a extensão de autorização do IAP (authzExtension). O IAP v2 avalia a regra 2 na política de acesso unificado do IAM. Como o autor da chamada corresponde a ${CONCIERGE_SPIFFE_PRINCIPAL} e o destino corresponde a burger-seller-agent, a IAP retorna ALLOW (granted: true).
  5. Execução entre projetos:o gateway de agente faz proxy da solicitação autorizada entre projetos para PROJECT_SELLERS, em que o mecanismo de raciocínio do vendedor de hambúrgueres processa o pedido e retorna a confirmação.

Resposta esperada:

Your order for 10 Classic Cheeseburger(s) has been placed!
Here is a summary of your order:
- 10x Classic Cheeseburger @ IDR 85,000/each = IDR 850,000

Total: IDR 850,000
Your Order ID is: e8f9c732-f347-4cc4-acff-cfe09ccbeddd

Etapa 3: inspecionar os registros de auditoria do Gateway de Agente e do IAP v2 (HTTP 200 / ALLOWED)

Consultar registros de solicitações do Gateway de Agente em 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
  )"

Os registros precisam capturar o tráfego de saída originado dos dois projetos de spoke (PROJECT_CONCIERGE e PROJECT_SELLERS) com campos de saída para chamadas de inferência do Gemini (generateContent), telemetria do Cloud Trace (/v1/traces) e pesquisas de credenciais do IAM, que são interceptadas e autorizadas de forma transparente pela regra 1 (core-gapi-services).

Consulte os registros de acesso a dados de auditoria do Cloud do IAP v2 para verificar a versão da política POLICY_VERSION_V2:

# query IAP v2 audit logs with shortened principal and resource fields
gcloud logging read "
  logName=\"projects/${PROJECT_GOVERNANCE}/logs/cloudaudit.googleapis.com%2Fdata_access\"
  AND protoPayload.serviceName=\"iap.googleapis.com\"
" \
  --project="${PROJECT_GOVERNANCE}" \
  --limit=5 \
  --format="table(
    timestamp.date('%H:%M:%S'):label=TIME,
    protoPayload.authenticationInfo.principalSubject.sub('\.global\..*\/reasoningEngines\/', '.[...]/reasoningEngines/'):label=CALLER,
    protoPayload.authorizationInfo[0].granted:label=GRANTED,
    protoPayload.metadata.destination.agent_registry.resource_type.basename():label=TYPE,
    protoPayload.metadata.destination.agent_registry.resource_id.basename():label=RESOURCE_ID,
    protoPayload.authorizationInfo[0].permission.basename():label=PERMISSION
  )"

Exemplo de resposta:

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

Etapa 4: testar o pedido de pizza (negação padrão -> HTTP 403 proibido FORÇADO)

Na mesma janela de conversa do Playground, envie o seguinte comando de pedido de pizza:

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

Se for necessário enviar uma resposta de confirmação, envie o seguinte:

Confirmed, please place the order.

Como alternativa, teste de forma programática no Cloud Shell / terminal:

uv run --directory ./cross-project-multiagent python -c "
import vertexai
from vertexai.preview import reasoning_engines
vertexai.init(project='${PROJECT_CONCIERGE}', location='${REGION}')
agent = reasoning_engines.ReasoningEngine('projects/${PROJECT_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}')
response = agent.query(input='I would like 8 Hawaiian pizzas, please. Place this order now.')
print(response)
"

Se uma resposta de confirmação for necessária, use este comando:

uv run --directory ./cross-project-multiagent python -c "
import vertexai
from vertexai.preview import reasoning_engines
vertexai.init(project='${PROJECT_CONCIERGE}', location='${REGION}')
agent = reasoning_engines.ReasoningEngine('projects/${PROJECT_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}')
response = agent.query(input='Yes please place the order now.')
print(response['text'])
"

Resposta esperada:

I apologize, but I am unable to process that request at the moment. It seems
there was an issue connecting to the pizza seller agent. Please try again later.

O que acontece nos bastidores:

  1. Descoberta dinâmica:o Concierge de compras resolveu o endpoint pizza-seller-agent do Agent Registry central durante a inicialização.
  2. Resolução de intenção e invocação de A2A:o Gemini no concierge de compras tenta enviar a solicitação de pedido de pizza ao endpoint do vendedor de pizza em PROJECT_SELLERS.
  3. Interceptação de gateway:a RPC de saída é capturada pelo agent_gateway_config e direcionada ao gateway de agente central.
  4. Avaliação de políticas do IAP v2 (negação padrão): o gateway de agente central invoca o IAP v2. Como nenhuma regra existe na política de acesso unificada que corresponde a pizza-seller-agent, o IAP retorna DENY (granted: false).
  5. Bloqueio de perímetro estrito:como a extensão de autorização está no modo restrito (failOpen: false), o Gateway de Agente central encerra imediatamente a conexão de saída e retorna HTTP 403 Forbidden. O tráfego nunca sai do gateway e nunca chega a PROJECT_SELLERS.

Etapa 5: inspecionar os registros do Gateway de Agente para solicitações bloqueadas (HTTP 403 / NEGADO)

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

Exemplo de saída de registro negado:

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

Consulte os registros de auditoria de acesso a dados da IAP v2 para a decisão negada:

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

Exemplo de saída de registro de auditoria negado:

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

Etapa 6: conceder acesso de saída dinamicamente ao Pizza Agent

Crie novas cfg/uap-rules-update-3.json para incluir a regra 1 (APIs principais), a regra 2 (agente de vendas de hambúrguer) e agora a regra 3 (agente de vendas de pizza).

# create addendum to update policy manifest with Rule 3 for Pizza Agent
cat > cfg/uap-rules-update-3.json << EOF
[
  {
    "description": "Rule 3: Allow Purchasing Concierge to invoke Pizza Seller Agent via Central Gateway",
    "effect": "ALLOW",
    "principals": [
      "${CONCIERGE_SPIFFE_PRINCIPAL}"
    ],
    "operation": {
      "permissions": [
        "iap.googleapis.com/resources.egressViaIAP"
      ]
    },
    "conditions": {
      "iap.googleapis.com": {
        "expression": \
        "destination.is_registered == true && \
         destination.agent_registry.resource_type == 'AGENT' && ( \
         destination.agent_registry.agent.name == 'projects/${PROJECT_GOVERNANCE}/locations/${REGION}/agents/pizza-seller-agent' || \
         destination.agent_registry.agent.name == 'projects/${PROJECT_GOVERNANCE}/locations/${REGION}/agents/${PIZZA_AGENT_ID}' || \
         destination.agent_registry.agent.name == 'projects/${PROJECT_NUMBER_GOVERNANCE}/locations/${REGION}/agents/${PIZZA_AGENT_ID}')"
      }
    }
  }
]
EOF

Aplique a atualização da política em tempo real:

# 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

Etapa 7: consultar o agente de pizza novamente (sucesso imediato 200 OK)

Na janela de conversa do Playground, envie novamente o comando do pedido de pizza:

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

Se for necessário enviar uma resposta de confirmação, envie o seguinte:

Confirmed, please place the order.

Como alternativa, teste de forma programática no Cloud Shell / terminal:

uv run --directory ./cross-project-multiagent python -c "
import vertexai
from vertexai.preview import reasoning_engines
vertexai.init(project='${PROJECT_CONCIERGE}', location='${REGION}')
agent = reasoning_engines.ReasoningEngine('projects/${PROJECT_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}')
response = agent.query(input='I would like 11 Veggie pizzas, please. Place this order now.')
print(response)
"

Se uma resposta de confirmação for necessária, use este comando:

uv run --directory ./cross-project-multiagent python -c "
import vertexai
from vertexai.preview import reasoning_engines
vertexai.init(project='${PROJECT_CONCIERGE}', location='${REGION}')
agent = reasoning_engines.ReasoningEngine('projects/${PROJECT_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}')
response = agent.query(input='Yes please place the order now.')
print(response['text'])
"

Resposta esperada:

Your order has been placed!

**Order ID:** 8d6c13d7-31dc-4d80-b6a7-80d1e50b6411

**Order Details:**
*   10 x BBQ Chicken Pizza @ IDR 130,000 each = IDR 1,300,000

**Total: IDR 1,300,000**

O que acontece nos bastidores:

  1. Atualização dinâmica de políticas:a atualização da política de acesso unificado do IAM entra em vigor imediatamente no mecanismo de avaliação da IAP sem tempo de inatividade e sem precisar reimplantar contêineres.
  2. Invocação do A2A:o Concierge envia a solicitação pelo Gateway de Agente Central.
  3. Avaliação da política da IAP v2 (aprovação): a IAP v2 corresponde à regra 3, verifica a identidade do caller e a expressão CEL de destino e retorna ALLOW (granted: true).
  4. Execução entre projetos:o Central Gateway de Agente faz proxy do tráfego autorizado para PROJECT_SELLERS, onde o Pizza Seller processa o pedido.

Etapa 8: inspecionar os registros do Gateway de Agente para solicitações de pizza concedidas

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

Exemplo de saída de registro de concessão:

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

Isso conclui os testes e a verificação. Em seguida, vamos para a seção Limpeza.

11. Limpeza

Para evitar cobranças na sua conta do Google Cloud pelos recursos usados neste codelab, execute as etapas de encerramento na ordem inversa de dependência:

1. Limpar implantações do Reasoning Engine

Execute o script cleanup_old_deployments.py incluído nos dois projetos de tempo de execução para excluir os mecanismos de inferência e aguardar as operações de longa duração:

# delete all Reasoning Engines deployed in Concierge and Sellers projects
uv run --directory ./cross-project-multiagent python cleanup_old_deployments.py --project=${PROJECT_CONCIERGE} --region=${REGION}
uv run --directory ./cross-project-multiagent python cleanup_old_deployments.py --project=${PROJECT_SELLERS} --region=${REGION}

Como alternativa, você pode listar e excluir mecanismos de raciocínio inline:

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. Excluir serviços do 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. Excluir vinculação da política de acesso unificada do IAM e política de acesso

# 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. Excluir o Gateway de Agente e as políticas de segurança

# 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. Remover vinculações do IAM entre projetos e função personalizada

# 1. remove custom role and network viewer bindings for spoke service agents
for NUM in "${PROJECT_NUMBER_CONCIERGE}" "${PROJECT_NUMBER_SELLERS}"; do
  SA="service-${NUM}@gcp-sa-aiplatform.iam.gserviceaccount.com"
  
  gcloud projects remove-iam-policy-binding ${PROJECT_GOVERNANCE} \
    --member="serviceAccount:${SA}" \
    --role="projects/${PROJECT_GOVERNANCE}/roles/ar_agw_cross_project_sa" --quiet || true

  gcloud projects remove-iam-policy-binding ${PROJECT_GOVERNANCE} \
    --member="serviceAccount:${SA}" \
    --role="roles/networkservices.viewer" --quiet || true
done
# 2. remove registry viewer permissions across both spoke projects
for NUM in "${PROJECT_NUMBER_CONCIERGE}" "${PROJECT_NUMBER_SELLERS}"; do
  for MEMBER in \
    "serviceAccount:service-${NUM}@gcp-sa-aiplatform.iam.gserviceaccount.com" \
    "serviceAccount:service-${NUM}@gcp-sa-aiplatform-re.iam.gserviceaccount.com" \
    "serviceAccount:${NUM}-compute@developer.gserviceaccount.com" \
    "principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${NUM}"; do
      gcloud projects remove-iam-policy-binding ${PROJECT_GOVERNANCE} \
        --member="${MEMBER}" \
        --role="roles/agentregistry.viewer" --quiet || true
  done
done
# 3. remove project viewer permissions
for MEMBER in \
  "serviceAccount:${PROJECT_NUMBER_CONCIERGE}-compute@developer.gserviceaccount.com" \
  "serviceAccount:service-${PROJECT_NUMBER_CONCIERGE}@gcp-sa-aiplatform.iam.gserviceaccount.com"; do
    gcloud projects remove-iam-policy-binding ${PROJECT_GOVERNANCE} \
      --member="${MEMBER}" \
      --role="roles/viewer" --quiet || true
done
# 4. remove spoke-to-spoke delegation in Sellers project
for MEMBER in \
  "serviceAccount:service-${PROJECT_NUMBER_CONCIERGE}@gcp-sa-aiplatform.iam.gserviceaccount.com" \
  "serviceAccount:service-${PROJECT_NUMBER_CONCIERGE}@gcp-sa-aiplatform-re.iam.gserviceaccount.com" \
  "serviceAccount:${PROJECT_NUMBER_CONCIERGE}-compute@developer.gserviceaccount.com" \
  "principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJECT_NUMBER_CONCIERGE}"; do
    gcloud projects remove-iam-policy-binding ${PROJECT_SELLERS} \
      --member="${MEMBER}" \
      --role="roles/aiplatform.user" --quiet || true
done
# 5. delete custom IAM role after all bindings have been unlinked
gcloud iam roles delete ar_agw_cross_project_sa \
  --project=${PROJECT_GOVERNANCE} --quiet || true

Se você atribuiu roles/iam.accessPolicyAdmin e roles/resourcemanager.projectIamAdmin durante a fase de configuração, remova-os da sua conta de usuário ativa para restaurar o privilégio mínimo:

# 6. remove Access Policy Admin and Project IAM Admin roles from user
for ROLE in "roles/iam.accessPolicyAdmin" "roles/resourcemanager.projectIamAdmin"; do
  gcloud projects remove-iam-policy-binding ${PROJECT_GOVERNANCE} \
    --member="user:$(gcloud config get-value account)" \
    --role="${ROLE}" \
    --condition=None --quiet || true
done

6. Reverter a geração de registros de dados de auditoria e as restrições da política da organização

# 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. Reverter restrições da política da organização

# 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. Excluir bucket de preparo compartilhado do GCS e artefatos locais

# 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

Isso conclui a parte de revisão dos dados. Em seguida, vamos para a Conclusão.

12. Conclusão

Parabéns! Você implantou e governou uma arquitetura multi-projeto de Comunicação entre Agentes (A2A) no Google Cloud usando o Vertex AI Agent Runtime, o Central Agent Gateway, o Agent Registry e as políticas de acesso unificado (UAP) do IAM.

Resumo dos principais conceitos

  • Perímetro de saída centralizado:contêineres de tempo de execução de spoke roteados (PROJECT_CONCIERGE, PROJECT_SELLERS) por um Gateway de Agente central em PROJECT_GOVERNANCE usando agentGatewayConfig.
  • Governança declarativa (UAP): substituiu vinculações fragmentadas por recurso por uma única política de acesso do IAM auditável, avaliada no gateway pelo IAP v2.
  • Identidade criptográfica:saída de privilégio mínimo forçada usando identidades SPIFFE de contêiner (principal://...) em vez de chaves de longa duração.
  • Descoberta dinâmica de serviços:resolveu Agent Endpoints semelhantes em tempo de execução usando o Agent Registry central, eliminando URLs e IDs de projetos fixados no código.
  • Agilidade da política de tempo de execução:a transição de pizza-seller-agent de negação padrão (403 Forbidden) para permitido (200 OK) em tempo real via atualização de política, sem reinicializações de contêiner.

cosmopup

Cosmopup diz: "Os agentes são ótimos. Eles fazem todo o trabalho entre projetos enquanto eu me concentro no meu objetivo principal: dormir!"

Próximas etapas e documentação