Intégration de l'ADK (Agent Engine) PSC SWP

1. Introduction

Une interface Private Service Connect est une ressource qui permet à un réseau cloud privé virtuel (VPC) de producteur d'initier des connexions avec différentes destinations dans un réseau VPC consommateur. Les réseaux de producteurs et les réseaux de clients peuvent appartenir à différents projets et organisations.

Si un rattachement de réseau accepte une connexion depuis une interface Private Service Connect, Google Cloud attribue à l'interface une adresse IP d'un sous-réseau client spécifié par le rattachement de réseau. Les réseaux utilisateur et producteur sont connectés et peuvent communiquer à l'aide d'adresses IP internes.

Une connexion entre un rattachement de réseau et une interface Private Service Connect est semblable à la connexion entre un point de terminaison Private Service Connect et un rattachement de service, avec toutefois deux différences majeures :

  • Un rattachement de réseau permet à un réseau producteur d'établir des connexions avec un réseau consommateur (sortie de service géré), tandis qu'un point de terminaison permet à un réseau consommateur d'établir des connexions avec un réseau producteur (entrée de service géré).
  • Une connexion d'interface Private Service Connect est transitive. Cela signifie qu'un réseau de producteur peut communiquer avec d'autres réseaux connectés au réseau du client.

Considérations concernant l'accessibilité de l'interface PSC Vertex AI

  • L'interface PSC est capable de router le trafic vers des destinations VPC ou sur site apprises par le réseau VPC.
  • Pour limiter la portée de l'accessibilité du rattachement réseau utilisé par Agent Engine au réseau VPC, la meilleure pratique consiste à implémenter des règles de pare-feu de sortie.
  • Pour limiter le champ d'application du trafic réseau sortant provenant du sous-réseau de rattachement réseau d'Agent Engine, une règle de pare-feu de sortie VPC doit être déployée. Cette règle autorisera explicitement le trafic de l'Agent Engine vers le SWP, tout en refusant tout autre trafic sortant.

Considérations concernant VPC-SC pour l'interface PSC Vertex AI

  • Vous devez fournir une connectivité Internet sortante dans le VPC client pour que l'interface PSC Agent Engine fonctionne, même si VPC Service Controls est activé.

Secure Web Proxy

Le proxy Web sécurisé est un service géré et cloud-natif qui vous offre un contrôle précis et une sécurité pour votre trafic sortant (HTTP/HTTPS). Il sert de passerelle centrale et vous permet d'appliquer des règles de sécurité aux connexions initiées à partir d'Agent Engine déployé avec l'interface PSC vers les ressources VPC, telles que les VM, GKE, Internet et les environnements multicloud.

Problèmes résolus

  • Empêche l'exfiltration de données : bloque les importations non autorisées ou la communication avec des sites malveillants.
  • Garantit la conformité : assure que le trafic sortant respecte les règles de sécurité et de traitement des données de votre organisation.
  • Réduction des coûts opérationnels : Secure Web Proxy étant un service entièrement géré, vous n'avez pas besoin de déployer, de mettre à l'échelle ni de gérer vos propres VM de proxy.
  • Visibilité approfondie : permet d'inspecter le trafic chiffré TLS (Transport Layer Security) pour détecter les menaces cachées.

Pour en savoir plus, consultez les ressources suivantes :

Déployer un agent | IA générative sur Vertex AI | Google Cloud

Configurer une interface Private Service Connect pour les ressources Vertex AI | Google Cloud

Ce que vous allez faire

Dans ce tutoriel, vous allez créer un Agent Engine complet déployé avec une interface Private Service Connect (PSC) intégrée à SWP pour effectuer les opérations suivantes à l'aide des bibliothèques ADK :

  • Déployez le peering DNS dans Agent Engine pour résoudre le nom de domaine complet des SWP utilisé dans la configuration du proxy.
  • Autorisez la connectivité à un site public (https://api.frankfurter.app/) via un proxy Web sécurisé déployé dans le VPC du consommateur avec une adresse RFC1918.
  • Autorisez le trafic du sous-réseau de rattachement réseau vers le SWP, tout en refusant tout autre trafic.

Figure 1

565e9eb07ef18f44.png

Points abordés

  • Créer un rattachement de réseau
  • Comment un producteur peut utiliser un rattachement de réseau pour créer une interface PSC
  • Établir une communication du producteur au consommateur à l'aide de l'appairage DNS
  • Déployer et utiliser un SWP pour la sortie Internet
  • Définir des règles de pare-feu de sortie pour réduire l'accessibilité réseau d'Agent Engine

Prérequis

Projet Google Cloud

Autorisations IAM

2. Avant de commencer

Mettre à jour le projet pour qu'il soit compatible avec le tutoriel

Ce tutoriel utilise des $variables pour faciliter l'implémentation de la configuration gcloud dans Cloud Shell.

Dans Cloud Shell, procédez comme suit :

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

Activation de l'API

Dans Cloud Shell, procédez comme suit :

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"

Vérifier que les API sont activées

gcloud services list --enabled

3. Configuration du client

Créer le VPC consommateur

Ce VPC réside dans un projet client. Les ressources suivantes seront créées dans ce VPC :

  • Sous-réseau du client
  • Sous-réseau de rattachement de réseau
  • Sous-réseau proxy réservé
  • Règles de pare-feu
  • Cloud DNS

Dans Cloud Shell, procédez comme suit :

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

Créer les sous-réseaux consommateurs

Dans Cloud Shell, créez le sous-réseau pour le 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

Créer le sous-réseau de rattachement de réseau Private Service Connect

Dans Cloud Shell, créez le sous-réseau pour l'association de réseau 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

Créer le sous-réseau proxy régional

Dans Cloud Shell, créez le sous-réseau proxy réservé requis pour les produits basés sur Envoy, tels que Secure Web Proxy et les équilibreurs de charge d'application internes/externes régionaux. L'indicateur "–purpose" doit être défini sur 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

Créer le sous-réseau du notebook

Dans Cloud Shell, créez le sous-réseau pour l'instance de 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. Créer un proxy Web sécurisé

Le mode explicite (ou mode de routage de proxy explicite) de Secure Web Proxy est une méthode de déploiement dans laquelle les charges de travail client doivent être explicitement configurées pour utiliser l'adresse IP interne, le nom de domaine complet et le port de SWP comme proxy de transfert.

Cette stratégie contiendra les règles qui régissent le trafic via le proxy Web sécurisé en fonction d'une correspondance de session host() == 'api.frankfurter.app' et d'une correspondance d'application request.method == 'GET'.

Dans les étapes ci-dessous, veillez à remplacer YOUR-PROJECT-ID par l'ID de votre projet.

Dans Cloud Shell, créez un fichier policy.yaml :

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

Dans Cloud Shell, importez la stratégie :

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

Créer des règles de proxy Web sécurisé

Définissez des règles dans la stratégie pour spécifier le trafic autorisé ou refusé. Les règles sont évaluées en fonction de leur priorité.

Dans Cloud Shell, créez un fichier rule.yaml pour autoriser l'accès au point de terminaison Internet utilisé par le moteur de l'agent, 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

Dans Cloud Shell, générez la règle de stratégie de sécurité :

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

Créer des règles de proxy Web sécurisé

L'instance SWP, déployée en mode de routage explicite, doit être créée de sorte que le moteur d'agent soit tenu de spécifier l'adresse IP ou le nom de domaine complet du SWP dans la configuration du proxy ADK, comme défini dans le fichier YAML de la passerelle. Cette configuration associe également l'instance à la règle, au réseau et au sous-réseau correspondants.

Dans Cloud Shell, créez un fichier gateway.yaml utilisé pour déployer le SWP.

Veillez à enregistrer le fichier YAML après avoir mis à jour les variables suivantes avec les détails de votre environnement : PROJECT_ID, REGION, NETWORK_NAME et PROXY_ONLY_SUBNET_NAME. Le port 8888 spécifié est le port de tunnel externe mappé à la configuration du proxy dans 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

Dans Cloud Shell, importez la passerelle :

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

5. Rattachement de réseau Private Service Connect

Les rattachements de réseau sont des ressources régionales qui représentent le côté utilisateur d'une interface Private Service Connect. Vous associez un seul sous-réseau à un rattachement de réseau, et le producteur attribue des adresses IP à l'interface Private Service Connect à partir de ce sous-réseau. Le sous-réseau doit se trouver dans la même région que le rattachement de réseau. Un rattachement réseau doit se trouver dans la même région que le service producteur.

Créer le rattachement de réseau

Dans Cloud Shell, créez le rattachement de réseau.

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

Lister les rattachements de réseau

Dans Cloud Shell, listez l'association réseau.

gcloud compute network-attachments list

Décrire les rattachements de réseau

Dans Cloud Shell, décrivez le rattachement de réseau.

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

Notez le nom du rattachement de réseau PSC, psc-network-attachment, qui sera utilisé par le producteur lors de la création de l'interface Private Service Connect.

Pour afficher l'URL d'association au réseau PSC dans la console Cloud, accédez à :

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

15f80b46c3a0332d.png

6. Zone DNS privée

Vous allez créer une zone Cloud DNS pour demo.com et la remplir avec un enregistrement A qui pointe vers les adresses IP de vos PWA. L'appairage DNS sera ensuite déployé dans Agent Engine, ce qui permettra d'accéder aux enregistrements DNS du consommateur.

Dans Cloud Shell, exécutez la commande suivante pour créer un nom 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"

Obtenez et stockez les adresses IP du SWP utilisées pour l'enregistrement A du DNS.

Dans Cloud Shell, exécutez une commande "describe" sur le SWP my-swp-instance :

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

Dans Cloud Shell, créez l'ensemble d'enregistrements pour SWP, swp.demo.com, et assurez-vous de mettre à jour l'adresse IP en fonction de la sortie de votre environnement.

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

Configuration du pare-feu

Créer une règle de pare-feu cloud pour autoriser l'accès depuis l'interface PSC

Dans la section suivante, créez une règle de pare-feu qui autorise le trafic provenant de l'accès au rattachement de réseau PSC vers le sous-réseau SWP dans le VPC consommateur. Pour renforcer la sécurité, vous pouvez spécifier l'adresse IP SWP comme seule destination.

Dans Cloud Shell, créez la règle de pare-feu de sortie autorisant l'accès de l'association de réseau à 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

Dans Cloud Shell, créez la règle de pare-feu de sortie qui refuse tout le trafic provenant de l'association de réseau :

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. Créez une stratégie de pare-feu pour le réseau VPC afin d'assurer la protection contre les renseignements sur les menaces :

Dans la section suivante, créez une stratégie de pare-feu qui vous permet d'exploiter les listes de menaces gérées de Google pour bloquer les sites malveillants connus avant que le trafic ne soit reçu par le SWP.

Dans Cloud Shell, créez la stratégie de pare-feu globale :

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

Dans Cloud Shell, associez la stratégie à votre VPC :

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

Dans Cloud Shell, ajoutez les règles de renseignements sur les menaces :

Ces règles bloquent le trafic vers les acteurs malveillants connus avant d'initier le trafic à partir de l'agent. Dans cet exemple, nous avons ajouté des règles pour bloquer les nœuds de sortie Tor (trafic sortant), les adresses IP malveillantes connues (trafic sortant), les proxys anonymes connus(trafic sortant) et les mineurs de cryptomonnaie pour empêcher l'utilisation non autorisée des ressources (trafic sortant).

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. Créer un notebook Jupyter

La section suivante vous explique comment créer un notebook Jupyter. Ce notebook sera utilisé pour déployer Agent Engine en ciblant un proxy explicite pour la sortie Internet.

Créer un compte de service géré par l'utilisateur

Dans la section suivante, vous allez créer un compte de service qui sera associé à l'instance Vertex AI Workbench utilisée dans le tutoriel.

Dans le tutoriel, les rôles suivants seront appliqués au compte de service :

Dans Cloud Shell, créez le compte de service.

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

Dans Cloud Shell, mettez à jour le compte de service avec le rôle "Administrateur Storage".

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

Dans Cloud Shell, mettez à jour le compte de service avec le rôle Utilisateur Vertex AI.

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

Dans Cloud Shell, mettez à jour le compte de service avec le rôle Administrateur Artifact Registry.

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

Dans Cloud Shell, autorisez le compte de service du notebook à utiliser le compte de service Compute Engine par défaut.

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. Créer une instance Vertex AI Workbench

Dans la section suivante, créez une instance Vertex AI Workbench qui intègre le compte de service notebook-sa créé précédemment.

Dans Cloud Shell, créez l'instance de client privé.

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     

Ajoutez une autre règle au proxy Web sécurisé existant pour transférer le trafic depuis cette instance de notebook :

Dans Cloud Shell, créez le fichier rule-notebook.yaml à l'aide d'un éditeur de texte, en veillant à mettre à jour le fichier YAML avec votre ID de projet.

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

Dans Cloud Shell, générez la règle de stratégie de sécurité :

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. Mise à jour de l'agent de service Vertex AI

Vertex AI agit en votre nom pour effectuer des opérations telles que l'obtention d'une adresse IP à partir du sous-réseau de rattachement de réseau PSC utilisé pour créer l'interface PSC. Pour ce faire, Vertex AI utilise un agent de service (listé ci-dessous) qui nécessite l'autorisation Administrateur réseau :

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

Dans Cloud Shell, obtenez le numéro de votre projet.

gcloud projects describe $projectid | grep projectNumber

Dans Cloud Shell, définissez le numéro de votre projet.

projectnumber=YOUR-PROJECT-NUMBER

Dans Cloud Shell, créez un compte de service pour AI Platform. Ignorez cette étape si vous disposez déjà d'un compte de service dans votre projet.

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

Dans Cloud Shell, mettez à jour le compte de l'agent de service avec le rôle compute.networkAdmin.

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

Dans Cloud Shell, mettez à jour le compte de l'agent de service avec le rôle dns.peer.

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

Mise à jour du compte de service par défaut

Accordez à votre compte de service par défaut l'accès à Vertex AI. Notez que la propagation de la modification d'accès peut prendre un certain temps.

Dans Cloud Shell, mettez à jour le compte de service par défaut avec le rôle aiplatform.user.

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

11. Déployer Agent Engine

Remarque : Nous utiliserons la console GCP et le notebook JupyterLab pour effectuer les tâches de cette section.

Dans la section suivante, vous allez créer un notebook qui effectue les tâches suivantes :

  • Utilise l'API Frankfurter (https://api.frankfurter.app/) pour obtenir des données sur les taux de change.
  • Fait référence à un proxy explicite (proxy_server) ciblant le SWP dans le VPC des consommateurs à l'aide du nom de domaine complet swp.demo.com
  • Définissez dnsPeeringConfigs "domain": "demo.com."

Exécutez le job d'entraînement dans l'instance Vertex AI Workbench.

  • Dans la console Google Cloud, accédez à Vertex AI → Workbench.
  • À côté du nom de votre instance Vertex AI Workbench (workbench-tutorial), cliquez sur "Ouvrir JupyterLab". Votre instance Vertex AI Workbench ouvre JupyterLab.
  • Sélectionner File > New > Notebook
  • Sélectionner Kernel > Python 3

Installez les bibliothèques Python nécessaires : installez les bibliothèques requises pour Agent Engine, y compris pyyaml, google-cloud-aiplatform, cloudpickle, google-cloud-api-keys et langchain-google-vertexai.

Dans votre notebook JupyterLab, créez une cellule et exécutez la commande suivante en spécifiant l'adresse IP du SWP.

7b827a6a38bb5afc.png

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

Définissez les variables suivantes en fonction de votre environnement dans l'extrait de code suivant :

  • PROJECT_ID
  • BUCKET_NAME
  • AGENT_NAME

Dans cet atelier, vous allez utiliser les variables BUCKET_NAME et AGENT_NAME pour initialiser et configurer votre bucket de stockage disponible dans le monde entier.

Dans la section suivante, le PROXY_SERVER est défini, par exemple swp.demo.com, qui nécessite un peering DNS pour la résolution de noms. Dans la configuration, AGENT_PEER_DOMAIN est déployé en tant que demo.com, ce qui correspond à la zone DNS privée créée lors d'une étape précédente dans AGENT_PEER_NETWORK, consumer-vpc.

Dans votre notebook JupyterLab, créez une cellule et exécutez la commande suivante :

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

Dans votre notebook JupyterLab, créez une cellule et exécutez la commande suivante.

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

Dans votre notebook JupyterLab, créez une cellule et exécutez la commande suivante pour créer la variable de proxy correspondant au nom de domaine complet et au port des points de terminaison de service.

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

La cellule de code suivante montre la configuration explicite du proxy pour qu'Agent Engine accède au point de terminaison Internet api.frankfurter.app en spécifiant le SWP, à l'aide de PROXY_SERVER_TO_USE qui correspond à 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}")

Dans votre notebook JupyterLab, créez une cellule et exécutez le code suivant qui définit l'implémentation de l'outil pour l'API de ciblage des taux de change api.frankfurther.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],
)

Dans votre notebook JupyterLab, créez une cellule et exécutez la commande suivante.

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

Dans votre notebook JupyterLab, créez une cellule et exécutez la commande suivante qui appelle la configuration de l'interface PSC utilisée par Agent Engine, en plus du peering 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.")

Dans votre notebook JupyterLab, créez une cellule et exécutez la commande suivante.

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

Dans votre notebook JupyterLab, créez une cellule et exécutez la commande suivante.

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

Dans votre notebook JupyterLab, créez une cellule et exécutez la commande suivante pour créer l'agent.

!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

Un ID de moteur de raisonnement sera généré lors de l'exécution de la cellule. Pour l'étape suivante, vous aurez besoin de l'ID généré, qui est 3235268984265768960 dans cet exemple.

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

Dans votre notebook JupyterLab, créez une cellule et exécutez le code suivant, en veillant à remplacer les valeurs par votre numéro de projet et l'ID de raisonnement Agent Engine de la sortie précédente :

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

Dans votre notebook JupyterLab, créez une cellule et exécutez la commande suivante.

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)

Exemple d'exécution réussie qui valide la connectivité au point de terminaison public api.frankfurther.app via le SWP en fonction du taux de change USD/INR.

f9f925983ab5cc9d.png

12. Validation de l'interface PSC

Vous pouvez également afficher les adresses IP de l'attachement réseau utilisées par Agent Engine en accédant à :

Services réseau → Private Service Connect → Rattachement de réseau → psc-network-attachment

Sélectionnez le projet locataire (nom de projet se terminant par "-tp").

c9c412334a7f5ad9.png

Le champ en surbrillance indique l'adresse IP utilisée par Agent Engine à partir du rattachement de réseau PSC.

e94c6c03fb51f7fe.png

13. SWP - Cloud Logging Validation

Pour valider la sortie Internet effectuée par le SWP, vous pouvez consulter Cloud Logging en accédant à :

Surveillance → Explorateur de journaux

Insérez la requête : resource.type=" networkservices.googleapis.com/Gateway", puis cliquez sur "Exécuter la requête". Vous trouverez ci-dessous un exemple qui confirme le point de terminaison de destination, api.frankfurter.app.

f53831ef8ec663db.png

fc154a5b22da2a87.png

L'exemple Cloud Logging suivant valide les éléments suivants :

Destination_range : adresse IP de l'interface PSC Agent Engine

Source_range : sous-réseau proxy uniquement Dest_ip : adresse IP du proxy Web sécurisé

Veillez à modifier le project_id pour la requête 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. Effectuer un nettoyage

Dans votre notebook JupyterLab, créez une cellule et exécutez la commande suivante pour déclencher la suppression du déploiement Agent Engine.

Assurez-vous de mettre à jour "project number" et "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)

Dans Cloud Shell, supprimez les composants du tutoriel.

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. Félicitations

Félicitations, vous avez configuré et validé Agent Engine déployé avec une interface Private Service Connect, avec une sortie Internet effectuée via un proxy explicite.

Vous avez créé l'infrastructure consommateur et ajouté un rattachement de réseau qui a permis au producteur de créer une VM multi-NIC pour faire le pont entre les communications consommateur et producteur. Vous avez appris à créer un proxy explicite et un appairage DNS qui permettaient la connectivité Internet.

Cosmopup pense que les tutoriels sont géniaux !

e6d3675ca7c6911f.jpeg

Et ensuite ?

Lectures et vidéos complémentaires

Documents de référence