Agent Engine(ADK)PSC SWP の統合

1. はじめに

Private Service Connect インターフェースは、プロデューサーの Virtual Private Cloud(VPC)ネットワークがコンシューマーの VPC ネットワーク内のさまざまな宛先への接続を開始できるようにするためのリソースです。プロデューサー ネットワークとコンシューマー ネットワークは、異なるプロジェクトや組織に属していてもかまわない。

ネットワーク アタッチメントが Private Service Connect インターフェースからの接続を受け入れると、Google Cloud はネットワーク アタッチメントで指定されたコンシューマー サブネットからインターフェースに IP アドレスを割り振ります。コンシューマ ネットワークとプロデューサー ネットワークが接続され、内部 IP アドレスを使用して通信が可能になります。

ネットワーク アタッチメントと Private Service Connect インターフェース間の接続は、Private Service Connect のエンドポイントとサービス アタッチメント間の接続に似ていますが、重要な違いが 2 つあります。

  • ネットワーク アタッチメントは、プロデューサー ネットワークからコンシューマー ネットワークへの接続(マネージド サービスの下り、外向き)を開始できるようにします。エンドポイントは、コンシューマー ネットワークからプロデューサー ネットワークへの接続(マネージド サービスの上り、内向き)を開始できるようにします。
  • Private Service Connect インターフェースの接続は推移的です。これは、プロデューサー ネットワークは、コンシューマー ネットワークに接続されている他のネットワークと通信できることを意味します。

Vertex AI PSC インターフェースの到達可能性に関する考慮事項

  • PSC インターフェースは、VPC ネットワークで学習した VPC またはオンプレミス ベースの宛先にトラフィックをルーティングできます。
  • Agent Engine で使用されるネットワーク アタッチメントから VPC ネットワークへの到達可能性の範囲を制限するには、下り(外向き)ファイアウォール ルールの実装がベスト プラクティスです。
  • Agent Engine のネットワーク アタッチメント サブネットから送信されるネットワーク下り(外向き)トラフィックの範囲を制限するには、VPC 下り(外向き)ファイアウォール ルールをデプロイする必要があります。このルールは、Agent Engine から SWP へのトラフィックを明示的に許可し、他のすべての送信トラフィックを拒否します。

Vertex AI PSC-Interface VPC-SC に関する考慮事項

  • VPC Service Controls が有効になっている場合でも、Agent Engine PSC インターフェースが機能するには、お客様の VPC 内でインターネット下り(外向き)接続を提供する必要があります。

安全なウェブプロキシ

Secure Web Proxy は、アウトバウンド トラフィック(HTTP/HTTPS)に対するきめ細かい制御とセキュリティを提供するマネージド クラウド ネイティブ サービスです。これは中央ゲートウェイとして機能し、PSC インターフェースでデプロイされた Agent Engine から開始された接続に対して、VM、GKE、インターネット、マルチクラウド環境などの VPC リソースへのセキュリティ ポリシーを適用できます。

解決できること

  • データの引き出しを防止する: 不正なアップロードや悪意のあるサイトとの通信をブロックします。
  • コンプライアンスを適用する: アウトバウンド トラフィックが組織のセキュリティ ポリシーとデータ処理ポリシーに準拠していることを確認します。
  • 運用オーバーヘッドの削減: フルマネージド サービスである Secure Web Proxy を使用すると、独自のプロキシ VM のデプロイ、スケーリング、メンテナンスが不要になります。
  • 詳細な可視性を提供: Transport Layer Security(TLS)で暗号化されたトラフィックの検査を有効にして、隠れた脅威を検出します。

詳しくは、次のリソースをご覧ください。

エージェントをデプロイする | Vertex AI の生成 AI | Google Cloud

Vertex AI リソースの Private Service Connect インターフェースを設定する | Google Cloud

作成するアプリの概要

このチュートリアルでは、Private Service Connect(PSC)インターフェースでデプロイされ、SWP と統合された包括的な Agent Engine を構築し、ADK ライブラリを使用して次の操作を行います。

  • Agent Engine に DNS ピアリングをデプロイして、プロキシ構成で使用される SWP の完全修飾ドメイン名を解決します。
  • RFC1918 アドレスを使用してコンシューマーの VPC にデプロイされたセキュア ウェブ プロキシを介して、パブリック サイト(https://api.frankfurter.app/)への接続を許可します。
  • ネットワーク アタッチメント サブネットから SWP へのトラフィックを許可し、それ以外はすべて拒否します。

図 1

565e9eb07ef18f44.png

学習内容

  • ネットワーク アタッチメントを作成する方法
  • プロデューサーがネットワーク アタッチメントを使用して PSC インターフェースを作成する方法
  • DNS ピアリングを使用してプロデューサーからコンシューマーへの通信を確立する方法
  • インターネット下り(外向き)用の SWP をデプロイして使用する方法
  • エージェント エンジンのネットワーク到達可能性を減らす外向きファイアウォール ルールを定義する方法

必要なもの

Google Cloud プロジェクト

IAM 権限

2. 始める前に

チュートリアルをサポートするようにプロジェクトを更新する

このチュートリアルでは、$variables を使用して、Cloud Shell での gcloud 構成の実装を支援します。

Cloud Shell で、次の操作を行います。

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

API の有効化

Cloud Shell で、次の操作を行います。

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"

API が正常に有効になっていることを確認する

gcloud services list --enabled

3. コンシューマーの設定

コンシューマー VPC を作成する

この VPC はお客様のプロジェクトに存在します。この VPC に次のリソースが作成されます。

  • コンシューマー サブネット
  • ネットワーク アタッチメント サブネット
  • プロキシ専用サブネット
  • ファイアウォール ルール
  • Cloud DNS

Cloud Shell で、次の操作を行います。

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

コンシューマー サブネットを作成する

Cloud Shell 内で、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

Private Service Connect ネットワーク アタッチメント サブネットを作成する

Cloud Shell 内で、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

リージョン プロキシ サブネットを作成する

Cloud Shell 内で、Secure Web Proxy やリージョン内部/外部アプリケーション ロードバランサなどの Envoy ベースのプロダクトに必要なプロキシ専用サブネットを作成します。–purpose フラグは 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

ノートブック サブネットを作成する

Cloud Shell 内で、ノートブック インスタンスのサブネットを作成します。

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. Secure Web Proxy を作成する

Secure Web Proxy の明示モード(または明示プロキシ ルーティング モード)は、クライアント ワークロードが SWP の内部 IP アドレスまたは完全修飾ドメイン名とポートを転送プロキシとして使用するように明示的に構成する必要があるデプロイ方法です。

このポリシーには、セッション一致 host() == 'api.frankfurter.app' とアプリケーション一致 request.method == 'GET' に基づいて、セキュア ウェブプロキシを通過するトラフィックを制御するルールが含まれます。

以下の手順では、YOUR-PROJECT-ID をプロジェクト ID に変更してください。

Cloud Shell 内で、policy.yaml ファイルを作成します。

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

Cloud Shell 内で、ポリシーをインポートします。

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

Secure Web Proxy ルールを作成する

ポリシー内でルールを定義して、許可または拒否するトラフィックを指定します。ルールは優先度に基づいて評価されます。

Cloud Shell 内で、エージェント エンジンで使用されるインターネット エンドポイント api.frankfurter.app へのアクセスを許可する rule.yaml ファイルを作成します。

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

Cloud Shell で、セキュリティ ポリシー ルールを生成します。

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

Secure Web Proxy ルールを作成する

明示的ルーティング モードでデプロイされる SWP インスタンスは、ゲートウェイ YAML ファイルで定義されているように、ADK プロキシ構成内で SWP の IP アドレスまたは FQDN を指定するために Agent Engine が必要となるように作成する必要があります。この構成では、インスタンスが対応するポリシー、ネットワーク、サブネットにもリンクされます。

Cloud Shell 内で、SWP のデプロイに使用する gateway.yaml ファイルを作成します。

次の変数(PROJECT_ID、REGION、NETWORK_NAME、PROXY_ONLY_SUBNET_NAME)を環境の詳細で更新したら、必ず YAML ファイルを保存してください。指定されたポート 8888 は、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

Cloud Shell 内で、ゲートウェイをインポートします。

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

5. Private Service Connect ネットワーク アタッチメント

ネットワーク アタッチメントは、Private Service Connect インターフェースのコンシューマー側を表すリージョン リソースです。単一のサブネットをネットワーク アタッチメントに関連付けると、プロデューサーはそのサブネットから Private Service Connect インターフェースに IP を割り当てます。サブネットは、ネットワーク アタッチメントと同じリージョンに存在する必要があります。ネットワーク アタッチメントは、プロデューサー サービスと同じリージョンに存在する必要があります。

ネットワーク アタッチメントを作成する

Cloud Shell 内で、ネットワーク アタッチメントを作成します。

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

ネットワーク アタッチメントを一覧表示する

Cloud Shell 内で、ネットワーク アタッチメントを一覧表示します。

gcloud compute network-attachments list

ネットワーク アタッチメントの説明を取得する

Cloud Shell 内で、ネットワーク アタッチメントの説明を取得します。

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

Private Service Connect インターフェースの作成時にプロデューサーが使用する PSC ネットワーク アタッチメント名 psc-network-attachment をメモします。

Cloud Console で PSC ネットワーク アタッチメントの URL を表示するには、次の場所に移動します。

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

15f80b46c3a0332d.png

6. 限定公開 DNS ゾーン

demo.com の Cloud DNS ゾーンを作成し、SWP の IP アドレスを指す A レコードを設定します。その後、DNS ピアリングが Agent Engine にデプロイされ、コンシューマーの DNS レコードにアクセスできるようになります。

Cloud Shell で、次の操作を行って 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"

DNS A レコードに使用される SWP の IP アドレスを取得して保存します。

Cloud Shell 内で、swp(my-swp-instance)に対して説明を実行します。

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

Cloud Shell 内で、SWP(swp.demo.com)のレコードセットを作成します。環境の出力に基づいて IP アドレスを更新してください。

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

ファイアウォールの構成

PSC インターフェースからのアクセスを許可する Cloud Firewall ルールを作成する

次のセクションでは、PSC ネットワーク アタッチメントからのトラフィックがコンシューマー VPC の SWP サブネットにアクセスできるようにするファイアウォール ルールを作成します。セキュリティを強化するために、SWP IP アドレスを宛先として指定できます。

Cloud Shell で、ネットワーク アタッチメントから 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

Cloud Shell で、ネットワーク アタッチメントからのすべてのトラフィックを拒否する下り(外向き)ファイアウォール ルールを作成します。

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. VPC ネットワークにファイアウォール ポリシーを作成して、脅威インテリジェンスを確保します。

次のセクションでは、Google のマネージド脅威リストを活用して、SWP がトラフィックを受信する前に既知の悪意のあるサイトをブロックできるファイアウォール ポリシーを作成します。

Cloud Shell で、グローバル ファイアウォール ポリシーを作成します。

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

Cloud Shell で、ポリシーを VPC に関連付けます。

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

Cloud Shell で、脅威インテリジェンス ルールを追加します。

これらのルールは、エージェントからのトラフィックを開始する前に、既知の悪意のある行為者へのトラフィックをドロップします。この例では、不正なリソースの使用を防ぐために、Tor 出口ノード(下り(外向き))のブロック、既知の悪意のある IP(下り(外向き))のブロック、既知の匿名プロキシ(下り(外向き))のブロック、暗号通貨マイナーのブロック(下り(外向き))にルールを追加しました。

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. Jupyter ノートブックを作成する

次のセクションでは、Jupyter Notebook の作成について説明します。このノートブックは、インターネット下り(外向き)の明示的なプロキシをターゲットとする Agent Engine のデプロイに使用されます。

ユーザー管理のサービス アカウントを作成する

次のセクションでは、チュートリアルで使用する Vertex AI Workbench インスタンスに関連付けるサービス アカウントを作成します。

このチュートリアルでは、サービス アカウントに次のロールが適用されます。

Cloud Shell 内で、サービス アカウントを作成します。

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

Cloud Shell 内で、ロール「ストレージ管理者」を使用してサービス アカウントを更新します。

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

Cloud Shell 内で、Vertex AI ユーザーロールを使用してサービス アカウントを更新します。

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

Cloud Shell 内で、Artifact Registry 管理者のロールを使用してサービス アカウントを更新します。

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

Cloud Shell 内で、ノートブック サービス アカウントが 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. Vertex AI Workbench インスタンスを作成する

次のセクションでは、前に作成したサービス アカウント notebook-sa を組み込んだ Vertex AI Workbench インスタンスを作成します。

Cloud Shell 内で 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     

既存の Secure Web Proxy に別のルールを追加して、このノートブック インスタンスからのトラフィックを転送します。

Cloud Shell で、テキスト エディタを使用して rule-notebook.yaml ファイルを作成します。YAML をプロジェクト ID で更新してください。

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

Cloud Shell で、セキュリティ ポリシー ルールを生成します。

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. Vertex AI サービス エージェントの更新

Vertex AI は、PSC インターフェースの作成に使用される PSC ネットワーク アタッチメント サブネットから IP アドレスを取得するなどのオペレーションをユーザーに代わって実行します。これを行うため、Vertex AI は ネットワーク管理者権限を必要とするサービス エージェント(下記)を使用します。

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

Cloud Shell で、プロジェクト番号を取得します。

gcloud projects describe $projectid | grep projectNumber

Cloud Shell で、プロジェクト番号を設定します。

projectnumber=YOUR-PROJECT-NUMBER

Cloud Shell 内で、AI Platform のサービス アカウントを作成します。プロジェクトに既存のサービス アカウントがある場合は、この手順をスキップします。

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

Cloud Shell 内で、ロール compute.networkAdmin を使用してサービス エージェント アカウントを更新します。

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

Cloud Shell 内で、サービス エージェント アカウントをロール dns.peer で更新します。

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

デフォルトのサービス アカウントの更新

Vertex AI へのアクセス権をデフォルトのサービス アカウントに付与します。アクセス権の変更が反映されるまでに時間がかかることがあります。

Cloud Shell 内で、デフォルトのサービス アカウントを aiplatform.user ロールで更新します。

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

11. Agent Engine をデプロイする

注: このセクションのタスクを完了するには、GCP コンソールと JupyterLab ノートブックを使用します。

次のセクションでは、次のタスクを実行するノートブックを作成します。

  • Frankfurter API(https://api.frankfurter.app/)を使用して為替レート データを取得します
  • FQDN swp.demo.com を使用して、コンシューマー VPC の SWP をターゲットとする明示的なプロキシ(proxy_server)を参照します。
  • dnsPeeringConfigs の "domain": "demo.com." を定義します。

Vertex AI Workbench インスタンスでトレーニング ジョブを実行します。

  • Google Cloud コンソールで、Vertex AI → Workbench に移動します。
  • Vertex AI Workbench インスタンス名(workbench-tutorial)の横にある [JupyterLab を開く] をクリックします。JupyterLab で Vertex AI Workbench インスタンスが開きます。
  • File > New > Notebook を選択
  • Kernel > Python 3 を選択

必要な Python ライブラリをインストールする: pyyaml、google-cloud-aiplatform、cloudpickle、google-cloud-api-keys、langchain-google-vertexai など、Agent Engine に必要なライブラリをインストールします。

JupyterLab ノートブックで、新しいセルを作成し、SWP の IP アドレスを指定して次のコマンドを実行します。

7b827a6a38bb5afc.png

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

次のコード スニペットで、環境に基づいて次の変数を定義します。

  • PROJECT_ID
  • BUCKET_NAME
  • AGENT_NAME

このラボでは、変数 BUCKET_NAME と AGENT_NAME を使用して、グローバルに利用可能なストレージ バケットを初期化して構成します。

次のセクションでは、名前解決に DNS ピアリングが必要な PROXY_SERVER(swp.demo.com など)を定義します。この構成では、AGENT_PEER_DOMAIN は demo.com としてデプロイされます。これは、AGENT_PEER_NETWORK(consumer-vpc)内の前の手順で作成した限定公開 DNS ゾーンに対応しています。

JupyterLab ノートブックで、新しいセルを作成して次のコマンドを実行します。

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

JupyterLab ノートブックで、新しいセルを作成して次のコマンドを実行します。

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

JupyterLab ノートブックで新しいセルを作成し、次のコマンドを実行して、SWP の FQDN とポートに対応するプロキシ変数を作成します。

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

次のコードセルは、os.environ["PROXY_SERVER_URL"]. にマッピングされる PROXY_SERVER_TO_USE を使用して SWP を指定し、インターネット エンドポイント api.frankfurter.app にアクセスするための Agent Engine の明示的なプロキシ構成を示しています。

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

JupyterLab ノートブックで、新しいセルを作成し、次のコードを実行して、通貨換算のターゲット設定 API(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],
)

JupyterLab ノートブックで、新しいセルを作成して次のコマンドを実行します。

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

JupyterLab ノートブックで、新しいセルを作成し、DNS ピアリングに加えて Agent Engine で使用される psc インターフェース構成を呼び出す次のコマンドを実行します。

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

JupyterLab ノートブックで、新しいセルを作成して次のコマンドを実行します。

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

JupyterLab ノートブックで、新しいセルを作成して次のコマンドを実行します。

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

JupyterLab ノートブックで、新しいセルを作成し、次のエージェントを作成するコードを実行します。

!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

セルを実行すると、推論エンジン ID が生成されます。次のステップでは、生成された ID(この例では 3235268984265768960)が必要になります。

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

JupyterLab ノートブックで新しいセルを作成し、次のコードを実行します。必ず、前の出力のプロジェクト番号と Agent Engine 推論 ID で更新してください。

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

JupyterLab ノートブックで、新しいセルを作成して次のコマンドを実行します。

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)

USD から INR への換算レートに基づいて SWP を介してパブリック エンドポイント api.frankfurther.app への接続を検証する実行が成功した例。

f9f925983ab5cc9d.png

12. PSC インターフェースの検証

Agent Engine で使用されているネットワーク アタッチメントの IP を表示するには、次の場所に移動します。

[ネットワーク サービス] → [Private Service Connect] → [ネットワーク アタッチメント] → [psc-network-attachment]

テナント プロジェクト(-tp で終わるプロジェクト名)を選択します。

c9c412334a7f5ad9.png

ハイライト表示されたフィールドは、PSC ネットワーク アタッチメントから Agent Engine で使用される IP アドレスを示します。

e94c6c03fb51f7fe.png

13. SWP - Cloud Logging の検証

Cloud Logging を表示して、SWP によって実行されたインターネット下り(外向き)を検証できます。次の場所に移動します。

[モニタリング] → [ログ エクスプローラ]

クエリ resource.type=" networkservices.googleapis.com/Gateway" を挿入し、[クエリを実行] をクリックします。次に、宛先エンドポイント api.frankfurter.app を確認する例を示します。

f53831ef8ec663db.png

fc154a5b22da2a87.png

次の Cloud Logging の例では、次のことを検証します。

Destination_range: Agent Engine PSC インターフェースの IP アドレス

Source_range: プロキシ専用サブネット Dest_ip: Secure Web Proxy の IP アドレス

必ず、クラウド ロギング クエリの project_id を変更してください。

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. クリーンアップ

JupyterLab ノートブックで、新しいセルを作成し、次のコマンドを実行して Agent Engine デプロイの削除をトリガーします。

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

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. 完了

お疲れさまでした。Private Service Connect インターフェースでデプロイされた Agent Engine を構成し、明示的なプロキシを介してインターネット Egress を実行して検証できました。

コンシューマー インフラストラクチャを作成し、プロデューサーがマルチ NIC VM を作成してコンシューマーとプロデューサーの通信をブリッジできるようにするネットワーク アタッチメントを追加しました。インターネット接続を許可する明示的なプロキシと DNS ピアリングを作成する方法を学習しました。

Cosmopup はチュートリアルが大好きです。

e6d3675ca7c6911f.jpeg

次のステップ

参考資料と動画

リファレンス ドキュメント