Integración de PSC SWP en Agent Engine (ADK)

1. Introducción

Una interfaz de Private Service Connect es un recurso que permite que una red de nube privada virtual (VPC) de productor inicie conexiones a varios destinos en una red de VPC de consumidor. Las redes de productores y consumidores pueden estar en diferentes proyectos y organizaciones.

Si un adjunto de red acepta una conexión desde una interfaz de Private Service Connect, Google Cloud asigna a la interfaz una dirección IP de una subred de consumidor que especifica el adjunto de red. Las redes del consumidor y del productor están conectadas y pueden comunicarse mediante direcciones IP internas.

Una conexión entre un adjunto de red y una interfaz de Private Service Connect es similar a la conexión entre un extremo de Private Service Connect y un adjunto de servicio, pero tiene dos diferencias clave:

  • Un adjunto de red permite que una red de productor inicie conexiones a una red de consumidor (salida de servicio administrado), mientras que un extremo permite que una red de consumidor inicie conexiones a una red de productor (entrada de servicio administrado).
  • Una conexión de la interfaz de Private Service Connect es transitiva. Esto significa que una red del productor puede comunicarse con otras redes que están conectadas a la red del consumidor.

Consideraciones sobre la accesibilidad de la interfaz de PSC de Vertex AI

  • PSC-Interface puede enrutar el tráfico a destinos locales o de VPC que aprendió la red de VPC.
  • Para limitar el alcance de la accesibilidad desde la vinculación de red que usa Agent Engine a la red de VPC, la implementación de reglas de firewall de salida es la práctica recomendada.
  • Para limitar el alcance del tráfico de salida de la red que se origina en la subred de la conexión de red del motor de Agent, se debe implementar una regla de firewall de salida de VPC. Esta regla permitirá de forma explícita el tráfico del Agent Engine al SWP y rechazará todo el resto del tráfico saliente.

Consideraciones sobre la interfaz de PSC de Vertex AI y el VPC-SC

  • Debes proporcionar conectividad de salida a Internet dentro de la VPC del cliente para que funcione la interfaz de PSC de Agent Engine, incluso si los Controles del servicio de VPC están habilitados.

Proxy web seguro

Secure Web Proxy es un servicio administrado y nativo de la nube que te brinda control y seguridad detallados para tu tráfico saliente (HTTP/HTTPS). Actúa como una puerta de enlace central, lo que te permite aplicar políticas de seguridad en las conexiones iniciadas desde Agent Engine implementado con la interfaz de PSC a los recursos de la VPC, como las VMs, GKE, Internet y los entornos multinube.

Qué problema resuelve

  • Evita el robo de datos: Bloquea las cargas no autorizadas o la comunicación con sitios maliciosos.
  • Aplica el cumplimiento: Garantiza que el tráfico saliente cumpla con las políticas de seguridad y manejo de datos de tu organización.
  • Reduce la sobrecarga operativa: Como servicio completamente administrado, el proxy web seguro elimina la necesidad de implementar, escalar o mantener tus propias VMs de proxy.
  • Proporciona visibilidad detallada: Permite la inspección del tráfico encriptado con seguridad de la capa de transporte (TLS) para detectar amenazas ocultas.

Para obtener más información, consulta los siguientes recursos:

Implementa un agente | IA generativa en Vertex AI | Google Cloud

Configura una interfaz de Private Service Connect para los recursos de Vertex AI | Google Cloud

Qué compilarás

En este instructivo, compilarás un Agent Engine integral implementado con una interfaz de Private Service Connect (PSC) integrada en SWP para realizar las siguientes acciones con las bibliotecas del ADK:

  • Implementa la interconexión de DNS en Agent Engine para resolver el nombre de dominio completamente calificado de SWP que se usa en la configuración del proxy.
  • Permite la conectividad a un sitio público (https://api.frankfurter.app/) a través de un proxy web seguro implementado en la VPC del consumidor con una dirección RFC1918.
  • Permite el tráfico de la subred de adjuntos de red al SWP y deniega todo lo demás.

Figura 1

565e9eb07ef18f44.png

Qué aprenderás

  • Cómo crear un adjunto de red
  • Cómo un productor puede usar un adjunto de red para crear una interfaz de PSC
  • Cómo establecer la comunicación del productor al consumidor con el intercambio de tráfico de DNS
  • Cómo implementar y usar un SWP para la salida de Internet
  • Cómo definir reglas de firewall de salida para reducir la accesibilidad de la red de Agent Engine

Requisitos

Proyecto de Google Cloud

Permisos de IAM

2. Antes de comenzar

Actualiza el proyecto para que admita el instructivo

En este instructivo, se usan variables para facilitar la implementación de la configuración de gcloud en Cloud Shell.

Dentro de Cloud Shell, haz lo siguiente:

gcloud config set project [YOUR-PROJECT-NAME]
projectid=YOUR-PROJECT-NAME
echo $projectid

Habilitación de la API

Dentro de Cloud Shell, haz lo siguiente:

gcloud services enable "compute.googleapis.com"
gcloud services enable "aiplatform.googleapis.com"
gcloud services enable "dns.googleapis.com"
gcloud services enable "notebooks.googleapis.com"
gcloud services enable "storage.googleapis.com"
gcloud services enable "iap.googleapis.com"
gcloud services enable "networksecurity.googleapis.com"
gcloud services enable "networkservices.googleapis.com"
gcloud services enable "cloudresourcemanager.googleapis.com"

Verifica que las APIs se hayan habilitado correctamente

gcloud services list --enabled

3. Configuración del consumidor

Crea la VPC del consumidor

Esta VPC reside en un proyecto del cliente. Se crearán los siguientes recursos en esta VPC

  • Subred del consumidor
  • Subred de adjunto de red
  • Subred de solo proxy
  • Reglas de firewall
  • Cloud DNS

Dentro de Cloud Shell, haz lo siguiente:

gcloud compute networks create consumer-vpc --project=$projectid --subnet-mode=custom

Crea las subredes de consumidor

Dentro de Cloud Shell, crea la subred para el SWP:

gcloud compute networks subnets create swp-subnet --project=$projectid --range=10.10.10.0/28 --network=consumer-vpc --region=us-central1 --enable-private-ip-google-access

Crea la subred del adjunto de red de Private Service Connect

Dentro de Cloud Shell, crea la subred para la vinculación de red de PSC:

gcloud compute networks subnets create intf-subnet --project=$projectid --range=192.168.10.0/28 --network=consumer-vpc --region=us-central1 --enable-private-ip-google-access

Crea la subred de proxy regional

Dentro de Cloud Shell, crea la subred de solo proxy que se requiere para los productos basados en Envoy, como Secure Web Proxy y los balanceadores de cargas de aplicaciones internos o externos regionales. La marca –purpose debe establecerse en REGIONAL_MANAGED_PROXY:

gcloud compute networks subnets create proxy-subnet \
  --purpose=REGIONAL_MANAGED_PROXY \
  --role=ACTIVE \
  --region=us-central1 \
  --network=consumer-vpc \
  --range=100.100.10.0/26

Crea la subred del notebook

Dentro de Cloud Shell, crea la subred para la instancia del notebook:

gcloud compute networks subnets create notebook-subnet --project=$projectid --range=192.168.20.0/28 --network=consumer-vpc --region=us-central1 --enable-private-ip-google-access

4. Crea un proxy web seguro

El modo explícito de Secure Web Proxy (o modo de enrutamiento de proxy explícito) es un método de implementación en el que las cargas de trabajo del cliente se deben configurar de forma explícita para usar la dirección IP interna o el nombre de dominio completamente calificado y el puerto de SWP como su proxy de reenvío.

Esta política contendrá las reglas que rigen el tráfico a través del proxy web seguro en función de una coincidencia de sesión, host() == 'api.frankfurter.app' y una coincidencia de aplicación request.method == 'GET'.

En los siguientes pasos, asegúrate de modificar YOUR-PROJECT-ID por el ID de tu proyecto.

Dentro de Cloud Shell, crea un archivo policy.yaml:

cat > policy.yaml << EOF
name: projects/$projectid/locations/us-central1/gatewaySecurityPolicies/my-swp-policy 
description: "My basic SWP policy" 
EOF

En Cloud Shell, importa la política:

gcloud network-security gateway-security-policies import my-swp-policy \
    --source=policy.yaml \
    --location=us-central1

Crea reglas de Secure Web Proxy

Define reglas dentro de la política para especificar qué tráfico se permite o rechaza. Las reglas se evalúan según su prioridad.

Dentro de Cloud Shell, crea un archivo rule.yaml para permitir el acceso al extremo de Internet que usa el motor de agentes, api.frankfurter.app:

cat > rule.yaml << EOF
name: "projects/$projectid/locations/us-central1/gatewaySecurityPolicies/my-swp-policy/rules/allow-example"
description: "Allow frankfurter API"
enabled: true
priority: 10
basicProfile: ALLOW
sessionMatcher: "host() == 'api.frankfurter.app'"
EOF

En Cloud Shell, genera la regla de política de seguridad:

gcloud network-security gateway-security-policies rules import allow-example \
    --source=rule.yaml \
    --location=us-central1 \
    --gateway-security-policy=my-swp-policy

Crea reglas de Secure Web Proxy

La instancia de SWP, que se implementa en modo de enrutamiento explícito, se debe crear de modo que Agent Engine deba especificar la dirección IP o el FQDN de la SWP dentro de la configuración del proxy del ADK, como se define en el archivo YAML de la puerta de enlace. Esta configuración también vincula la instancia a la política, la red y la subred correspondientes.

Dentro de Cloud Shell, crea un archivo gateway.yaml que se usa para implementar la SWP.

Asegúrate de guardar el archivo YAML después de actualizar las siguientes variables con los detalles de tu entorno: PROJECT_ID, REGION, NETWORK_NAME y PROXY_ONLY_SUBNET_NAME. El puerto 8888 especificado es el puerto del túnel externo asignado a la configuración del proxy dentro de Agent Engine.

cat > gateway.yaml << EOF
name: "projects/$projectid/locations/us-central1/gateways/my-swp-instance"
type: SECURE_WEB_GATEWAY
ports: [8888]
addresses: ["10.10.10.5"]
gatewaySecurityPolicy: "projects/$projectid/locations/us-central1/gatewaySecurityPolicies/my-swp-policy"
network: "projects/$projectid/global/networks/consumer-vpc"
subnetwork: "projects/$projectid/regions/us-central1/subnetworks/swp-subnet"
routingMode: EXPLICIT_ROUTING_MODE
EOF

Dentro de Cloud Shell, importa la puerta de enlace:

gcloud network-services gateways import my-swp-instance \
    --source=gateway.yaml \
    --location=us-central1

5. Adjunto de red de Private Service Connect

Los adjuntos de red son recursos regionales que representan el lado del consumidor de una interfaz de Private Service Connect. Debes asociar una sola subred con un adjunto de red y el productor asigna IPs a la interfaz de Private Service Connect desde esa subred. La subred debe estar en la misma región que el adjunto de red. Un adjunto de red debe estar en la misma región que el servicio del productor.

Crea el adjunto de red

Dentro de Cloud Shell, crea la conexión de red.

gcloud compute network-attachments create psc-network-attachment \
    --region=us-central1 \
    --connection-preference=ACCEPT_AUTOMATIC \
    --subnets=intf-subnet

Enumera los archivos adjuntos de red

Dentro de Cloud Shell, enumera el adjunto de red.

gcloud compute network-attachments list

Describe los adjuntos de red

Dentro de Cloud Shell, describe el adjunto de red.

gcloud compute network-attachments describe psc-network-attachment --region=us-central1

Toma nota del nombre del adjunto de red de PSC, psc-network-attachment, que usará el productor cuando cree la interfaz de Private Service Connect.

Para ver la URL de la conexión de red de PSC en la consola de Cloud, navega a la siguiente ubicación:

Network Services → Private Service Connect → Network Attachment → psc-network-attachment

15f80b46c3a0332d.png

6. Zona de DNS privada

Crearás una zona de Cloud DNS para demo.com y la completarás con un registro A que apunte a las direcciones IP de tus SWP. Más adelante, se implementará el intercambio de tráfico de DNS en Agent Engine, lo que permitirá el acceso a los registros de DNS del consumidor.

Dentro de Cloud Shell, realiza las siguientes acciones para crear un nombre de DNS demo.com.

gcloud dns --project=$projectid managed-zones create private-dns-codelab --description="" --dns-name="demo.com." --visibility="private" --networks="https://compute.googleapis.com/compute/v1/projects/$projectid/global/networks/consumer-vpc"

Obtén y almacena las direcciones IP del SWP que se usan para el registro A de DNS.

En Cloud Shell, ejecuta una descripción en swp, my-swp-instance:

gcloud network-services gateways describe my-swp-instance --location=us-central1

Dentro de Cloud Shell, crea el conjunto de registros para la SWP, swp.demo.com, y asegúrate de actualizar la dirección IP según el resultado de tu entorno.

gcloud dns --project=$projectid record-sets create swp.demo.com. --zone="private-dns-codelab" --type="A" --ttl="300" --rrdatas="10.10.10.5"

Configuración del firewall

Crea una regla de Cloud Firewall para permitir el acceso desde la interfaz de PSC

En la siguiente sección, crea una regla de firewall que permita que el tráfico que se origina en el adjunto de red del PSC acceda a la subred de SWP en la VPC del consumidor. Para mayor seguridad, puedes especificar la dirección IP de SWP como el único destino.

En Cloud Shell, crea la regla de firewall de salida que permite el acceso desde la conexión de red al SWP:

gcloud compute firewall-rules create allow-access-to-swp \
    --network=consumer-vpc \
    --action=ALLOW \
    --rules=ALL \
    --direction=EGRESS \
    --priority=1000 \
    --source-ranges="192.168.10.0/28" \
    --destination-ranges="10.10.10.5/32" \
    --enable-logging

En Cloud Shell, crea la regla de firewall de salida que rechaza todo el tráfico del adjunto de red:

gcloud compute firewall-rules create deny-all \
    --network=consumer-vpc \
    --action=DENY \
    --rules=ALL \
    --direction=EGRESS \
    --priority=65534 \
    --source-ranges="192.168.10.0/28" \
    --destination-ranges="0.0.0.0/0" \
    --enable-logging

7. Crea una política de firewall para la red de VPC y, así, garantizar la inteligencia sobre amenazas:

En la siguiente sección, crearás una política de firewall que te permitirá aprovechar las listas de amenazas administradas de Google para bloquear sitios maliciosos conocidos antes de que el SWP reciba tráfico.

En Cloud Shell, crea la política de firewall global:

gcloud compute network-firewall-policies create psc-secure-policy \
    --global \
    --description="Policy to protect VPC with Threat Intelligence"

En Cloud Shell, asocia la política a tu VPC:

gcloud compute network-firewall-policies associations create \
    --firewall-policy=psc-secure-policy \
    --network=consumer-vpc \
    --name=psc-swp-association \
    --global-firewall-policy

En Cloud Shell, agrega las reglas de Threat Intelligence:

Estas reglas descartarán el tráfico hacia agentes maliciosos conocidos antes de iniciar el tráfico desde el agente. En este ejemplo, agregamos reglas para bloquear nodos de salida de Tor (salida), bloquear IPs maliciosas conocidas (salida), bloquear proxies anónimos conocidos(salida) y bloquear mineros de criptomonedas para evitar el uso no autorizado de recursos (salida).

gcloud compute network-firewall-policies rules create 100 \
    --firewall-policy=psc-secure-policy \
    --action=deny \
    --direction=EGRESS \
    --dest-threat-intelligence=iplist-tor-exit-nodes \
    --layer4-configs=all \
    --enable-logging \
    --description="Block anonymous Tor traffic" \
    --global-firewall-policy
gcloud compute network-firewall-policies rules create 110 \
    --firewall-policy=psc-secure-policy \
    --action=deny \
    --direction=EGRESS \
    --dest-threat-intelligence=iplist-known-malicious-ips \
    --layer4-configs=all \
    --enable-logging \
    --description="Block known botnets and malware sources" \
    --global-firewall-policy
gcloud compute network-firewall-policies rules create 120 \
    --firewall-policy=psc-secure-policy \
    --action=deny \
    --direction=EGRESS \
    --dest-threat-intelligence=iplist-anon-proxies \
    --layer4-configs=all \
    --enable-logging \
    --description="Block Known Anonymous Proxies" \
    --global-firewall-policy
gcloud compute network-firewall-policies rules create 130 \
    --firewall-policy=psc-secure-policy \
    --action=deny \
    --direction=EGRESS \
    --dest-threat-intelligence=iplist-crypto-miners \
    --layer4-configs=all \
    --enable-logging \
    --description="Block Crypto Miners (Prevent unauthorized resource usage)" \
    --global-firewall-policy

8. Crea un notebook de Jupyter

En la siguiente sección, se te guiará para crear un notebook de Jupyter. Este notebook se usará para implementar Agent Engine con un proxy explícito para la salida a Internet.

Crea una cuenta de servicio administrada por el usuario

En la siguiente sección, crearás una cuenta de servicio que se asociará con la instancia de Vertex AI Workbench que se usa en el instructivo.

En el instructivo, la cuenta de servicio tendrá los siguientes roles aplicados:

Dentro de Cloud Shell, crea la cuenta de servicio.

gcloud iam service-accounts create notebook-sa \
    --display-name="notebook-sa"

En Cloud Shell, actualiza la cuenta de servicio con el rol de administrador de Storage.

gcloud projects add-iam-policy-binding $projectid --member="serviceAccount:notebook-sa@$projectid.iam.gserviceaccount.com" --role="roles/storage.admin"

Dentro de Cloud Shell, actualiza la cuenta de servicio con el rol de usuario de Vertex AI.

gcloud projects add-iam-policy-binding $projectid --member="serviceAccount:notebook-sa@$projectid.iam.gserviceaccount.com" --role="roles/aiplatform.user"

Dentro de Cloud Shell, actualiza la cuenta de servicio con el rol de administrador de Artifact Registry.

gcloud projects add-iam-policy-binding $projectid --member="serviceAccount:notebook-sa@$projectid.iam.gserviceaccount.com" --role="roles/artifactregistry.admin"

Dentro de Cloud Shell, permite que la cuenta de servicio del notebook use la cuenta de servicio predeterminada de Compute Engine.

gcloud iam service-accounts add-iam-policy-binding \
    $(gcloud projects describe $(gcloud config get-value project) --format='value(projectNumber)')-compute@developer.gserviceaccount.com \
    --member="serviceAccount:notebook-sa@$projectid.iam.gserviceaccount.com" \
    --role="roles/iam.serviceAccountUser"

9. Crea una instancia de Vertex AI Workbench

En la siguiente sección, crea una instancia de Vertex AI Workbench que incorpore la cuenta de servicio creada anteriormente, notebook-sa.

Dentro de Cloud Shell, crea la instancia de private-client.

gcloud workbench instances create workbench-tutorial --vm-image-project=cloud-notebooks-managed --vm-image-family=workbench-instances --machine-type=n1-standard-4 --location=us-central1-a --subnet-region=us-central1 --subnet=notebook-subnet --disable-public-ip --shielded-secure-boot=true --shielded-integrity-monitoring=true --shielded-vtpm=true --service-account-email=notebook-sa@$projectid.iam.gserviceaccount.com     

Agrega otra regla en el Proxy web seguro existente para reenviar el tráfico desde esta instancia del notebook:

En Cloud Shell, crea el archivo rule-notebook.yaml con un editor de texto y asegúrate de actualizar el archivo YAML con tu ID del proyecto.

cat > rule-notebook.yaml << EOF
name: projects/$projectid/locations/us-central1/gatewaySecurityPolicies/my-swp-policy/rules/allow-notebook-subnet
description: Allow Internet access for notebook subnet
enabled: true
priority: 2
basicProfile: ALLOW
sessionMatcher: inIpRange(source.ip,'192.168.20.2')
EOF

En Cloud Shell, genera la regla de política de seguridad:

gcloud network-security gateway-security-policies rules import allow-notebook-subnet \
    --source=rule-notebook.yaml \
    --location=us-central1 \
    --gateway-security-policy=my-swp-policy

10. Actualización del agente de servicio de Vertex AI

Vertex AI actúa en tu nombre para realizar operaciones como obtener una dirección IP de la subred del adjunto de red de PSC que se usa para crear la interfaz de PSC. Para ello, Vertex AI usa un agente de servicio (que se indica a continuación) que requiere permiso de administrador de red:

service-$projectnumber@gcp-sa-aiplatform.iam.gserviceaccount.com

En Cloud Shell, obtén el número de tu proyecto.

gcloud projects describe $projectid | grep projectNumber

En Cloud Shell, establece el número de tu proyecto.

projectnumber=YOUR-PROJECT-NUMBER

En Cloud Shell, crea una cuenta de servicio para AI Platform. Omite este paso si ya tienes una cuenta de servicio en tu proyecto.

gcloud beta services identity create --service=aiplatform.googleapis.com --project=$projectnumber

Dentro de Cloud Shell, actualiza la cuenta del agente de servicio con el rol compute.networkAdmin.

gcloud projects add-iam-policy-binding $projectid --member="serviceAccount:service-$projectnumber@gcp-sa-aiplatform.iam.gserviceaccount.com" --role="roles/compute.networkAdmin"

Dentro de Cloud Shell, actualiza la cuenta del agente de servicio con el rol dns.peer

gcloud projects add-iam-policy-binding $projectid --member="serviceAccount:service-$projectnumber@gcp-sa-aiplatform.iam.gserviceaccount.com" --role="roles/dns.peer"

Actualización de la cuenta de servicio predeterminada

Otorga a tu cuenta de servicio predeterminada acceso a Vertex AI. Ten en cuenta que el cambio de acceso puede tardar un poco en propagarse.

En Cloud Shell, actualiza la cuenta de servicio predeterminada con el rol aiplatform.user

gcloud projects add-iam-policy-binding $projectid \
  --member="serviceAccount:$projectnumber-compute@developer.gserviceaccount.com" \
    --role="roles/aiplatform.user"

11. Implementa Agent Engine

Nota: Usaremos la consola de GCP y el notebook de JupyterLab para completar las tareas de esta sección.

En la siguiente sección, crearás un notebook que realizará las siguientes tareas:

  • Usa la API de Frankfurter (https://api.frankfurter.app/) para obtener datos del tipo de cambio.
  • Hace referencia a un proxy explícito (proxy_server) que segmenta el SWP en la VPC de los consumidores con el FQDN swp.demo.com
  • Define dnsPeeringConfigs "domain": "demo.com.".

Ejecuta el trabajo de entrenamiento en la instancia de Vertex AI Workbench.

  • En la consola de Google Cloud, navega a Vertex AI → Workbench.
  • Junto al nombre de la instancia de Vertex AI Workbench (workbench-tutorial), haz clic en Open JupyterLab. Tu instancia de Vertex AI Workbench abre JupyterLab.
  • Seleccionar File > New > Notebook
  • Seleccionar Kernel > Python 3

Instala las bibliotecas de Python necesarias: Instala las bibliotecas necesarias para Agent Engine, incluidas pyyaml, google-cloud-aiplatform, cloudpickle, google-cloud-api-keys y langchain-google-vertexai.

En tu notebook de JupyterLab, crea una celda nueva y ejecuta el siguiente comando especificando la dirección IP del SWP

7b827a6a38bb5afc.png

!pip install --proxy http://10.10.10.5:8888 --upgrade google-cloud-aiplatform[agent_engines,adk]

Define las siguientes variables según tu entorno en el siguiente fragmento de código:

  • ID DEL PROYECTO
  • BUCKET_NAME
  • AGENT_NAME

En este lab, usarás las variables BUCKET_NAME y AGENT_NAME para inicializar y configurar tu bucket de almacenamiento que está disponible a nivel global.

En la siguiente sección, se define el PROXY_SERVER, p. ej., swp.demo.com, que requiere la interconexión de DNS para la resolución de nombres. En la configuración, AGENT_PEER_DOMAIN se implementa como demo.com, que corresponde a la zona de DNS privada creada en un paso anterior dentro de AGENT_PEER_NETWORK, consumer-vpc.

En tu notebook de JupyterLab, crea una celda nueva y ejecuta lo siguiente:

# --- Fundamental Project Configuration ---
PROJECT_ID = "YOUR_PROJECT_ID"
LOCATION = "us-central1" # e.g., "us-central1"
BUCKET_NAME = "YOUR_BUCKET_NAME" # A GCS bucket in the same location

# --- Agent Configuration ---
AGENT_NAME = "YOUR_AGENT_NAME"
MODEL = "gemini-2.5-flash" # Or another suitable model

# --- Network and Proxy Configuration ---
# The agent will call the Frankfurter API via this proxy
PROXY_SERVER = "http://swp.demo.com:8888"

# --- Deployment Configuration (PSC & DNS Peering) ---
# This should be a pre-existing Network Attachment
NETWORK_ATTACHMENT_NAME = f"projects/{PROJECT_ID}/regions/{LOCATION}/networkAttachments/psc-network-attachment"
# Optional DNS Peering config
AGENT_PEER_DOMAIN = "demo.com."
AGENT_PEER_NETWORK = "consumer-vpc"

# --- Initialize Vertex AI SDK ---
import vertexai
STAGING_BUCKET = f"gs://{BUCKET_NAME}"

vertexai.init(project=PROJECT_ID, location=LOCATION, staging_bucket=STAGING_BUCKET)

print(f"Vertex AI SDK initialized for project {PROJECT_ID} in {LOCATION}.")

En tu notebook de JupyterLab, crea una celda nueva y ejecuta lo siguiente.

!adk create $AGENT_NAME --model=$MODEL --project=$PROJECT_ID --region=$LOCATION

En tu notebook de JupyterLab, crea una celda nueva y ejecuta el siguiente comando para crear la variable de proxy que corresponde al FQDN y al puerto de los SWP.

import os
os.environ["PROXY_SERVER_URL"] = "http://swp.demo.com:8888"

En la siguiente celda de código, se muestra la configuración explícita del proxy para que Agent Engine acceda a la API del extremo de Internet api.frankfurter.app especificando el SWP con PROXY_SERVER_TO_USE, que se asigna a os.environ["PROXY_SERVER_URL"]..

import requests
# Use the globally defined proxy server URL
    proxies = {
       "http": PROXY_SERVER_TO_USE,
       "https": PROXY_SERVER_TO_USE,
    }
    try:
        response = requests.get(
            f"https://api.frankfurter.app/{currency_date}",
            params={"from": currency_from, "to": currency_to},
            proxies=proxies,
) 
response.raise_for_status() 
print(response.json()) 
except requests.exceptions.RequestException as e: print(f"An error occurred: {e}")

En tu notebook de JupyterLab, crea una celda nueva y ejecuta el siguiente código que define la implementación de la herramienta para la API de segmentación de intercambio de divisas api.frankfurter.app.

%%writefile $AGENT_NAME/agent.py
from google.adk.agents.llm_agent import Agent
import os
import requests


# Get Proxy Server URL
# This is the VM's FQDN to reach the proxy vm in the consumers network
if "PROXY_SERVER_URL" not in os.environ:
    raise ValueError("Missing required environment variable: PROXY_SERVER_URL is not set.")
PROXY_SERVER_TO_USE = os.environ["PROXY_SERVER_URL"]

# Mock tool implementation
def get_exchange_rate(
    currency_from: str = "USD",
    currency_to: str = "EUR",
    currency_date: str = "latest",
):
    """Retrieves the exchange rate between two currencies on a specified date.

    Uses the Frankfurter API (https://api.frankfurter.app/) to obtain
    exchange rate data.

    Args:
        currency_from: The base currency (3-letter currency code).
            Defaults to "USD" (US Dollar).
        currency_to: The target currency (3-letter currency code).
            Defaults to "EUR" (Euro).
        currency_date: The date for which to retrieve the exchange rate.
            Defaults to "latest" for the most recent exchange rate data.
            Can be specified in YYYY-MM-DD format for historical rates.

    Returns:
        dict: A dictionary containing the exchange rate information.
            Example: {"amount": 1.0, "base": "USD", "date": "2023-11-24",
                "rates": {"EUR": 0.95534}}
    """
    # Use the globally defined proxy server URL
    proxies = {
       "http": PROXY_SERVER_TO_USE,
       "https": PROXY_SERVER_TO_USE,
    }
    
    try:
        response = requests.get(
            f"https://api.frankfurter.app/{currency_date}",
            params={"from": currency_from, "to": currency_to},
            proxies=proxies,
        )
        response.raise_for_status()  # Raise an error for bad responses
        return response.json()
    except Exception as e:
        return f"An unexpected error occurred: {e}"

root_agent = Agent(
    model='gemini-2.5-flash',
    name='root_agent',
    description="Provides the currency exchange rates between two currencies",
    instruction="You are a helpful assistant that provides the currency exchange rates between two currencies. Use the 'get_exchange_rate' tool for this purpose.",
    tools=[get_exchange_rate],
)

En tu notebook de JupyterLab, crea una celda nueva y ejecuta lo siguiente.

# 1. Set your variables
CURRENCY_DATE="latest"
CURRENCY_FROM="USD"
CURRENCY_TO="EUR"
PROXY_SERVER="http://swp.demo.com:8888"

# 2. Run the curl command
!curl -x "$PROXY_SERVER" "https://api.frankfurter.app/$CURRENCY_DATE?from=$CURRENCY_FROM&to=$CURRENCY_TO"

En tu notebook de JupyterLab, crea una celda nueva y ejecuta el siguiente comando que invoca la configuración de la interfaz de PSC que usa Agent Engine, además de la interconexión de DNS.

import json
import os

CONFIG_FILE_PATH = os.path.join(AGENT_NAME, ".agent_engine_config.json")
# Create your config as a Python dictionary ---
config_data = {
    "requirements": [
        "google-cloud-aiplatform[agent_engines,adk]",
        "requests",
    ],
    "psc_interface_config": {
        "network_attachment": NETWORK_ATTACHMENT_NAME,
        "dns_peering_configs": [
            {
                "domain": AGENT_PEER_DOMAIN,
                "target_project": PROJECT_ID,
                "target_network": AGENT_PEER_NETWORK,
            },
        ],
    },
}

# Write the dictionary to a JSON file ---
os.makedirs(AGENT_NAME, exist_ok=True) # Ensure the directory exists
with open(CONFIG_FILE_PATH, 'w') as f:
    json.dump(config_data, f, indent=4)

print(f"Successfully created {CONFIG_FILE_PATH} with your variables.")

En tu notebook de JupyterLab, crea una celda nueva y ejecuta lo siguiente.

import json
import os

CONFIG_FILE_PATH = os.path.join(AGENT_NAME, ".agent_engine_config.json")
# Create your config as a Python dictionary ---
config_data = {

    "psc_interface_config": {
        "network_attachment": NETWORK_ATTACHMENT_NAME,
        "dns_peering_configs": [
            {
                "domain": AGENT_PEER_DOMAIN,
                "target_project": PROJECT_ID,
                "target_network": AGENT_PEER_NETWORK,
            },
        ],
    },
}

# Write the dictionary to a JSON file ---
os.makedirs(AGENT_NAME, exist_ok=True) # Ensure the directory exists
with open(CONFIG_FILE_PATH, 'w') as f:
    json.dump(config_data, f, indent=4)

print(f"Successfully created {CONFIG_FILE_PATH} with your variables.")

En tu notebook de JupyterLab, crea una celda nueva y ejecuta lo siguiente.

%%writefile $AGENT_NAME/.env

GOOGLE_CLOUD_PROJECT=PROJECT_ID
GOOGLE_CLOUD_LOCATION=us-central1
GOOGLE_GENAI_USE_VERTEXAI=1


PROXY_SERVER_URL=http://swp.demo.com:8888

En tu notebook de JupyterLab, crea una celda nueva y ejecuta el siguiente código para crear el agente.

!adk deploy agent_engine $AGENT_NAME --staging_bucket=$STAGING_BUCKET --env_file=$AGENT_NAME/.env --agent_engine_config_file=$AGENT_NAME/.agent_engine_config.json --display_name=$AGENT_NAME

Se generará un ID del motor de inferencia cuando se ejecute la celda. Para el siguiente paso, necesitarás el ID generado, que es 3235268984265768960 en este ejemplo.

✅ Created agent engine: projects/9315891080/locations/us-central1/reasoningEngines/3235268984265768960

En tu notebook de JupyterLab, crea una celda nueva y ejecuta lo siguiente. Asegúrate de actualizar el número de proyecto y el ID del razonamiento del motor de agentes del resultado anterior:

from vertexai import agent_engines
remote_app = agent_engines.get("projects/PROJECT_NUMBER/locations/us-central1/reasoningEngines/ENTER_YOUR_ID")

En tu notebook de JupyterLab, crea una celda nueva y ejecuta lo siguiente.

def print_event_nicely_with_thoughts(event):
    """
    Parses and prints streaming query events, including thoughts.
    """
    try:
        content = event.get('content', {})
        role = content.get('role')
        parts = content.get('parts', [{}])

        if not parts:
            print("...")
            return

        part = parts[0] # Get the first part

        # Event 1: Model is thinking (calling a tool or just text)
        if role == 'model':

            # Check for and print any explicit 'thought' text
            if 'thought' in part:
                print(f"🧠 Thought: {part['thought']}")

            # Check for a function call
            if 'function_call' in part:
                # If we haven't *already* printed an explicit thought,
                # print a generic one.
                if 'thought' not in part:
                    print("🧠 Thinking... (decided to use a tool)")

                call = part['function_call']
                print(f"   🔧 Tool Call: {call.get('name')}()")
                print(f"      Args: {call.get('args')}")

            # Check for the final text answer
            elif 'text' in part:
                text = part.get('text', '')
                print(f"\n💬 Model: {text}")

        # Event 2: The tool returns its result
        elif role == 'user' and 'function_response' in part:
            resp = part['function_response']
            print(f"⚙️ Tool Response (from {resp.get('name')}):")
            print(f"   Output: {resp.get('response')}")

        # Other event types (like progress messages)
        else:
            print("...") # Show progress for other events

    except Exception as e:
        print(f"Error processing event: {e}")
        # print(f"Raw event: {event}") # Uncomment to debug



for event in remote_app.stream_query(
    user_id="u_456",
    # session_id=remote_session["id"],
    message="Provide USD to INR conversion rate",
):
    print_event_nicely_with_thoughts(event)

Ejemplo de una ejecución exitosa que valida la conectividad con el extremo público api.frankfurther.app a través de SWP según el tipo de cambio de USD a INR.

f9f925983ab5cc9d.png

12. Validación de la interfaz de PSC

También puedes ver las IPs de Network Attachment que usa Agent Engine. Para ello, navega a la siguiente ubicación:

Servicios de red → Private Service Connect → Adjunto de red → psc-network-attachment

Selecciona el proyecto de usuario (el nombre del proyecto termina en -tp).

c9c412334a7f5ad9.png

El campo destacado indica la dirección IP que usa Agent Engine desde el adjunto de red de PSC.

e94c6c03fb51f7fe.png

13. SWP: Validación de Cloud Logging

Para validar el tráfico de salida de Internet que realiza el SWP, puedes ver Cloud Logging. Para ello, navega a lo siguiente:

Supervisión → Explorador de registros

Inserta la consulta: resource.type=" networkservices.googleapis.com/Gateway" y, luego, haz clic en Ejecutar consulta. A continuación, se muestra un ejemplo que confirma el extremo de destino, api.frankfurter.app.

f53831ef8ec663db.png

fc154a5b22da2a87.png

En el siguiente ejemplo de Cloud Logging, se validan los siguientes elementos:

Destination_range: Dirección IP de la interfaz de PSC de Agent Engine

Source_range: Subred de solo proxy Dest_ip: Dirección IP del proxy web seguro

Asegúrate de cambiar el project_id de la consulta de Cloud Logging.

logName:("projects/project_id/logs/compute.googleapis.com%2Ffirewall") AND jsonPayload.rule_details.reference:("network:consumer-vpc/firewall:allow-access-to-swp")
{
  "insertId": "1j9ym95fmu8g6o",
  "jsonPayload": {
    "vpc": {
      "project_id": "XXXXXXXXXXXXX",
      "subnetwork_name": "intf-subnet",
      "vpc_name": "consumer-vpc"
    },
    "rule_details": {
      "destination_range": [
        "10.10.10.5/32"
      ],
      "reference": "network:consumer-vpc/firewall:allow-access-to-swp",
      "priority": 1000,
      "source_range": [
        "192.168.10.0/28"
      ],
      "direction": "EGRESS",
      "ip_port_info": [
        {
          "ip_protocol": "ALL"
        }
      ],
      "action": "ALLOW"
    },
    "disposition": "ALLOWED",
    "remote_instance": {
      "region": "us-central1"
    },
    "remote_vpc": {
      "vpc_name": "consumer-vpc",
      "project_id": "XXXXXXXXXXXXXXX",
      "subnetwork_name": "swp-subnet"
    },
    "connection": {
      "src_ip": "192.168.10.2",
      "src_port": 48640,
      "dest_port": 8888,
      "dest_ip": "10.10.10.5",
      "protocol": 6
    }
  },
  "resource": {
    "type": "gce_subnetwork",
    "labels": {
      "subnetwork_id": "7147084067647653041",
      "project_id": "XXXXXXXXXXXXXX",
      "location": "us-central1",
      "subnetwork_name": "intf-subnet"
    }
  },
  "timestamp": "2025-12-30T12:51:36.628538815Z",
  "logName": "projects/dec30-run1-agent/logs/compute.googleapis.com%2Ffirewall",
  "receiveTimestamp": "2025-12-30T12:51:40.846652708Z"
}

14. Limpia

En tu notebook de JupyterLab, crea una celda nueva y ejecuta el siguiente comando que activará la eliminación de la implementación de Agent Engine.

Asegúrate de actualizar "project number" y "reasoningEngines token".

import requests
token = !gcloud auth application-default print-access-token
ENDPOINT = "https://us-central1-aiplatform.googleapis.com"
response = requests.delete(
    f"{ENDPOINT}/v1beta1/projects/218166745590/locations/us-central1/reasoningEngines/3086854705725308928",
    params={"force": "true"},
    headers={
        "Content-Type": "application/json; charset=utf-8",
        "Authorization": f"Bearer {token[0]}"
    },
)
print(response.text)

Borra los componentes del instructivo desde Cloud Shell.

gcloud workbench instances delete workbench-tutorial --project=$projectid --location=us-central1-a

gcloud network-security gateway-security-policies rules delete allow-notebook-subnet \
    --gateway-security-policy=my-swp-policy \
    --location=us-central1

gcloud network-security gateway-security-policies rules delete allow-example \
    --gateway-security-policy=my-swp-policy \
    --location=us-central1

gcloud network-security gateway-security-policies delete my-swp-policy \
    --location=us-central1
gcloud network-services gateways delete my-swp-instance\
    --location=us-central1

gcloud dns record-sets delete swp.demo.com --zone=private-dns-codelab  --type=A

gcloud dns managed-zones delete private-dns-codelab


gcloud compute network-attachments delete psc-network-attachment --region=us-central1 --quiet

export ROUTER_NAME=$(gcloud compute routers list --regions=us-central1 \
    --filter="name ~ swg-autogen-router" --format="value(name)")


 gcloud compute routers nats delete swg-autogen-nat --router=$ROUTER_NAME --region=us-central1 --quiet 

gcloud compute routers delete $ROUTER_NAME --region=us-central1 --quiet

gcloud compute networks subnets delete intf-subnet rfc1918-subnet1 --region=us-central1 --quiet

gcloud compute networks subnets delete intf-subnet swp-subnet
 --region=us-central1 --quiet

gcloud compute networks subnets delete intf-subnet intf-subnet --region=us-central1 --quiet

gcloud compute networks subnets delete intf-subnet proxy-subnet
 --region=us-central1 --quiet

gcloud compute networks subnets delete intf-subnet notebook-subnet
--region=us-central1 --quiet

gcloud compute networks delete consumer-vpc --quiet

15. Felicitaciones

¡Felicitaciones! Configuraste y validaste correctamente Agent Engine implementado con la interfaz de Private Service Connect con salida a Internet realizada a través de un proxy explícito.

Creaste la infraestructura del consumidor y agregaste un adjunto de red que permitió al productor crear una VM con varias NIC para conectar la comunicación entre el consumidor y el productor. Aprendiste a crear un proxy explícito y un intercambio de tráfico de DNS que permitieron la conectividad a Internet.

Cosmopup cree que los instructivos son geniales.

e6d3675ca7c6911f.jpeg

¿Qué sigue?

Lecturas y videos adicionales

Documentos de referencia