1. 소개
Private Service Connect 인터페이스는 프로듀서 가상 프라이빗 클라우드 (VPC) 네트워크가 소비자 VPC 네트워크의 다양한 대상에 연결을 시작할 수 있게 해주는 리소스입니다. 프로듀서 및 소비자 네트워크는 다른 프로젝트 및 조직에 포함될 수 있습니다.
네트워크 연결이 Private Service Connect 인터페이스의 연결을 수락하면 Google Cloud는 네트워크 연결에 지정된 소비자 서브넷의 IP 주소를 인터페이스에 할당합니다. 소비자 및 프로듀서 네트워크는 내부 IP 주소를 사용하여 연결되고 통신할 수 있습니다.
네트워크 연결과 Private Service Connect 인터페이스 간의 연결은 Private Service Connect 엔드포인트와 서비스 연결 간의 연결과 유사하지만 여기에는 두 가지 주요 차이점이 있습니다.
- 네트워크 연결을 사용하면 프로듀서 네트워크가 소비자 네트워크 (관리형 서비스 이그레스)로의 연결을 시작할 수 있고, 엔드포인트를 사용하면 소비자 네트워크가 프로듀서 네트워크 (관리형 서비스 인그레스)에 대한 연결을 시작할 수 있습니다.
- Private Service Connect 인터페이스 연결은 전환됩니다. 즉, 프로듀서 네트워크는 소비자 네트워크에 연결된 다른 네트워크와 통신할 수 있습니다.
Vertex AI PSC 인터페이스 도달 가능성 고려사항
- PSC 인터페이스는 VPC 네트워크에서 학습한 VPC 또는 온프레미스 기반 대상으로 트래픽을 라우팅할 수 있습니다.
- Agent Engine에서 사용하는 네트워크 연결에서 VPC 네트워크로의 도달 범위를 제한하려면 이그레스 방화벽 규칙을 구현하는 것이 좋습니다.
- 에이전트 엔진의 네트워크 연결 서브넷에서 시작되는 네트워크 이그레스 트래픽의 범위를 제한하려면 VPC 이그레스 방화벽 규칙을 배포해야 합니다. 이 규칙은 에이전트 엔진에서 SWP로의 트래픽을 명시적으로 허용하면서 다른 모든 아웃바운드 트래픽을 거부합니다.
Vertex AI PSC-Interface VPC-SC 고려사항
- VPC 서비스 제어가 사용 설정된 경우에도 에이전트 엔진 PSC 인터페이스가 작동하려면 고객 VPC 내에서 인터넷 이그레스 연결을 제공해야 합니다.
보안 웹 프록시
보안 웹 프록시 는 아웃바운드 트래픽 (HTTP/HTTPS)에 대한 세부적인 제어 및 보안을 제공하는 관리형 클라우드 네이티브 서비스입니다. 중앙 게이트웨이 역할을 하며 PSC 인터페이스로 배포된 에이전트 엔진에서 VM, GKE, 인터넷, 멀티 클라우드 환경과 같은 VPC 리소스로 시작된 연결에 보안 정책을 적용할 수 있습니다.
해결되는 문제
- 데이터 유출 방지: 승인되지 않은 업로드 또는 악성 사이트와의 통신을 차단합니다.
- 규정 준수 시행: 아웃바운드 트래픽이 조직의 보안 및 데이터 처리 정책을 준수하도록 합니다.
- 운영 오버헤드 감소: 완전 관리형 서비스인 보안 웹 프록시를 사용하면 자체 프록시 VM을 배포, 확장 또는 유지관리할 필요가 없습니다.
- 심층적인 가시성 제공: 전송 계층 보안 (TLS)으로 암호화된 트래픽을 검사하여 숨겨진 위협을 감지할 수 있습니다.
자세한 내용은 다음 리소스를 참고하세요.
에이전트 배포 | Vertex AI의 생성형 AI | Google Cloud
Vertex AI 리소스에 대한 Private Service Connect 인터페이스 설정 | Google Cloud
빌드할 항목
이 튜토리얼에서는 ADK 라이브러리를 사용하여 다음을 실행하기 위해 SWP와 통합된 Private Service Connect (PSC) 인터페이스로 배포된 포괄적인 에이전트 엔진을 빌드합니다.
- 프록시 구성에 사용되는 SWP 정규화된 도메인 이름을 확인하기 위해 에이전트 엔진에 DNS 피어링을 배포합니다.
- RFC1918 주소를 사용하여 소비자의 VPC에 배포된 보안 웹 프록시를 통해 공개 사이트 (https://api.frankfurter.app/)에 연결할 수 있습니다.
- 네트워크 연결 서브넷에서 SWP로의 트래픽은 허용하고 그 외 모든 트래픽은 거부합니다.
그림 1

학습할 내용
- 네트워크 연결을 만드는 방법
- 프로듀서가 네트워크 연결을 사용하여 PSC 인터페이스를 만드는 방법
- DNS 피어링을 사용하여 공급자에서 소비자로 통신을 설정하는 방법
- 인터넷 이그레스를 위해 SWP를 배포하고 사용하는 방법
- 에이전트 엔진 네트워크 연결을 줄이기 위해 이그레스 방화벽 규칙을 정의하는 방법
필요한 항목
Google Cloud 프로젝트
IAM 권한
- Compute 네트워크 관리자 (roles/compute.networkAdmin)
- Compute 인스턴스 관리자 (roles/compute.instanceAdmin)
- Compute 보안 관리자 (roles/compute.securityAdmin)
- DNS 관리자 (roles/dns.admin)
- IAP 보안 터널 사용자 (roles/iap.tunnelResourceAccessor)
- 로깅 관리자 (roles/logging.admin)
- Notebooks 관리자 (roles/notebooks.admin)
- 프로젝트 IAM 관리자 (roles/resourcemanager.projectIamAdmin)
- 서비스 계정 관리자 (roles/iam.serviceAccountAdmin)
- 서비스 사용량 관리자 (roles/serviceusage.serviceUsageAdmin)
2. 시작하기 전에
튜토리얼을 지원하도록 프로젝트 업데이트
이 튜토리얼에서는 Cloud Shell에서 gcloud 구성 구현을 지원하기 위해 $variables를 사용합니다.
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에서 보안 웹 프록시, 리전 내부/외부 애플리케이션 부하 분산기와 같은 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의 명시적 모드 (또는 명시적 프록시 라우팅 모드)는 클라이언트 워크로드가 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
보안 웹 프록시 규칙 만들기
정책 내에서 규칙을 정의하여 허용 또는 거부되는 트래픽을 지정합니다. 규칙은 우선순위에 따라 평가됩니다.
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
보안 웹 프록시 규칙 만들기
명시적 라우팅 모드로 배포된 SWP 인스턴스는 에이전트 엔진이 게이트웨이 YAML 파일에 정의된 대로 ADK 프록시 구성 내에서 SWP의 IP 주소 또는 FQDN을 지정해야 하도록 만들어야 합니다. 이 구성은 인스턴스를 해당 정책, 네트워크, 서브넷에 연결하기도 합니다.
Cloud Shell 내에서 SWP를 배포하는 데 사용되는 gateway.yaml 파일을 만듭니다.
PROJECT_ID, REGION, NETWORK_NAME, PROXY_ONLY_SUBNET_NAME 변수를 환경 세부정보로 업데이트한 후 YAML 파일을 저장해야 합니다. 지정된 포트 8888은 에이전트 엔진 내의 프록시 구성에 매핑된 외부 터널 포트입니다.
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 콘솔에서 PSC 네트워크 연결 URL을 보려면 다음으로 이동하세요.
Network Services → Private Service Connect → Network Attachment → psc-network-attachment

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에 대해 describe를 실행합니다.
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 방화벽 규칙 만들기
다음 섹션에서는 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 노트북을 만드는 방법을 안내합니다. 이 노트북은 인터넷 이그레스의 명시적 프록시를 타겟팅하는 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
기존 보안 웹 프록시에 다른 규칙을 추가하여 이 노트북 인스턴스의 트래픽을 전달합니다.
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 열기를 클릭합니다. Vertex AI Workbench 인스턴스가 JupyterLab을 엽니다.
File > New > Notebook선택Kernel > Python 3선택
필요한 Python 라이브러리 설치: pyyaml, google-cloud-aiplatform, cloudpickle, google-cloud-api-keys, langchain-google-vertexai를 비롯해 Agent Engine에 필요한 라이브러리를 설치합니다.
JupyterLab 노트북에서 새 셀을 만들고 SWP IP 주소를 지정하여 다음을 실행합니다.

!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 피어링이 필요한 swp.demo.com과 같은 PROXY_SERVER가 정의됩니다. 구성에서 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를 지정하여 Agent Engine이 인터넷 엔드포인트 api.frankfurter.app에 액세스하도록 명시적 프록시 구성을 보여줍니다.
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.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 노트북에서 새 셀을 만들고 다음을 실행합니다. 이전 출력에서 프로젝트 번호와 에이전트 엔진 추론 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에 대한 연결을 검증하는 성공적인 실행의 예

12. PSC 인터페이스 검사
다음으로 이동하여 에이전트 엔진에서 사용하는 네트워크 연결 IP를 확인할 수도 있습니다.
네트워크 서비스 → Private Service Connect → 네트워크 연결 → psc-network-attachment
테넌트 프로젝트(-tp로 끝나는 프로젝트 이름)를 선택합니다.

강조 표시된 필드는 PSC 네트워크 연결에서 에이전트 엔진이 사용하는 IP 주소를 나타냅니다.

13. SWP - Cloud Logging 검증
Cloud Logging을 확인하여 SWP에서 실행한 인터넷 이그레스를 검증하려면 다음으로 이동하세요.
모니터링 → 로그 탐색기
쿼리를 삽입합니다(resource.type=" networkservices.googleapis.com/Gateway"). 그런 다음 쿼리 실행을 클릭합니다. 다음은 대상 엔드포인트(api.frankfurter.app)를 확인하는 예입니다.


다음 Cloud Logging 예시에서는 다음을 검증합니다.
Destination_range: 에이전트 엔진 PSC 인터페이스 IP 주소
Source_range: 프록시 전용 서브넷 Dest_ip: 보안 웹 프록시 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 노트북에서 새 셀을 만들고 에이전트 엔진 배포 삭제를 트리거하는 다음 코드를 실행합니다.
"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을 성공적으로 구성하고 검증했습니다.
소비자 인프라를 만들고 프로듀서가 소비자 및 프로듀서 통신을 연결하는 다중 NIC VM을 만들 수 있도록 네트워크 연결을 추가했습니다. 인터넷 연결을 허용하는 명시적 프록시 및 DNS 피어링을 만드는 방법을 알아봤습니다.
Cosmopup은 튜토리얼이 멋지다고 생각합니다.
