Agent Runtime에서 VPC 네트워크로의 에이전트 게이트웨이 이그레스

1. 소개

이 Codelab에서는 비공개 VPC 네트워크를 통해 원격 엔드포인트에 액세스하는 AI 에이전트의 에이전트 게이트웨이 이그레스 거버넌스를 살펴봅니다. 이그레스 (에이전트-투-애니웨어) 모드에서 작동하는 에이전트 게이트웨이는 Private Service Connect (PSC) 인터페이스를 사용하여 VPC 네트워크에 대한 비공개 연결을 지원합니다. 이 시나리오에서 에이전트 런타임은 에이전트 게이트웨이를 사용하여 VPC 네트워크의 Google API용 Private Service Connect (PSC) 엔드포인트를 통해 Cloud Run에 호스팅된 원격 스트림 가능 HTTP MCP 서버에 액세스합니다.

독립형 챗봇부터 멀티 에이전트 워크플로가 있는 자율 시스템에 이르기까지 AI 앱은 외부 도구를 동적으로 호출할 수 있습니다. 데이터베이스를 쿼리하고, 웹 콘텐츠를 가져오고, 작업을 실행할 수 있는 제어된 액세스 권한을 에이전트에게 제공하는 것은 안전하고 생산적인 에이전트를 위해 필수적입니다. 하지만 엔터프라이즈 환경에서는 에이전트 도구 실행을 보호하는 것이 어렵습니다. 에이전트가 직접 네트워크 액세스 권한을 보유한 경우 프롬프트 인젝션 공격이나 모델 할루시네이션으로 인해 에이전트가 민감한 데이터를 유출하거나 파괴적인 명령어를 실행할 수 있습니다.

에이전트 게이트웨이는 자율 에이전트를 대규모로 관리하기 위해 Agent Platform 아키텍처에 직접 통합된 중앙 집중식 제로 트러스트 시행 지점을 제공합니다. 각 애플리케이션 또는 에이전트 코드에 고유한 맞춤 구현에 의존하는 대신 에이전트 게이트웨이는 플랫폼 수준에서 적용되는 네트워크 라우팅, 에이전트 거버넌스, 런타임 보안을 제공합니다.

에이전트 게이트웨이가 이그레스 (agent-to-anywhere) 모드로 작동하면 게이트웨이를 사용하도록 구성된 에이전트의 모든 아웃바운드 요청을 프록시합니다. 각 에이전트 워크로드 요청은 고유한 에이전트 ID를 사용하여 인증되고 Identity-Aware Proxy (IAP) 정책을 사용하여 승인됩니다. MCP 도구 호출은 정책 시행을 위해 동적으로 디코딩되고 검사됩니다. 보안 관리자는 세부적인 권한을 중앙에서 적용하여 에이전트가 승인된 엔드포인트와 메서드만 호출할 수 있도록 할 수 있습니다.

빌드할 항목

  • 이그레스 (agent-to-anywhere) 모드의 에이전트 게이트웨이
  • IAP (Identity-Aware Proxy) 승인 확장 프로그램
  • 에이전트 ID가 있는 Agent Runtime ADK 에이전트
  • Cloud Run 스트리밍 가능한 HTTP MCP 서버
  • Google API 및 맞춤 MCP 엔드포인트가 있는 에이전트 레지스트리
  • IAM 액세스 제어를 사용하는 승인 정책
  • VPC 네트워크 리소스, Cloud DNS 영역, Google API용 PSC 엔드포인트
  • 에이전트 게이트웨이 이그레스용 PSC 네트워크 연결
  • Cloud Next Generation Firewall (NGFW) 방화벽 정책 규칙

figure1

그림 1. Codelab 아키텍처

학습 내용

  • 구조화된 구성 시퀀스에서 에이전트 게이트웨이를 배포하는 방법
  • 비공개 VPC 네트워크 연결로 에이전트 게이트웨이를 구성하는 방법
  • 승인 정책을 테스트 실행 모드에서 강제 모드로 전환하는 방법
  • 에이전트 레지스트리에 Google API 엔드포인트 및 MCP 서버를 등록하는 방법
  • 에이전트 게이트웨이 로그를 감사하여 이그레스 거버넌스를 검증하는 방법
  • Cloud NGFW 로그를 사용하여 에이전트 게이트웨이 이그레스 트래픽을 검증하는 방법

필요한 항목

  • 결제가 사용 설정된 Google Cloud 프로젝트
  • 네트워킹 서비스, BigQuery 데이터 세트, 에이전트 플랫폼 리소스를 프로비저닝하는 IAM 권한
  • Google Cloud CLI (gcloudbq 구성요소)가 설치된 POSIX 호환 셸 (bash 또는 zsh)
  • 명령줄 도구: git, curl, jq (JSON 프로세서), Python 3, uv (Python 패키지 관리자)

2. 개념

배포 시퀀스

이 Codelab은 구조화된 구성 시퀀스를 따르므로 에이전트가 초기화 시 필요한 리소스에 액세스할 수 있고 강제 적용 액세스 정책을 적용하기 전에 연결을 확인할 수 있습니다.

이 Codelab에서는 다음 배포 시퀀스를 사용합니다.

  1. DRY_RUN 모드에서 시작: 에이전트 요청이 게이트웨이에 성공적으로 도착하고 통과하는지 확인합니다 (감사 전용 모드).
  2. 모든 서비스 등록: 에이전트 레지스트리에 모든 에이전트 구성요소를 등록하고 에이전트 도구 액세스를 확인합니다. Cloud Logging 및 에이전트 게이트웨이 관측 가능성 대시보드를 사용하여 에이전트 레지스트리에 대한 쿼리를 확인합니다.
  3. 승인 정책 만들기: 에이전트에서 MCP 서버 및 엔드포인트로의 이그레스 트래픽을 허용하는 승인 정책을 만들고 적용합니다.
  4. ENFORCED 모드로 전환: 승인 확장 프로그램 정책을 업데이트하여 정책을 적용하고 승인되지 않은 이그레스 트래픽을 차단합니다.

figure2

그림 2. 배포 시퀀스

이그레스 라우팅 토폴로지

에이전트 게이트웨이 이그레스 (agent-to-anywhere)는 에이전트형 워크로드의 중앙화된 제로 트러스트 아웃바운드 프록시 역할을 합니다. 에이전트가 외부 도구 또는 API에 요청하면 아웃바운드 요청이 에이전트 게이트웨이에 의해 가로채지고 대상으로 라우팅되기 전에 거버넌스 정책에 따라 평가됩니다. Google Cloud Agent Platform 아키텍처에서 에이전트 게이트웨이는 다음 항목에 데이터 영역 연결을 제공합니다.

  • 비공개 네트워크 (VPC): 하이브리드 연결을 통해 연결할 수 있는 내부 엔터프라이즈 API, 마이크로서비스, 비공개 VPC 내에 호스팅된 데이터베이스, 온프레미스 또는 크로스 클라우드 네트워크를 타겟팅하는 아웃바운드 트래픽입니다.
  • 외부 네트워크 (인터넷): 서드 파티 웹 서비스, SaaS API 또는 공개 엔드포인트를 타겟팅하는 아웃바운드 트래픽입니다.
  • AI 서비스 및 에이전트 플랫폼: 관리형 Google Cloud API, 기본 모델, Google MCP 엔드포인트 (예: BigQuery), 플랫폼 거버넌스 서비스 (에이전트 레지스트리 및 IAP 정책)를 타겟팅하는 아웃바운드 트래픽입니다.

figure3

그림 3. 에이전트 게이트웨이 이그레스 라우팅 토폴로지

이 Codelab에서는 VPC 네트워크에 배포된 Google API용 PSC 엔드포인트를 타겟팅하는 Agent Runtime의 맞춤 에이전트에서 발생하는 아웃바운드 트래픽에 중점을 둡니다. 이 아키텍처를 사용하면 에이전트 게이트웨이 이그레스를 위한 PSC 네트워크 연결을 통해 Cloud Run에서 호스팅되는 MCP 서버에 비공개로 액세스할 수 있습니다.

VPC 연결

에이전트 게이트웨이 이그레스 (agent-to-anywhere)는 배포 YAML 구성 파일에서 networkConfig: egress: networkAttachment: [URI]를 지정하여 VPC 네트워크에 연결할 수 있습니다. 이 설정은 PSC 네트워크 연결을 통해 비공개 IP 주소로 확인되는 트래픽을 VPC 네트워크로 전송하도록 에이전트 게이트웨이의 라우팅 규칙을 구성합니다.

figure4

그림 4. 에이전트 게이트웨이 VPC 연결

에이전트 게이트웨이는 지정된 타겟 프로젝트 및 VPC 네트워크에 대한 Cloud DNS 피어링을 사용하여 비공개 DNS 호스트 이름을 확인할 수 있습니다. dnsPeeringConfig: domains: [NAME] 구성에 나열된 비공개 영역은 타겟 프로젝트의 Cloud DNS 레코드를 사용합니다. 다른 DNS 쿼리는 기본 VPC Cloud DNS 공개 리졸버를 사용합니다.

이로써 개념 부분이 마무리되었습니다. 다음은 설정 섹션입니다.

3. 설정

필요한 IAM 역할

이 Codelab에서 리소스를 만들려면 다음 역할이 필요합니다.

카테고리

필수 IAM 역할 (ID)

설명

API 관리

roles/serviceusage.serviceUsageAdmin

Google Cloud API 서비스 사용 설정

네트워킹 및 게이트웨이

roles/networkservices.admin

에이전트 게이트웨이 프로비저닝

Service Extensions

roles/serviceextensions.admin

라우팅 확장 프로그램 구성

네트워크 보안

roles/networksecurity.admin

승인 정책 배포

에이전트 레지스트리

roles/agentregistry.admin

카탈로그 허용 호스트

Vertex AI 및 에이전트

roles/aiplatform.admin

Agent Runtime 워크로드 배포

이그레스 정책

roles/iap.admin

roles/iap.egressor 정책 적용

Cloud Storage

roles/storage.admin

배포 스테이징 버킷 관리

로그 및 감사

roles/logging.viewer

트레이스 및 감사 로그 검사

Cloud Run 개발자

roles/run.developer

Cloud Run 서비스 배포

Artifact Registry 리더

roles/artifactregistry.reader

컨테이너 이미지 가져오기

Compute 네트워크 관리자

roles/compute.networkAdmin

VPC 네트워킹 리소스 관리

DNS 관리자

roles/dns.admin

Cloud DNS 영역 및 레코드 관리

또는 roles/admin와 같은 광범위한 기본 역할이나 기존 역할 roles/owner를 사용합니다.

프로젝트에 액세스

이 Codelab에서는 단일 Google Cloud 프로젝트를 사용합니다. 구성 단계에서는 gcloud CLI 및 Linux 셸 명령어를 사용합니다.

먼저 Google Cloud 프로젝트 명령줄에 액세스합니다.

프로젝트 ID 설정

gcloud config set project SET_YOUR_PROJECT_ID_HERE

세션 인증

# login to gcloud cli
gcloud auth login
# login for gcloud api
gcloud auth application-default login

셸 환경 변수 설정

# set custom var for slug (eg, "foo") and region preference
export SLUG="foo"
export REGION="us-central1"
export MREGION="us"
echo ${SLUG}
echo ${REGION}
echo ${MREGION}
# create project vars (automatic)
export PROJ_ID=$(gcloud config list --format="value(core.project)")
export PROJ_NO=$(gcloud projects describe ${PROJ_ID} --format="value(projectNumber)")
export ORG_ID=$(gcloud projects get-ancestors ${PROJ_ID} --format="value(id)" | tail -n 1)
export USER_IDENTITY=$(gcloud config get-value account)
echo ${PROJ_ID}
echo ${PROJ_NO}
echo ${ORG_ID}
echo ${USER_IDENTITY}
# create resource vars (automatic)
export AGW_NAME="agw-${SLUG}-${REGION}-ata"
export AGW_URI="projects/${PROJ_ID}/locations/${REGION}/agentGateways/${AGW_NAME}"
export RE_AGENT_NAME="agent-weather"
export RE_AGENT_ID_SET="principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJ_NO}"
export STAGING_BUCKET="agent-staging-${PROJ_NO}"
export MCP_NAME="mcp-weather"
export MCP_DISPLAY_NAME="${MCP_NAME}-${PROJ_NO}.${REGION}.run.app"
export MCP_URL="https://${MCP_DISPLAY_NAME}/mcp"
echo ${AGW_NAME}
echo ${AGW_URI}
echo ${RE_AGENT_NAME}
echo ${RE_AGENT_ID_SET}
echo ${STAGING_BUCKET}
echo ${MCP_NAME}
echo ${MCP_DISPLAY_NAME}
echo ${MCP_URL}
# create local dir for config files
mkdir -p cfg

Google Cloud SDK의 자체 관리 설치를 실행하는 경우 (즉, Cloud Shell 외부) 구성요소를 최신 버전으로 업데이트합니다.

# update gcloud cli
gcloud components update

API 서비스 사용 설정

# enable google apis (agent platform bundle, part 1)
gcloud services enable \
  agentregistry.googleapis.com \
  aiplatform.googleapis.com \
  apphub.googleapis.com \
  apptopology.googleapis.com \
  cloudapiregistry.googleapis.com \
  cloudtrace.googleapis.com \
  compute.googleapis.com \
  dataform.googleapis.com \
  iam.googleapis.com \
  iamconnectors.googleapis.com \
  iap.googleapis.com \
  logging.googleapis.com \
  modelarmor.googleapis.com \
  monitoring.googleapis.com \
  networksecurity.googleapis.com \
  networkservices.googleapis.com \
  notebooks.googleapis.com \
  observability.googleapis.com
# enable google apis (agent platform bundle, part 2)
gcloud services enable \
  securitycenter.googleapis.com \
  saasservicemgmt.googleapis.com \
  storage.googleapis.com \
  telemetry.googleapis.com \
  texttospeech.googleapis.com
# enable google apis (all the rest)
gcloud services enable \
  run.googleapis.com \
  artifactregistry.googleapis.com \
  cloudbuild.googleapis.com \
  dns.googleapis.com

이것으로 설정 부분이 마무리되었습니다. 다음은 네트워크 섹션입니다.

4. 네트워크

VPC 네트워크는 커스텀 모드를 사용하여 배포되어 에이전트 게이트웨이 및 Cloud Run 직접 VPC 이그레스를 위한 PSC 네트워크 연결을 지원하는 일반 서브넷을 만듭니다.

Google API용 PSC 엔드포인트는 Cloud Run에 대한 비공개 내부 액세스를 지원하기 위해 단일 /32전역 내부 IPv4 주소를 사용하여 배포됩니다. 이 IP 주소는 리전 서브넷에서 할당되지 않습니다.

네트워크 만들기

글로벌 VPC 네트워크를 만듭니다.

# create vpc network
gcloud compute networks create vnet-${SLUG} --subnet-mode=custom

에이전트 게이트웨이 PSC 네트워크 연결 및 Cloud Run 직접 VPC 이그레스용 서브넷을 만듭니다.

# create subnet for agent gateway psc na
gcloud compute networks subnets create subnet-${REGION}-agw \
  --network=vnet-${SLUG} \
  --range=192.168.10.0/28 \
  --region=${REGION} \
  --enable-private-ip-google-access

# create subnet for cloud run dvpc egress
gcloud compute networks subnets create subnet-${REGION}-crun \
  --network=vnet-${SLUG} \
  --range=10.10.10.0/24 \
  --region=${REGION} \
  --enable-private-ip-google-access

방화벽 규칙 만들기

로깅이 사용 설정된 모든 이그레스 트래픽을 허용하는 방화벽 정책 및 규칙을 만듭니다. 이는 에이전트 게이트웨이에서 VPC 네트워크로 나가는 트래픽을 모니터링하는 데 사용됩니다.

# create fw policy
gcloud compute network-firewall-policies create fw-policy-${SLUG} --global
# create fw policy rule
gcloud compute network-firewall-policies rules create 1001 \
  --description="allow all out and log" \
  --firewall-policy=fw-policy-${SLUG} \
  --global-firewall-policy \
  --action=allow \
  --direction=EGRESS \
  --layer4-configs=all \
  --dest-ip-ranges=0.0.0.0/0 \
  --enable-logging
# associate fw policy to vpc network
gcloud compute network-firewall-policies associations create \
  --name=fw-policy-bind-${SLUG} \
  --firewall-policy=fw-policy-${SLUG} \
  --network=vnet-${SLUG} \
  --global-firewall-policy

PSC 네트워크 연결 만들기

새 제작자 연결을 자동으로 수락하도록 구성된 PSC 네트워크 연결을 만듭니다.

# create psc network attachment
gcloud compute network-attachments create psc-na-${REGION}-agw \
  --region=${REGION} \
  --subnets=subnet-${REGION}-agw \
  --connection-preference=ACCEPT_AUTOMATIC

PSC 네트워크 연결 확인

# show psc network attachment details
gcloud compute network-attachments describe psc-na-${REGION}-agw --region=${REGION}
# fetch psc na uri
export PSC_NA_URI=$(gcloud compute network-attachments describe psc-na-${REGION}-agw \
  --region=${REGION} \
  --format="value(selfLink.scope(v1))")
echo ${PSC_NA_URI}

PSC 엔드포인트 만들기

전역 PSC 엔드포인트의 IP 주소 예약을 만듭니다. 여기에 사용된 주소는 기존 서브넷에서 가져오거나 기존 서브넷과 겹칠 수 없습니다.

# set env var for psc ep ip address
export PSC_EP_IP="240.0.0.10"
echo ${PSC_EP_IP}
# reserve internal global ipv4 address
gcloud compute addresses create ip-psc2gapis \
  --global \
  --purpose=PRIVATE_SERVICE_CONNECT \
  --addresses=${PSC_EP_IP} \
  --network=vnet-${SLUG}

Cloud Run (run.app)이 포함된 all-apis 번들을 사용하여 Google API용 PSC 엔드포인트를 만듭니다.

# create psc endpoint for google apis
gcloud compute forwarding-rules create psc2gapis \
  --global \
  --network=vnet-${SLUG} \
  --address=ip-psc2gapis \
  --target-google-apis-bundle=all-apis

PSC 엔드포인트 확인

# show psc endpoint details
gcloud compute forwarding-rules describe psc2gapis --global

DNS 영역 및 레코드 만들기

run.app 도메인의 비공개 Cloud DNS 관리 영역을 만듭니다.

# create private dns zone
gcloud dns managed-zones create priv-zone-run \
  --description="private zone for cloud run" \
  --dns-name="run.app." \
  --visibility=private \
  --networks=vnet-${SLUG}

PSC 엔드포인트의 IP 주소를 가리키는 *.run.app.의 와일드 카드 DNS A 레코드를 만듭니다.

# create dns record
gcloud dns record-sets create *.run.app \
  --zone=priv-zone-run \
  --type=A \
  --ttl=300 \
  --rrdatas=${PSC_EP_IP}

DNS 쿼리 로깅을 사용 설정하는 Cloud DNS 정책을 만듭니다.

# create dns policy (logging)
gcloud dns policies create dns-policy-${SLUG} \
  --description="dns logging for vnet-${SLUG}" \
  --networks=vnet-${SLUG} \
  --enable-logging

Cloud NAT 만들기

MCP 서버가 VPC 네트워크를 통해 외부 날씨 데이터에 도달할 수 있도록 Cloud Run 직접 VPC 이그레스를 지원하는 Cloud Router 및 Cloud NAT를 만듭니다.

# create router for nat
gcloud compute routers create cr-nat-${SLUG}-${REGION} \
  --network=vnet-${SLUG} \
  --asn=16550 \
  --region=${REGION}
# create nat gateway
gcloud compute routers nats create nat-${SLUG}-${REGION} \
  --router=cr-nat-${SLUG}-${REGION} \
  --region=${REGION} \
  --auto-allocate-nat-external-ips \
  --nat-all-subnet-ip-ranges

이것으로 네트워크 부분이 마무리되었습니다. 다음은 게이트웨이 섹션입니다.

5. 게이트웨이

액세스 제어를 적용하기 전에 에이전트 게이트웨이를 배포하고 DRY_RUN 모드에서 승인 확장 프로그램을 구성합니다. 이렇게 하면 감사 목적으로 평가 결과를 로깅하는 동안 아웃바운드 도구 호출이 성공할 수 있습니다.

여기서 에이전트 게이트웨이는 리전 에이전트 런타임 리소스를 지원하기 위해 리전 레지스트리를 사용하고 VPC 네트워크 PSC 네트워크 연결 및 DNS 피어링 구성에 networkConfig 필드를 지정합니다.

게이트웨이 만들기

# create new agent gateway config file (with network settings)
cat > cfg/${AGW_NAME}-networkConfig.yaml << EOF
name: ${AGW_NAME}
protocols:
  - MCP
googleManaged:
  governedAccessPath: AGENT_TO_ANYWHERE
registries:
  - "//agentregistry.googleapis.com/projects/${PROJ_ID}/locations/${REGION}"
networkConfig:
  egress:
    networkAttachment: ${PSC_NA_URI}
  dnsPeeringConfig:
    domains:
      - run.app.
    targetProject: ${PROJ_ID}
    targetNetwork: projects/${PROJ_ID}/global/networks/vnet-${SLUG}
EOF
# import agent gateway config file (create gateway)
gcloud network-services agent-gateways import ${AGW_NAME} \
  --source="cfg/${AGW_NAME}-networkConfig.yaml" \
  --location=${REGION}

게이트웨이 확인

# show agent gateway details
gcloud network-services agent-gateways describe ${AGW_NAME} \
  --location=${REGION}
# show psc network attachment details
gcloud compute network-attachments describe psc-na-${REGION}-agw --region=${REGION}

수락된 연결 엔드포인트가 있는지 확인합니다.

connectionEndpoints:
- ipAddress: 192.168.10.2
  projectIdOrNum: '[AGW_PROJECT_NO]'
  status: ACCEPTED
  subnetwork: https://www.googleapis.com/compute/v1/projects/${PROJ_ID}/regions/${REGION}/subnetworks/subnet-${REGION}-agw

이것으로 게이트웨이 부분이 마무리되었습니다. 다음은 승인 섹션입니다.

6. 승인

Identity-Aware Proxy (IAP)용 에이전트 게이트웨이 승인 확장 프로그램은 모든 에이전트 플랫폼 통신의 승인 결정을 위임하는 데 사용되는 서비스 확장 프로그램의 한 유형입니다.

  1. 위임 흐름: 상담사가 외부 엔드포인트 또는 MCP 서버를 호출하려고 하면 요청이 상담사 게이트웨이로 라우팅됩니다. 게이트웨이는 로컬에서 액세스를 평가하는 대신 승인 확장 프로그램을 사용하여 IAP 평가 서비스에 콜아웃을 전송합니다. IAP는 Agent Registry의 타겟 리소스 IAM 정책에 대해 에이전트 (SPIFFE 기반) ID를 평가합니다. IAP는 ALLOW 또는 DENY 결정을 게이트웨이에 다시 반환하며, 게이트웨이는 트래픽을 전달하거나 HTTP 403 Forbidden 상태 코드로 차단합니다.
  2. 강제 적용 모드: DRY_RUN 모드에서 IAP는 요청을 평가하고 트래픽을 차단하지 않고 Cloud Logging에 결정을 로깅합니다. ENFORCE 모드에서는 승인되지 않은 에이전트의 요청이나 등록되지 않은 타겟에 대한 요청이 즉시 차단됩니다.
  3. 바인딩 레이어: 서비스 확장 프로그램은 REQUEST_AUTHZ 프로필로 구성된 승인 정책을 사용하여 에이전트 게이트웨이에 연결됩니다.

승인 확장 프로그램

승인 확장 프로그램은 서비스가 작동하고 에이전트 게이트웨이와 통합되는 방식을 정의하는 연결 설정 및 기타 매개변수가 있는 보안 제공업체 서비스를 지정합니다.

승인 확장 프로그램 만들기

# create authz extension config file (dry run mode)
cat > cfg/${AGW_NAME}-svc-ext-authz-iap-dryrun.yaml << EOF
name: ${AGW_NAME}-svc-ext-authz-iap-dryrun
service: iap.googleapis.com
failOpen: true
timeout: 1s
metadata:
  iamEnforcementMode: "DRY_RUN"
  iapPolicyVersion: "V1"
EOF

승인 확장 프로그램 가져오기

# import authz extension file (create extension)
gcloud service-extensions authz-extensions import ${AGW_NAME}-svc-ext-authz-iap-dryrun \
  --source=cfg/${AGW_NAME}-svc-ext-authz-iap-dryrun.yaml \
  --location=${REGION}

승인 확장 프로그램 확인

# show authz extension details
gcloud service-extensions authz-extensions describe ${AGW_NAME}-svc-ext-authz-iap-dryrun \
  --location=${REGION}

승인 정책

승인 정책은 보안 제공업체 (IAP)를 타겟 게이트웨이 리소스에 바인딩하고 인터셉션 프로필 (REQUEST_AUTHZ)을 지정합니다.

인증 정책 만들기

# create authz policy config file (attach dry-run authz extension)
cat > cfg/${AGW_NAME}-authz-policy-profile-iap.yaml << EOF
name: ${AGW_NAME}-authz-policy-profile-iap
target:
  resources:
    - "projects/${PROJ_ID}/locations/${REGION}/agentGateways/${AGW_NAME}"
policyProfile: REQUEST_AUTHZ
action: CUSTOM
customProvider:
  authzExtension:
    resources:
      - "projects/${PROJ_ID}/locations/${REGION}/authzExtensions/${AGW_NAME}-svc-ext-authz-iap-dryrun"
EOF

승인 정책 바인딩

# import authz policy config file (enable authz policy)
gcloud beta network-security authz-policies import ${AGW_NAME}-authz-policy-profile-iap \
  --source=cfg/${AGW_NAME}-authz-policy-profile-iap.yaml \
  --location=${REGION}

인증 정책 확인

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

이것으로 승인 부분이 마무리되었습니다. 다음으로 코드베이스 섹션으로 이동합니다.

7. 코드베이스

이 Codelab에 사용되는 에이전트, MCP 서버, 엔드포인트 등록 코드는 원격 Google Cloud GitHub 저장소에 유지됩니다. 다음 단계에서는 저장소를 로컬로 클론하고, 필요한 파일을 현재 작업 디렉터리 구조에 복사한 후 임시 파일을 정리합니다.

패키징된 에이전트 애플리케이션 코드와 종속 항목 아티팩트를 업로드, 빌드, 배포하기 위해 에이전트 런타임용 스토리지 스테이징 버킷이 생성됩니다.

원격 아티팩트 가져오기

# clone remote repository to temp local dir
git clone https://github.com/GoogleCloudPlatform/cloud-networking-solutions.git ./temp_agw_cuj_arun_egress_vpc
# copy agent runtime and endpoint definitions to working project dir
cp -r temp_agw_cuj_arun_egress_vpc/codelabs/agw-cuj-arun-egress-vpc/agent-weather ./agent-weather
cp -r temp_agw_cuj_arun_egress_vpc/codelabs/agw-cuj-arun-egress-vpc/mcp-weather ./mcp-weather
# remove temporary directory
rm -rf temp_agw_cuj_arun_egress_vpc

스테이징 버킷 만들기

# create storage bucket for agent deployment artifacts
gcloud storage buckets create gs://${STAGING_BUCKET} --location=${REGION}
# verify staging bucket url
gcloud storage buckets list --format="value(storage_url)"

이것으로 코드베이스 부분이 마무리되었습니다. 다음은 레지스트리 섹션입니다.

8. 레지스트리

Agent Registry는 AI 생태계의 모든 에이전트, MCP 서버, 엔드포인트 (API)의 중앙 집중식 인벤토리입니다. 또한 AI 애플리케이션에서 사용할 수 있는 다른 등록된 도구와 서비스를 나열, 검색, 탐색하는 데 사용할 수 있는 카탈로그이기도 합니다. 에이전트 게이트웨이는 레지스트리 데이터 모델을 거버넌스 프레임워크로 사용하여 이그레스 액세스 제어를 적용합니다. 호출 에이전트 주 구성원의 IAM 역할 권한은 레지스트리 리소스에 바인딩된 정책에 대해 확인됩니다.

환경을 부트스트랩하고 다양한 Google API 및 서비스를 사용하여 에이전트를 지원하려면 이 실습에 필요한 핵심 API 인터페이스를 번들로 묶는 단일 레지스트리 엔드포인트 서비스를 만드세요. 이렇게 하면 대부분의 상담사가 사용할 일반적인 도구 세트의 거버넌스 정책을 더 쉽게 관리할 수 있습니다.

엔드포인트 등록

# create endpoint service (with multiple entries)
gcloud agent-registry services create core-gapi-services \
  --location=${REGION} \
  --display-name="gapi.core.services" \
  --description="core apis and services" \
  --endpoint-spec-type=no-spec \
  --interfaces=protocolBinding=JSONRPC,url=https://telemetry.googleapis.com \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com \
  --interfaces=protocolBinding=JSONRPC,url=https://cloudresourcemanager.googleapis.com \
  --interfaces=protocolBinding=JSONRPC,url=https://iamcredentials.googleapis.com

엔드포인트 등록 확인

# list registry regional endpoints
gcloud agent-registry endpoints list --location=${REGION} \
  --flatten="interfaces[]" \
  --format="table(displayName, name.basename():label=ENDPOINT_ID, interfaces.url:label=URL)"

이로써 레지스트리 부분이 마무리되었습니다. 다음은 MCP 서버 섹션입니다.

9. MCP 서버

배포를 위한 IAM 권한 부여

소스 코드에서 Cloud Run 서비스를 배포할 수 있도록 기본 Compute 서비스 계정에 권한을 부여합니다.

# grant cloud run builder role to default compute sa
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="serviceAccount:${PROJ_NO}-compute@developer.gserviceaccount.com" \
  --role="roles/run.builder"

IAM 권한 확인

# show iam policy on project for default compute sa
gcloud projects get-iam-policy ${PROJ_ID} \
  --flatten="bindings[].members" \
  --filter="bindings.members=serviceAccount:${PROJ_NO}-compute@developer.gserviceaccount.com" \
  --format="table(bindings.role:label=ROLE, bindings.members:label=PRINCIPAL_IDENTITY)"

MCP 서버 배포

# deploy cloud run service
gcloud -q run deploy ${MCP_NAME} \
  --source=mcp-weather/server \
  --region=${REGION} \
  --no-allow-unauthenticated \
  --min-instances=1 \
  --network=vnet-${SLUG} \
  --subnet=subnet-${REGION}-crun \
  --vpc-egress=all-traffic \
  --startup-probe=httpGet.path=/warmup

수신에 대한 IAM 권한 부여

사용자 액세스 정책 바인딩

Cloud Run 호스팅 MCP 서버를 호출할 사용자 계정 (본인)에 권한을 부여합니다. toolspec 생성 스크립트를 실행하려면 이 작업이 필요합니다.

# grant run invoker role to user account on cloud run service level
gcloud run services add-iam-policy-binding ${MCP_NAME} \
  --region=${REGION} \
  --member="user:${USER_IDENTITY}" \
  --role="roles/run.invoker"

IAM 권한 확인

# show iam policy on cloud run service for invoker role
gcloud run services get-iam-policy ${MCP_NAME} \
  --region=${REGION} \
  --flatten="bindings[].members" \
  --filter="bindings.role=roles/run.invoker" \
  --format="table(bindings.members:label=PRINCIPAL_IDENTITY, bindings.role:label=ROLE)"

MCP 호출을 위한 맞춤 SA 만들기

Cloud Run 호스팅 MCP 서버를 호출하기 위한 맞춤 서비스 계정을 만듭니다. 이 서비스 계정은 에이전트가 Cloud Run에 액세스하기 위해 유효한 Google 서명 OIDC ID 토큰을 가져오는 데 사용됩니다.

# create custom sa for mcp server invocation
gcloud iam service-accounts create sa-${MCP_NAME}-invoker \
  --display-name="custom sa to invoke ${MCP_NAME}"
# set env var for service account identity
export MCP_INVOKER_SA="sa-${MCP_NAME}-invoker@${PROJ_ID}.iam.gserviceaccount.com"
echo ${MCP_INVOKER_SA}

서비스 계정의 정책 바인딩

# grant run invoker role to custom sa on cloud run service level
gcloud run services add-iam-policy-binding ${MCP_NAME} \
  --role="roles/run.invoker" \
  --member="serviceAccount:${MCP_INVOKER_SA}" \
  --region=${REGION}

IAM 권한 확인

# show iam policy on cloud run service for invoker role
gcloud run services get-iam-policy ${MCP_NAME} \
  --region=${REGION} \
  --flatten="bindings[].members" \
  --filter="bindings.role=roles/run.invoker" \
  --format="table(bindings.members:label=PRINCIPAL_IDENTITY, bindings.role:label=ROLE)"

인증을 위한 IAM 권한 부여

기본 Compute 서비스 계정에 서비스 계정 가장 역할을 부여합니다. 이렇게 하면 애플리케이션 기본 사용자 인증 정보 (ADC)로 실행되는 에이전트가 Cloud Run에 대한 호출을 인증하기 위해 커스텀 호출자 서비스 계정을 대신하여 Google 서명 OIDC ID 토큰을 생성할 수 있습니다.

인증을 위한 정책 바인딩

# grant oidc token creator role to default compute service account
gcloud iam service-accounts add-iam-policy-binding ${MCP_INVOKER_SA} \
  --role="roles/iam.serviceAccountOpenIdTokenCreator" \
  --member="serviceAccount:${PROJ_NO}-compute@developer.gserviceaccount.com"

# grant service account token creator role to default compute service account
gcloud iam service-accounts add-iam-policy-binding ${MCP_INVOKER_SA} \
  --role="roles/iam.serviceAccountTokenCreator" \
  --member="serviceAccount:${PROJ_NO}-compute@developer.gserviceaccount.com"

IAM 권한 확인

# show iam policy for the custom service account
gcloud iam service-accounts get-iam-policy ${MCP_INVOKER_SA} \
  --flatten="bindings[].members" \
  --format="table(bindings.role:label=ROLE, bindings.members:label=PRINCIPAL_IDENTITY)"

MCP 만들기 toolspec

MCP 서버를 수동으로 등록할 때는 도구 사양 파일을 포함해야 합니다. toolspec.json 파일은 MCP 서버에서 제공하는 모든 도구를 나열하며, 등록되면 다른 사용자가 이를 검색할 수 있습니다.

mcp-weather/ 코드베이스에 포함된 test_mcp.py 스크립트는 SSE 또는 HTTP를 통해 타겟 MCP 서버에 연결하고 list_tools()를 호출하여 서버에서 노출된 사용 가능한 모든 도구를 가져와 toolspec.json 파일을 생성합니다.

# fetch oidc token for cloud run authentication
export OIDC_TOKEN=$(gcloud auth print-identity-token)
# generate toolspec for registry ingestion
uv --directory mcp-weather run test_mcp.py --toolspec=include --token="${OIDC_TOKEN}"

생성된 toolspec 출력을 살펴보면 에이전트 게이트웨이가 이그레스 정책 평가 및 시행에 사용할 수 있는 MCP 속성이 표시됩니다.

MCP toolspec 확인

# show toolspec mcp attributes
jq '.tools[] | {name, isReadOnly, isDestructive, isIdempotent, isOpenWorld}' mcp-weather/toolspec.json

Cloud Run 인그레스 업데이트

VPC 네트워크에서 들어오는 요청만 수락하도록 Cloud Run 서비스의 인그레스 설정을 변경합니다. 이렇게 하면 MCP 엔드포인트에 대한 직접 공개 액세스가 방지되고 내부 리소스만 액세스할 수 있습니다. VPC 네트워크의 Google API용 PSC 엔드포인트로 향하는 트래픽은 내부 인그레스로 간주되어 허용됩니다.

# update cloud run service config
gcloud run services update ${MCP_NAME} \
  --region=${REGION} \
  --ingress=internal

Cloud Run 인그레스 확인

# show cloud run service details
gcloud run services describe ${MCP_NAME} --region=${REGION} | grep -iE 'ingress|egress'

MCP 서버 등록

이제 toolspec를 사용하여 지역 에이전트 레지스트리에 MCP 서버를 등록합니다.

# register mcp server
gcloud agent-registry services create ${MCP_NAME} \
  --location=${REGION} \
  --display-name="${MCP_DISPLAY_NAME}" \
  --description="mcp server for weather info" \
  --mcp-server-spec-type=tool-spec \
  --mcp-server-spec-content=mcp-weather/toolspec.json \
  --interfaces=url=${MCP_URL},protocolBinding=JSONRPC

MCP 등록 확인

# list registry regional mcp servers
gcloud agent-registry mcp-servers list --location=${REGION} --format="table(displayName, interfaces.url)"
# show mcp server registry details
gcloud agent-registry services describe ${MCP_NAME} --location=${REGION}
# fetch mcp server registry id
export MCP_REGISTRY_ID=$(gcloud agent-registry services describe ${MCP_NAME} \
  --location=${REGION} \
  --format="value(registryResource.basename())")
echo ${MCP_REGISTRY_ID}

MCP 서버 섹션이 끝났습니다. 다음은 ADK 에이전트 섹션입니다.

10. ADK 에이전트

Agent Runtime에 배포된 agent-weather ADK 에이전트는 Agent Platform과 통합하기 위해 배포 스크립트에서 다음 설정으로 구성됩니다.

  • "identity_type": types.IdentityType.AGENT_IDENTITY를 사용하여 에이전트의 고유한 SPIFFE 기반 보안 주체 ID를 프로비저닝합니다.
  • "agent_gateway_config": { "agent_to_anywhere_config": {"agent_gateway": } }를 사용하여 모든 아웃바운드 에이전트 시작 트래픽을 정책 평가 및 시행을 위해 에이전트 게이트웨이로 전달

또한 OIDC ID 토큰을 가져오기 위한 URL과 서비스 계정을 전달하여 MCP 서버를 사용하도록 에이전트가 구성됩니다.

에이전트 배포

# deploy agent runtime workload
uv --directory agent-weather run python3 deploy_agent.py \
  --project=${PROJ_ID} \
  --region=${REGION} \
  --src-dir=./agent \
  --staging-bucket=${STAGING_BUCKET} \
  --display-name="${RE_AGENT_NAME}" \
  --description="agent for weather info" \
  --mcp-server-url="${MCP_URL}" \
  --mcp-invoker-sa="${MCP_INVOKER_SA}" \
  --enable-telemetry \
  --enable-agent-identity \
  --agent-gateway-egress=${AGW_URI} \
  --allow-token-sharing

배포 확인

배포 주요 지표 가져오기

# fetch agent runtime resource (reasoning engine) id
export RE_ENGINE_ID=$(curl -s -X GET "https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJ_ID}/locations/${REGION}/reasoningEngines" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" | \
  jq -r --arg name "${RE_AGENT_NAME}" '.reasoningEngines[] | select(.displayName==$name) | .name | split("/") | last')
echo ${RE_ENGINE_ID}
# fetch agent runtime (reasoning engine) agent identity
export RE_AGENT_IDENTITY=$(gcloud agent-registry agents list \
  --location=${REGION} --filter="displayName=${RE_AGENT_NAME}" \
  --format="value(attributes.'agentregistry.googleapis.com/system/RuntimeIdentity'.principal)")
echo ${RE_AGENT_IDENTITY}
# fetch agent registry uid for agent
export RE_AGENT_REGISTRY_ID=$(gcloud agent-registry agents list \
  --location=${REGION} \
  --filter="displayName=${RE_AGENT_NAME}" \
  --format="value(uid)")
echo ${RE_AGENT_REGISTRY_ID}

레지스트리 항목 확인

# show agent resource registry details
gcloud agent-registry agents describe ${RE_AGENT_REGISTRY_ID} --location=${REGION}

게이트웨이 구성 확인

# show agent config details (gateway config)
curl -s -X GET "https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJ_ID}/locations/${REGION}/reasoningEngines/${RE_ENGINE_ID}" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  | jq '{displayName: .displayName, name: .name, effectiveIdentity: .spec.effectiveIdentity, agentGatewayConfig: .spec.deploymentSpec.agentGatewayConfig}'

인증을 위한 IAM 권한 부여

에이전트가 에이전트 ID를 사용하도록 구성되면 제휴 보안 토큰 서비스 (STS)에서 토큰 (JWT-SVID 형식)을 수신합니다. 이 토큰은 sts.googleapis.com (SPIFFE ID 공급자)에 의해 서명됩니다.

하지만 내장된 Cloud Run IAM 호출자 확인은 기본 Google OIDC 발급자 (accounts.google.com)가 서명한 표준 OIDC ID 토큰만 신뢰하고 확인할 수 있습니다.

따라서 커스텀 서비스 계정은 에이전트 ID로 획득한 제휴 STS 토큰 (JWT-SVID)을 런타임에 서비스 계정 가장을 사용하여 획득한 표준 Google (OIDC) 토큰으로 교환하는 데 사용됩니다.

커스텀 서비스 계정에 필요한 역할 바인딩을 만듭니다.

인증 (명의 도용)을 위한 정책 바인딩

# grant service account token creator role to agent principal identity
gcloud iam service-accounts add-iam-policy-binding ${MCP_INVOKER_SA} \
  --role="roles/iam.serviceAccountTokenCreator" \
  --member="${RE_AGENT_IDENTITY}"

# grant service account openid token creator role to agent principal identity
gcloud iam service-accounts add-iam-policy-binding ${MCP_INVOKER_SA} \
  --role="roles/iam.serviceAccountOpenIdTokenCreator" \
  --member="${RE_AGENT_IDENTITY}"

IAM 권한 확인

# show iam policy for custom service account
gcloud iam service-accounts get-iam-policy ${MCP_INVOKER_SA} \
  --flatten="bindings[].members" \
  --format="table(bindings.members.sub('^.*locations/', '.../locations/'):label=PRINCIPAL_IDENTITY, bindings.role:label=ROLE)"

런타임에 대한 IAM 권한 부여

런타임에 대한 IAM 권한 부여를 통해 에이전트는 SPIFFE 기반 보안 주체 에이전트 ID를 사용하여 AI 플랫폼 서비스 및 기타 핵심 Google API와 서비스에 액세스할 수 있습니다. 이러한 정책은 리소스 수준에서 IAM을 사용하여 적용됩니다.

에이전트 ID에 필요한 역할 바인딩을 만듭니다.

에이전트 액세스 정책 바인딩

# grant ai platform user role
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="${RE_AGENT_IDENTITY}" \
  --role="roles/aiplatform.user"

# grant agent default access role
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="${RE_AGENT_IDENTITY}" \
  --role="roles/aiplatform.agentDefaultAccess"

# grant agent registry viewer role
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="${RE_AGENT_IDENTITY}" \
  --role="roles/agentregistry.viewer"
# grant cloud logging writer role
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="${RE_AGENT_IDENTITY}" \
  --role="roles/logging.logWriter"

# grant cloud monitoring writer role
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="${RE_AGENT_IDENTITY}" \
  --role="roles/monitoring.metricWriter"

# grant browser role for resource manager lookup
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="${RE_AGENT_IDENTITY}" \
  --role="roles/browser"

IAM 권한 확인

# show iam policy on project for agent identity
gcloud projects get-iam-policy ${PROJ_ID} \
  --flatten="bindings[].members" \
  --filter="bindings.members:${RE_AGENT_IDENTITY}" \
  --format="table(bindings.members.sub('^.*locations/', '.../locations/'):label=PRINCIPAL_IDENTITY, bindings.role:label=ROLE)"

이로써 ADK 에이전트 부분이 마무리되었습니다. 다음은 정책 섹션입니다.

11. 정책

에이전트 거버넌스 승인 정책은 AI 에이전트에서 에이전트 게이트웨이를 거쳐 최종 리소스 대상 (예: 데이터 검색을 위한 비공개 MCP 서버 엔드포인트)으로 트래픽이 라우팅되도록 허용합니다. 트래픽이 대상에 도달하면 일반 서비스 수준 또는 애플리케이션 수준 권한으로 데이터 액세스가 승인됩니다.

에이전트 게이트웨이 이그레스에 대한 IAM 역할을 부여하면 에이전트 주 구성원 ID가 에이전트 게이트웨이를 통해 등록된 대상 리소스에 액세스할 수 있는 액세스 정책이 사용 설정됩니다. 정책은 에이전트 게이트웨이 수준에서 적용되며 IAP (Identity-Aware Proxy) IAM 정책을 사용하여 검증됩니다.

에이전트 게이트웨이 이그레스에 대한 IAM 역할 부여

에이전트 게이트웨이는 수신 요청을 확인하여 호출 에이전트 ID에 타겟 리소스에 대한 iap.webServiceVersions.egressViaIAP 권한 (roles/iap.egressor 역할에 의해 부여됨)이 있는지 확인합니다.

선택한 대상 리소스에 대한 에이전트 ID 또는 Agent Runtime 주 구성원 집합roles/iap.egressor 권한을 부여하면 이 이그레스 트래픽이 허용됩니다. 이 Codelab에서는 특정 Agent Runtime 에이전트 ID에 권한을 부여하는 주 구성원 agent에 역할이 적용됩니다.

IAM 정책은 에이전트 레지스트리 데이터 모델에 정의된 대로 대상 리소스에 바인딩됩니다. iap_web/agentRegistry 리소스는 IAM 계층 구조의 '레지스트리 전체' 수준을 나타냅니다. 여기서 agentRegistryagents, mcpServers, endpoints의 개별 하위 리소스의 상위 요소 역할을 합니다. 이 Codelab에서는 IAM 정책이 mcpServerendpoint 수준에 바인딩되어 특정 하위 리소스에 권한이 적용됩니다.

에이전트-MCP 서버 정책 구성

에이전트-MCP 서버 정책 만들기

# fetch active etag on policy for mcp server
export IAP_ETAG=$(gcloud beta iap web get-iam-policy \
  --resource-type=agent-registry --region=${REGION} \
  --mcp-server=${MCP_REGISTRY_ID} --format="value(etag)")
echo ${IAP_ETAG}

참고: 아직 정책이 정의되지 않았으므로 etag:는 기본 ACAB를 반환해야 합니다.

# create policy config file
cat > cfg/iap-policy-agent-to-mcp.json << EOF
{
  "bindings": [
    {
      "role": "roles/iap.egressor",
      "members": [
        "${RE_AGENT_IDENTITY}"
      ]
    }
  ],
  "etag": "${IAP_ETAG}"
}
EOF

에이전트와 mcp 서버 간 정책 바인딩

# import policy file
gcloud beta iap web set-iam-policy cfg/iap-policy-agent-to-mcp.json \
  --resource-type=agent-registry \
  --mcp-server=${MCP_REGISTRY_ID} \
  --region=${REGION}

IAM 권한 확인

# show iap iam policy on mcp server for agent
gcloud beta iap web get-iam-policy \
  --region=${REGION} \
  --resource-type=agent-registry \
  --mcp-server=${MCP_REGISTRY_ID}

정책 부분이 끝났습니다. 다음은 감사 섹션입니다.

12. 감사

에이전트 게이트웨이 승인 확장 프로그램이 DRY_RUN 모드로 작동하고 있습니다. 아웃바운드 요청은 관찰되고 로깅되지만 차단되지는 않습니다. ENFORCED 모드로 전환하기 전에 로그를 분석하면 원하는 트래픽을 허용하도록 구성해야 하는 정책을 확인할 수 있습니다.

에이전트 쿼리 테스트

브라우저 창을 열어 Google Cloud 콘솔 UI로 이동하고 다음으로 이동합니다.

  • Agent Platform → Agents → Deployments → agent-weather
  • Playground 탭을 선택합니다.

또는 이 터미널 명령어를 에코하고 링크를 클릭하여 에이전트 플레이그라운드로 이동합니다.

# playground
echo "https://console.cloud.google.com/agent-platform/runtimes/locations/${REGION}/agent-engines/${RE_ENGINE_ID}/playground?project=${PROJ_ID}"

테스트 쿼리를 제출합니다.

  • What is the weather like in London?
  • How warm is it in New York?

쿼리가 유효한 응답을 반환하는지 확인합니다.

감사 로그 분석

로그를 확인하고 테스트 실행 정책 평가를 검사합니다.

# show gateway logs for endpoints and authz status (duplicates removed)
gcloud logging read \
  "resource.type=\"networkservices.googleapis.com/Gateway\" \
  AND httpRequest.requestUrl:*" \
  --project=${PROJ_ID} \
  --limit=50 \
  --freshness=24h \
  --format="table( \
    timestamp.date(tz=LOCAL):label=TIMESTAMP, \
    httpRequest.status:label=STATUS, \
    jsonPayload.authzPolicyInfo.result:label=AUTHZ, \
    httpRequest.requestUrl.sub('(https?://[^/:]+).*', '\1'):label=ENDPOINT \
  )" | awk 'NR==1 {print; next} ! seen[$2,$3,$4]++'
TIMESTAMP            STATUS  AUTHZ    ENDPOINT
YYYY-MM-DDTHH:MM:SS  200     ALLOWED  https://cloudresourcemanager.googleapis.com
YYYY-MM-DDTHH:MM:SS  200     ALLOWED  https://${REGION}-aiplatform.googleapis.com
YYYY-MM-DDTHH:MM:SS  200     ALLOWED  https://iamcredentials.googleapis.com
YYYY-MM-DDTHH:MM:SS  200     ALLOWED  https://mcp-weather-${PROJ_NO}.${REGION}.run.app
YYYY-MM-DDTHH:MM:SS  200     ALLOWED  https://telemetry.googleapis.com
YYYY-MM-DDTHH:MM:SS  202     ALLOWED  https://mcp-weather-${PROJ_NO}.${REGION}.run.app

에이전트-엔드포인트 정책 구성

agent-weather의 핵심 Google API가 레지스트리 (gapi.core.services)의 집합적 엔드포인트 서비스에 등록되었으므로 엔드포인트 액세스에 대한 에이전트 이그레스 권한을 부여하는 데 하나의 정책만 필요합니다.

에이전트에서 엔드포인트로의 정책 만들기

# set var for endpoint display name
export ENDPOINT_DISPLAY_NAME="gapi.core.services"
echo ${ENDPOINT_DISPLAY_NAME}
# fetch endpoint registry id
export ENDPOINT_REGISTRY_ID=$(gcloud agent-registry services list \
  --location=${REGION} \
  --filter="displayName=${ENDPOINT_DISPLAY_NAME}" \
  --format="value(registryResource.basename())")
echo ${ENDPOINT_REGISTRY_ID}
# create policy config file
cat > cfg/iap-policy-agent-to-ep.json << EOF
{
  "bindings": [
    {
      "role": "roles/iap.egressor",
      "members": [
        "${RE_AGENT_IDENTITY}"
      ]
    }
  ]
}
EOF

에이전트의 정책을 엔드포인트에 바인드

# import policy file (bind iam policy)
gcloud -q beta iap web set-iam-policy cfg/iap-policy-agent-to-ep.json \
  --resource-type=agent-registry \
  --endpoint=${ENDPOINT_REGISTRY_ID} \
  --region=${REGION}

IAM 권한 확인

# show iap iam policy on endpoint for agent
gcloud beta iap web get-iam-policy \
  --region=${REGION} \
  --resource-type=agent-registry \
  --endpoint=${ENDPOINT_REGISTRY_ID}

감사 부분이 끝났습니다. 다음은 시행 섹션입니다.

13. 적용

상담사는 DRY_RUN 모드에서 게이트웨이를 통해 요청을 성공적으로 수행할 수 있었습니다. 액세스 로그와 엔드포인트를 분석하여 에이전트에서 필요한 이그레스 트래픽을 허용하는 거버넌스 정책을 만들었습니다. 이제 승인 정책을 업데이트하여 에이전트 게이트웨이 IAP 승인 확장 프로그램을 ENFORCE 모드로 전환합니다.

승인 확장 프로그램 업데이트

승인 확장 프로그램 만들기

# create authz extension config file (enforced mode)
cat > cfg/${AGW_NAME}-svc-ext-authz-iap-enforced.yaml << EOF
name: ${AGW_NAME}-svc-ext-authz-iap-enforced
service: iap.googleapis.com
failOpen: false
timeout: 1s
metadata:
  iapPolicyVersion: "V1"
EOF

승인 확장 프로그램 가져오기

# import authz extension file (create extension)
gcloud service-extensions authz-extensions import ${AGW_NAME}-svc-ext-authz-iap-enforced \
  --source=cfg/${AGW_NAME}-svc-ext-authz-iap-enforced.yaml \
  --location=${REGION}

승인 확장 프로그램 확인

# list authz extensions (imported configs)
gcloud service-extensions authz-extensions list --location=${REGION}

승인 정책 업데이트

인증 정책 만들기

# re-write authz policy config file (pointing to enforced authz extension)
cat > cfg/${AGW_NAME}-authz-policy-profile-iap.yaml << EOF
name: ${AGW_NAME}-authz-policy-profile-iap
target:
  resources:
    - "projects/${PROJ_ID}/locations/${REGION}/agentGateways/${AGW_NAME}"
policyProfile: REQUEST_AUTHZ
action: CUSTOM
customProvider:
  authzExtension:
    resources:
      - "projects/${PROJ_ID}/locations/${REGION}/authzExtensions/${AGW_NAME}-svc-ext-authz-iap-enforced"
EOF

승인 정책 바인딩

# import authz policy config file (enable new authz policy)
gcloud beta network-security authz-policies import ${AGW_NAME}-authz-policy-profile-iap \
  --source=cfg/${AGW_NAME}-authz-policy-profile-iap.yaml \
  --location=${REGION}

인증 정책 확인

# show authz policy details (verify enforced mode)
gcloud beta network-security authz-policies describe ${AGW_NAME}-authz-policy-profile-iap \
  --location=${REGION}

시행 확인

콘솔 UI에서 에이전트 Playground로 돌아갑니다.

  • '+ 새 세션' 버튼을 클릭하여 새 채팅 세션을 만듭니다.

추가 테스트 질문을 제출하세요.

  • What is the current temperature in Los Angeles?

Gemini 기본 모델 (${REGION}-aiplatform.googleapis.com/...) 및 MCP 서버 엔드포인트 (mcp-weather-${PROJ_NO}.${REGION}.run.app/mcp)에 대한 에이전트 요청이 HTTP 200 OK 상태 코드로 전달되는지 확인합니다.

게이트웨이 로그 분석

# show gateway logs for http requests
gcloud logging read \
  "resource.type=\"networkservices.googleapis.com/Gateway\" \
  AND httpRequest.requestUrl:*" \
  --project=${PROJ_ID} \
  --limit=10 \
  --format="table(
    timestamp.date(tz=LOCAL):label=TIMESTAMP,
    httpRequest.requestMethod:label=METHOD,
    httpRequest.status:label=STATUS,
    jsonPayload.authzPolicyInfo.result:label=IAP_AUTHZ,
    jsonPayload.agentGatewayInfo.mcpInfo.method:label=MCP_METHOD,
    httpRequest.requestUrl:label=URL)"

차단된 요청이 없는지 확인합니다. 게이트웨이 감사 로그에서 HTTP 403 Forbidden 상태 코드로 거부된 이그레스 시도를 찾습니다.

# show gateway logs for authz denies
gcloud logging read \
  "resource.type=\"networkservices.googleapis.com/Gateway\" \
  AND (jsonPayload.authzPolicyInfo.result=\"DENIED\" OR httpRequest.status=403)" \
  --project=${PROJ_ID} \
  --limit=10 \
  --format="table(
    timestamp.date(tz=LOCAL):label=TIMESTAMP,
    httpRequest.requestMethod:label=METHOD,
    httpRequest.status:label=STATUS,
    jsonPayload.enforcedGatewaySecurityPolicy.serverNameIndication:label=SNI,
    jsonPayload.authzPolicyInfo.result:label=AUTHZ_RESULT,
    jsonPayload.authzPolicyInfo.policies[0].name.basename():label=DENYING_POLICY
  )"

에이전트 게이트웨이 MCP 로그를 확인하고 실행 중인 도구를 비롯한 프로토콜 메타데이터를 노출하기 위해 MCP 애플리케이션 페이로드 (JSON-RPC)가 검사되는 방식을 확인합니다.

# show gateway logs for mcp requests with method and tool name
gcloud logging read \
  "resource.type=\"networkservices.googleapis.com/Gateway\" \
  AND jsonPayload.agentGatewayInfo.mcpInfo.method:*" \
  --project=${PROJ_ID} \
  --limit=10 \
  --format="table(
    timestamp.date(tz=LOCAL):label=TIMESTAMP,
    httpRequest.status:label=STATUS,
    jsonPayload.authzPolicyInfo.result:label=IAP_AUTHZ,
    jsonPayload.agentGatewayInfo.mcpInfo.method:label=MCP_METHOD,
    jsonPayload.agentGatewayInfo.mcpInfo.parameter:label=TOOL_NAME,
    httpRequest.requestUrl:label=URL
  )"

방화벽 로그 분석

네트워크 방화벽 정책 규칙 우선순위 1001의 로그를 확인합니다.

# show firewall logs for rule 1001
gcloud logging read \
  "jsonPayload.rule_details.priority=1001" \
  --project=${PROJ_ID} \
  --limit=10 \
  --format="table(
    timestamp.date(tz=LOCAL):label=TIMESTAMP,
    jsonPayload.disposition:label=ACTION,
    jsonPayload.connection.src_ip:label=SRC_IP,
    jsonPayload.connection.dest_ip:label=DEST_IP,
    jsonPayload.connection.dest_port:label=DEST_PORT,
    jsonPayload.vpc.subnetwork_name:label=SUBNET
  )"

다양한 트래픽 경로의 네트워크 수준 보기를 확인하세요.

  • subnet-${REGION}-agw를 사용하여 내부 VPC 네트워크 리소스와 통신하는 에이전트 게이트웨이
  • subnet-${REGION}-crun를 사용하여 외부 날씨 API를 호출하는 Cloud Run 호스팅 MCP 서버
TIMESTAMP            ACTION   SRC_IP        DEST_IP        DEST_PORT  SUBNET
YYYY-MM-DDTHH:MM:SS  ALLOWED  10.10.10.16   188.40.99.226  443        subnet-${REGION}-crun
YYYY-MM-DDTHH:MM:SS  ALLOWED  10.10.10.16   202.61.206.6   443        subnet-${REGION}-crun
YYYY-MM-DDTHH:MM:SS  ALLOWED  10.10.10.16   188.40.99.226  443        subnet-${REGION}-crun
YYYY-MM-DDTHH:MM:SS  ALLOWED  10.10.10.16   202.61.206.6   443        subnet-${REGION}-crun
YYYY-MM-DDTHH:MM:SS  ALLOWED  10.10.10.16   202.61.206.6   443        subnet-${REGION}-crun
YYYY-MM-DDTHH:MM:SS  ALLOWED  10.10.10.16   202.61.206.6   443        subnet-${REGION}-crun
YYYY-MM-DDTHH:MM:SS  ALLOWED  192.168.10.2  240.0.0.10     443        subnet-${REGION}-agw
YYYY-MM-DDTHH:MM:SS  ALLOWED  192.168.10.2  240.0.0.10     443        subnet-${REGION}-agw
YYYY-MM-DDTHH:MM:SS  ALLOWED  192.168.10.2  240.0.0.10     443        subnet-${REGION}-agw

DNS 로그 분석

비공개 DNS 영역 (priv-zone-run)에서 해결된 요청의 DNS 쿼리 로그를 확인합니다.

gcloud logging read \
  "resource.type=\"dns_query\" AND resource.labels.target_name=\"priv-zone-run\"" \
  --project=${PROJ_ID} \
  --limit=10 \
  --format="table(
    timestamp.date(tz=LOCAL):label=TIMESTAMP,
    jsonPayload.queryName:label=QUERY_NAME,
    jsonPayload.queryType:label=TYPE,
    jsonPayload.rdata:label=RESPONSE_RDATA,
    jsonPayload.sourceNetwork:label=NETWORK,
    resource.labels.source_type:label=SRC_TYPE
  )"

Cloud Run 서비스 (mcp-weather...run.app)의 DNS 조회는 DNS 피어링을 사용하여 VPC 네트워크에서 시작되며 Google API의 내부 PSC 엔드포인트 (240.0.0.10)로 성공적으로 확인됩니다.

TIMESTAMP            QUERY_NAME                                     TYPE  RESPONSE_RDATA                                                     NETWORK   SRC_TYPE
YYYY-MM-DDTHH:MM:SS  mcp-weather-${PROJ_NO}.${REGION}.run.app.  A     mcp-weather-${PROJ_NO}.${REGION}.run.app. 300     IN      a       240.0.0.10  vnet-${SLUG}  peering-zone
YYYY-MM-DDTHH:MM:SS  mcp-weather-${PROJ_NO}.${REGION}.run.app.  A     mcp-weather-${PROJ_NO}.${REGION}.run.app. 300     IN      a       240.0.0.10  vnet-${SLUG}  peering-zone
YYYY-MM-DDTHH:MM:SS  mcp-weather-${PROJ_NO}.${REGION}.run.app.  A     mcp-weather-${PROJ_NO}.${REGION}.run.app. 300     IN      a       240.0.0.10  vnet-${SLUG}  peering-zone
YYYY-MM-DDTHH:MM:SS  mcp-weather-${PROJ_NO}.${REGION}.run.app.  A     mcp-weather-${PROJ_NO}.${REGION}.run.app. 300     IN      a       240.0.0.10  vnet-${SLUG}  peering-zone

강제 적용 부분이 끝났습니다. 다음은 정리 섹션입니다.

14. 삭제

# delete agent runtime
curl -s -X DELETE "https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJ_ID}/locations/${REGION}/reasoningEngines/${RE_ENGINE_ID}?force=true" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)"

# next
# delete agent resources
gcloud -q storage rm --recursive gs://${STAGING_BUCKET}

for ROLE in \
  "roles/aiplatform.user" \
  "roles/aiplatform.agentDefaultAccess" \
  "roles/agentregistry.viewer" \
  "roles/logging.logWriter" \
  "roles/monitoring.metricWriter" \
  "roles/browser"; do
  gcloud -q projects remove-iam-policy-binding ${PROJ_ID} \
    --member="${RE_AGENT_IDENTITY}" \
    --role="${ROLE}"
done

# next
# delete mcp (cloud run) resources
gcloud -q projects remove-iam-policy-binding ${PROJ_ID} \
  --member="serviceAccount:${PROJ_NO}-compute@developer.gserviceaccount.com" \
  --role="roles/run.builder"

gcloud -q run services delete ${MCP_NAME} --region=${REGION}

gcloud -q artifacts repositories delete cloud-run-source-deploy --location=${REGION}

gcloud -q iam service-accounts delete sa-${MCP_NAME}-invoker@${PROJ_ID}.iam.gserviceaccount.com

gcloud -q agent-registry services delete ${MCP_NAME} --location=${REGION}

# next
# delete gateway resources (policy binding must be deleted synchronously first)
gcloud -q beta network-security authz-policies delete ${AGW_NAME}-authz-policy-profile-iap --location=${REGION}

gcloud -q beta service-extensions authz-extensions delete ${AGW_NAME}-svc-ext-authz-iap-dryrun --location=${REGION} --async

gcloud -q beta service-extensions authz-extensions delete ${AGW_NAME}-svc-ext-authz-iap-enforced --location=${REGION} --async

gcloud -q network-services agent-gateways delete ${AGW_NAME} --location=${REGION} --async

# next
# remove policies
export IAP_ETAG=$(gcloud beta iap web get-iam-policy --resource-type=agent-registry --endpoint=${ENDPOINT_REGISTRY_ID} --region=${REGION} --format="value(etag)")
cat > cfg/iap-policy-empty.json << EOF
{
  "bindings": [],
  "etag": "${IAP_ETAG}"
}
EOF

gcloud -q beta iap web set-iam-policy cfg/iap-policy-empty.json \
  --resource-type=agent-registry \
  --endpoint=${ENDPOINT_REGISTRY_ID} \
  --region=${REGION}

# next
# delete dns resources
gcloud -q dns record-sets delete *.run.app --type=A --zone=priv-zone-run

gcloud -q dns managed-zones delete priv-zone-run

gcloud -q dns policies update dns-policy-${SLUG} --networks=""

gcloud -q dns policies delete dns-policy-${SLUG}

# next
# delete router (includes nat) and psc resources
gcloud -q compute routers delete cr-nat-${SLUG}-${REGION} --region=${REGION}

gcloud -q compute forwarding-rules delete psc2gapis --global

gcloud -q compute addresses delete ip-psc2gapis --global

# next
# delete firewall resources
gcloud -q compute network-firewall-policies associations delete --name=fw-policy-bind-${SLUG} --firewall-policy=fw-policy-${SLUG} --global-firewall-policy

gcloud -q compute network-firewall-policies rules delete 1001 --firewall-policy=fw-policy-${SLUG} --global-firewall-policy

gcloud -q compute network-firewall-policies delete fw-policy-${SLUG} --global

# next
# delete network resources
gcloud -q compute networks subnets delete subnet-${REGION}-agw --region=${REGION}

gcloud -q compute networks subnets delete subnet-${REGION}-crun --region=${REGION}

gcloud -q compute network-attachments delete psc-na-${REGION}-agw --region=${REGION}

gcloud -q compute networks delete vnet-${SLUG}

# next
# clean up local working directories and generated configs
rm -rf cfg agent-weather mcp-weather

# end

이로써 정리 부분이 마무리되었습니다. 다음은 결론입니다.

15. 결론

수고하셨습니다 에이전트 게이트웨이를 배포하고 아웃바운드 AI 에이전트 트래픽을 관리했습니다.

cosmopup

Cosmopup은 Codelab이 최고라고 생각합니다.

다음 단계는 무엇인가요?

의견 양식을 사용하여 의견, 질문 또는 수정사항을 자유롭게 제공해 주세요.

감사합니다.