1. Introduction
This Codelab explores Agent Gateway egress governance for AI agents accessing remote endpoints through a private VPC network. Agent Gateway operating in egress (agent-to-anywhere) mode supports private connectivity to a VPC network using Private Service Connect (PSC) interfaces. In this scenario, Agent Runtime uses Agent Gateway to access a remote streamable HTTP MCP server hosted on Cloud Run by using a Private Service Connect (PSC) endpoint for Google APIs in the VPC network.
AI apps, from standalone chatbots to autonomous systems with multi-agent workflows, can dynamically invoke external tools. Providing agents with controlled access for querying databases, fetching web content, and executing actions is essential for safe and productive agents. However, in enterprise environments, securing agent tool execution is a challenge. If an agent has direct network access, prompt injection attacks or model hallucinations can cause the agent to exfiltrate sensitive data or run destructive commands.
To manage autonmous agents at scale, Agent Gateway provides a centralized, zero-trust enforcement point directly integrated into the Agent Platform architecture. Instead of relying on custom implementations unique to each application or agent code, Agent Gateway provides network routing, agent governance, and runtime security enforced at the platform level.
When Agent Gateway operates in egress (agent-to-anywhere) mode, it proxies all outbound requests from agents configured to use the gateway. Each agent workload request is authenticated using the unique Agent Identity and authorized using Identity-Aware Proxy (IAP) policies. MCP tool calls are dynamically decoded and inspected for policy enforcement. Security admins can centrally enforce fine-grained permissions to ensure agents can only invoke approved endpoints and methods.
What you build
- Agent Gateway in egress (agent-to-anywhere) mode
- Identity-Aware Proxy (IAP) authorization extension
- Agent Runtime ADK agent with agent identity
- Cloud Run streamable HTTP MCP server
- Agent Registry with Google API and custom MCP endpoints
- Authorization policies with IAM access control
- VPC network resources, Cloud DNS zone, and PSC endpoint for Google APIs
- PSC network attachment for Agent Gateway egress
- Cloud Next Generation Firewall (NGFW) firewall policy rules
Fig 1. Codelab architecture
What you learn
- How to deploy Agent Gateway in a structured configuration sequence
- How to configure Agent Gateway with private VPC network connectivity
- How to transition authorization policies from a dry-run to enforced mode
- How to register Google API endpoints and MCP servers in the Agent Registry
- How to audit Agent Gateway logs to validate egress governance
- How to validate Agent Gateway egress traffic using Cloud NGFW logs
What you need
- A Google Cloud project with billing enabled
- IAM permissions to provision networking services, BigQuery datasets, and Agent Platform resources
- A POSIX-compatible shell (
bashorzsh) with Google Cloud CLI (gcloudandbqcomponents) installed - Command-line tools:
git,curl,jq(JSON processor), Python 3, anduv(Python package manager)
2. Concepts
Deployment sequence
This codelab follows a structured configuration sequence so agents have access to the necessary resources on initialization and connectivity can be confirmed before applying enforced access policies.
This Codelab uses the following deployment sequence:
- Start in
DRY_RUNmode: Ensure that agent requests are successfully arriving at the gateway and passing through (audit-only mode). - Register all services: Register all agentic components in Agent Registry and confirm agent tool access. Use Cloud Logging and the Agent Gateway observability dashboard to view queries to Agent Registry.
- Create authorization policies: Create and apply authorization policies to allow egress traffic from agents to MCP servers and endpoints.
- Switch to
ENFORCEDmode: Update authorization extension policy to enforce policies and block unauthorized egress traffic.
Fig 2. Deployment sequence
Egress routing topology
Agent Gateway egress (agent-to-anywhere) acts as a centralized, zero-trust outbound proxy for agentic workloads. When an agent makes a request to an external tool or API, the outbound request is intercepted by Agent Gateway and evaluated against governance policies before routing to its destination. In a Google Cloud Agent Platform architecture, Agent Gateway provides data plane connectivity to:
- Private networks (VPC): Outbound traffic targeting internal enterprise APIs, microservices, databases hosted within private VPCs, and on-premises or cross-cloud networks reachable through hybrid connectivity.
- External networks (Internet): Outbound traffic targeting third-party web services, SaaS APIs, or public endpoints.
- AI services & Agent Platform: Outbound traffic targeting managed Google Cloud APIs, foundation models, Google MCP endpoints (such as BigQuery), and platform governance services (Agent Registry and IAP policies).
Fig 3. Agent Gateway egress routing topology
The focus of this Codelab is outbound traffic from a custom agent on Agent Runtime targeting a PSC for Google APIs endpoint deployed in a VPC network. This architecture enables private access to the MCP server hosted on Cloud Run by using the PSC network attachment for Agent Gateway egress.
VPC connectivity
Agent Gateway egress (agent-to-anywhere) is able to connect to a VPC network by specifying the networkConfig: egress: networkAttachment: [URI] in the deployment YAML configuration file. This setting configures routing rules on Agent Gateway to send traffic that resolves to private IP addresses through the PSC network attachment into the VPC network.
Fig 4. Agent Gateway VPC connectivity
Agent Gateway is able to resolve private DNS hostnames using Cloud DNS peering to a specified target project and VPC network. Any private zones listed in the dnsPeeringConfig: domains: [NAME] configuration will use Cloud DNS records in the target project. Any other DNS queries will use the default VPC Cloud DNS public resolver.
This concludes the concepts portion... next on to the Setup section.
3. Setup
Required IAM roles
The following roles are required to create the resources in this Codelab:
Category | Required IAM role (ID) | Description |
API management |
| Enable Google Cloud API services |
Networking & gateway |
| Provision Agent Gateway |
Service extensions |
| Configure routing extensions |
Network security |
| Deploy authorization policies |
Agent Registry |
| Catalog allowed hosts |
Vertex AI & agents |
| Deploy Agent Runtime workloads |
Egress policies |
| Apply |
Cloud Storage |
| Manage deployment staging buckets |
Logs & auditing |
| Inspect traces and audit logs |
Cloud Run Developer |
| Deploy Cloud Run services |
Artifact Registry Reader |
| Pull container images |
Compute Network Admin |
| Manage VPC networking resources |
DNS Administrator |
| Manage Cloud DNS zones and records |
Alternatively, use a broad basic role like roles/admin or legacy role roles/owner.
Access your project
This Codelab uses a single Google Cloud project. Configuration steps use gcloud CLI and Linux shell commands.
Start by accessing your Google Cloud project command line:
- Cloud Shell at
shell.cloud.google.com, or - A local terminal with
gcloudCLI installed
Set your Project ID
gcloud config set project SET_YOUR_PROJECT_ID_HERE
Authenticate session
# login to gcloud cli
gcloud auth login
# login for gcloud api
gcloud auth application-default login
Set shell environment variables
# 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
Update gcloud cli (recommended)
If running a self-managed install of the Google Cloud SDK (ie, outside of Cloud Shell), update the components to the latest version.
# update gcloud cli
gcloud components update
Enable API services
# 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
This concludes the setup portion... next on to the Network section.
4. Network
The VPC network is deployed using custom mode to create regular subnets supporting the PSC network attachment for Agent Gateway and Cloud Run direct VPC egress.
The PSC endpoint for Google APIs is deployed using a single /32global internal IPv4 address to support private internal access to Cloud Run. This IP address is not assigned from any regional subnet.
Create networks
Create a global VPC network.
# create vpc network
gcloud compute networks create vnet-${SLUG} --subnet-mode=custom
Create subnets for the Agent Gateway PSC network attachment and Cloud Run direct VPC egress.
# 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
Create firewall rules
Create a firewall policy and rule to allow all egress traffic with logging enabled. This will be used to monitor traffic egressing from Agent Gateway to the VPC network.
# 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
Create PSC network attachment
Create a PSC network attachment configured to automatically accept new producer connections.
# create psc network attachment
gcloud compute network-attachments create psc-na-${REGION}-agw \
--region=${REGION} \
--subnets=subnet-${REGION}-agw \
--connection-preference=ACCEPT_AUTOMATIC
Verify PSC network attachment
# 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}
Create PSC endpoint
Create an IP address reservation for the global PSC endpoint. The address used here cannot come from, or overlap with, an existing subnet.
# 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}
Create a PSC endpoint for Google APIs using the all-apis bundle, which includes Cloud Run (run.app).
# 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
Verify PSC endpoint
# show psc endpoint details
gcloud compute forwarding-rules describe psc2gapis --global
Create DNS zone and records
Create a private Cloud DNS managed zone for the run.app domain.
# 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}
Create a wildcard DNS A record for *.run.app. pointing to the IP address of the PSC endpoint.
# create dns record
gcloud dns record-sets create *.run.app \
--zone=priv-zone-run \
--type=A \
--ttl=300 \
--rrdatas=${PSC_EP_IP}
Create a Cloud DNS policy to enable DNS query logging.
# create dns policy (logging)
gcloud dns policies create dns-policy-${SLUG} \
--description="dns logging for vnet-${SLUG}" \
--networks=vnet-${SLUG} \
--enable-logging
Create Cloud NAT
Create a Cloud Router and Cloud NAT to support Cloud Run direct VPC egress for the MCP server to reach external weather data through the VPC network.
# 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
This concludes the network portion... next on to the Gateway section.
5. Gateway
Before enforcing access controls, deploy Agent Gateway and configure the authorization extension in DRY_RUN mode. This allows outbound tool calls to succeed while logging evaluation results for audit purposes.
Here Agent Gateway uses a regional registry to support regional Agent Runtime resources and specifies the networkConfig fields for the VPC network PSC network attachment and DNS peering config.
Create gateway
# 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}
Verify gateway
# 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}
Check that there is an accepted connection endpoint.
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
This concludes the gateway portion... next on to the Authorization section.
6. Authorization
The Agent Gateway authorization extension for Identity-Aware Proxy (IAP) is a type of Service Extension used to delegate authorization decisions for all Agent Platform communications.
- Delegation flow: When an agent attempts to invoke an external endpoint or MCP server, it routes the request to Agent Gateway. Instead of evaluating access locally, the gateway uses the authorization extension to send a callout to the IAP evaluation service. IAP evaluates the agent (SPIFFE-based) identity against the IAM policy of the target resource in the Agent Registry. IAP returns an
ALLOWorDENYdecision back to the gateway, which either forwards the traffic onward or blocks it with an HTTP403 Forbiddenstatus code. - Enforcement modes: In
DRY_RUNmode, IAP evaluates requests and logs decisions in Cloud Logging without blocking traffic. InENFORCEmode, any request from an unauthorized agent or to an unregistered target is immediately blocked. - Binding layer: The service extension is connected to Agent Gateway using an authorization policy configured with the
REQUEST_AUTHZprofile.
Authorization extension
An authorization extension specifies the security provider service with connectivity settings and other parameters that define how the service will operate and integrate with Agent Gateway.
Create authz extension
# 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
# 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}
Verify authz extension
# show authz extension details
gcloud service-extensions authz-extensions describe ${AGW_NAME}-svc-ext-authz-iap-dryrun \
--location=${REGION}
Authorization policy
An authorization policy binds the security provider (IAP) to the target gateway resource and specifies the interception profile (REQUEST_AUTHZ).
Create authz policy
# 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
Bind authz policy
# 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}
Verify authz policy
# show authz policy details
gcloud beta network-security authz-policies describe ${AGW_NAME}-authz-policy-profile-iap \
--location=${REGION}
This concludes the authorization portion... next on to the Codebase section.
7. Codebase
The agent, MCP server, and endpoint registration code used for this Codelab are maintained in a remote Google Cloud GitHub repository. The following steps will clone the repository locally, copy the necessary files to the current working directory structure, and then cleanup temporary files.
A storage staging bucket is created for Agent Runtime to upload, build, and deploy the packaged agent application code and its dependency artifacts.
Fetch remote artifacts
# 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 staging bucket
# 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)"
This concludes the codebase portion... next on to the Registry section.
8. Registry
The Agent Registry is a centralized inventory of all agents, MCP servers, and endpoints (APIs) in the AI ecosystem. It is also a catalog that can be used to list, search, and discover other registered tools and services for use by AI applications. Agent Gateway uses the registry data model as the governance framework to enforce egress access control. IAM role grants for principal calling agents are checked against the policy bound to the registry resource.
In order to bootstrap the environment and support the agent using various Google APIs and Services, create a single registry endpoint service that bundles the core API interfaces needed for this lab. This will make it easier to manage governance policies for common sets of tools that most agents will use.
Register endpoints
# 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
Verify endpoint registration
# 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)"
This concludes the registry portion... next on to the MCP server section.
9. MCP server
Grant IAM permissions for deployment
Grant permissions to the default compute service account to support deploying Cloud Run services from source code.
# 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"
Verify IAM permissions
# 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)"
Deploy MCP server
# 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
Grant IAM permissions for ingress
Bind policy for user access
Grant permissions to the user account (self) for invoking the Cloud Run hosted MCP server. This is needed for running the toolspec generation script.
# 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"
Verify IAM permissions
# 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)"
Create custom SA for MCP invocation
Create a custom service account for invoking the Cloud Run hosted MCP server. This service account will be used by the agent to fetch a valid Google-signed OIDC ID token to access Cloud Run.
# 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}
Bind policy for service account
# 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}
Verify IAM permissions
# 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)"
Grant IAM permissions for authentication
Grant service account impersonation roles to the Default Compute Service Account. This will allow the agent, running under Application Default Credentials (ADC), to mint Google-signed OIDC ID tokens on behalf of the custom invoker service account to authenticate calls to Cloud Run.
Bind policy for authentication
# 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"
Verify IAM permissions
# 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)"
Create MCP toolspec
When registering an MCP server manually, a tool specification file must be included. A toolspec.json file lists all of the tools made available by the MCP server and lets other users discover them once registered.
The test_mcp.py script, included in the mcp-weather/ codebase, generates a toolspec.json file by connecting to the target MCP server (over SSE or HTTP) and calling list_tools() to retrieve all available tools exposed by the server.
# 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}"
A look at the generated toolspec output shows the MCP attributes that Agent Gateway can use for egress policy evaluation and enforcement.
Verify MCP toolspec
# show toolspec mcp attributes
jq '.tools[] | {name, isReadOnly, isDestructive, isIdempotent, isOpenWorld}' mcp-weather/toolspec.json
Update Cloud Run ingress
Change the ingress setting for the Cloud Run service so it only accepts incoming requests from the VPC network. This prevents direct public access to the MCP endpoint and only allows internal resources to access it. Traffic destined to the PSC endpoint for Google APIs in the VPC network will be considered internal ingress and allowed.
# update cloud run service config
gcloud run services update ${MCP_NAME} \
--region=${REGION} \
--ingress=internal
Verify Cloud Run ingress
# show cloud run service details
gcloud run services describe ${MCP_NAME} --region=${REGION} | grep -iE 'ingress|egress'
Register MCP server
Now with the toolspec in hand, register the MCP server with the regional Agent Registry.
# 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
Verify MCP registration
# 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}
This concludes the MCP server section... next on to the ADK agent section.
10. ADK agent
The agent-weather ADK agent deployed to Agent Runtime is configured with the following settings in the deployment script to integrate with Agent Platform:
"identity_type": types.IdentityType.AGENT_IDENTITYto provision a unique SPIFFE-based principal identity for the agent"agent_gateway_config": { "agent_to_anywhere_config": {"agent_gateway": } }to direct all outbound agent-initiated traffic to Agent Gateway for policy evaluation and enforcement
The agent is also configured to use the MCP server by passing the URL and the service account for fetching the OIDC ID token.
Deploy agent
# 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
Verify deployment
Fetch deployment vitals
# 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}
Verify registry entry
# show agent resource registry details
gcloud agent-registry agents describe ${RE_AGENT_REGISTRY_ID} --location=${REGION}
Verify gateway config
# 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}'
Grant IAM permissions for authentication
When an agent is configured to use Agent Identity, it receives a token (JWT-SVID format) from the federated Security Token Service (STS) which is signed by sts.googleapis.com (the SPIFFE identity provider).
However, the built-in Cloud Run IAM invoker check only trusts and can verify standard OIDC ID tokens signed by the main Google OIDC issuer (accounts.google.com).
So a custom service account is used to exchange the federated STS token (JWT-SVID) obtained by the agent identity for a standard Google (OIDC) token obtained using service account impersonation at runtime.
Create the role bindings needed for the custom service account.
Bind policy for authentication (impersonation)
# 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}"
Verify IAM permissions
# 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)"
Grant IAM permissions for runtime
Granting IAM permissions for runtime enables the agent to access to AI platform services and other core Google APIs and services using its SPIFFE-based principal agent identity. These policies are enforced using IAM at the resource level.
Create the role bindings needed for the agent identity.
Bind policies for agent access
# 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"
Verify IAM permissions
# 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)"
This concludes the ADK agent portion... next on to the Policies section.
11. Policies
Agent governance authorization policies permit traffic to be routed from an AI agent through Agent Gateway and on to the ultimate resource destination (eg, a private MCP server endpoint for data retrieval). Once traffic reaches the destination, regular service-level or application-level permissions authorize data access.
Granting IAM roles for Agent Gateway egress enables access policies that allow the agent principal identity access to registered destination resources through Agent Gateway. Policies are enforced at the Agent Gateway level and validated using Identity-Aware Proxy (IAP) IAM policies.
Grant IAM roles for Agent Gateway egress
Agent Gateway checks incoming requests to validate the calling agent identity has the iap.webServiceVersions.egressViaIAP permission (granted by the role roles/iap.egressor) on the target resource.
Granting roles/iap.egressor to the agent identity or Agent Runtime principal set on the selected destination resource permits this egress traffic. In this codelab, the role is applied to the principal agent which grants permission to the specific Agent Runtime agent identity.
The IAM policies are bound to the destination resources as defined in the Agent Registry data model. The iap_web/agentRegistry resource represents a "registry-wide" level in the IAM hierarchy. Where agentRegistry serves as the parent to the individual child resources for agents, mcpServers, and endpoints. In this codelab, the IAM policy is bound to the mcpServer and endpoint levels which applies the permission to the specific child resources.
Configure agent to MCP server policy
Create policy for agent to mcp server
# 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}
NOTE: etag: should return default ACAB since no policies have been defined yet.
# 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
Bind policy for agent to mcp server
# 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}
Verify IAM permissions
# 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}
This concludes the policies portion... next on to the Audit section.
12. Audit
The Agent Gateway authorization extension is operating in DRY_RUN mode. Outbound requests are observed and logged but not blocked. Analyzing the logs before switching to ENFORCED mode will confirm which policies need to be configured to allow the intended traffic.
Test agent queries
Open a browser window to the Google Cloud console UI and navigate to:
- Agent Platform → Agents → Deployments →
agent-weather - Select the Playground tab
Or echo this terminal command and click the link to jump to the agent playground:
# playground
echo "https://console.cloud.google.com/agent-platform/runtimes/locations/${REGION}/agent-engines/${RE_ENGINE_ID}/playground?project=${PROJ_ID}"
Submit some test queries....
What is the weather like in London?How warm is it in New York?
Verify the queries return valid responses.
Analyze audit logs
View logs and inspect the dry-run policy evaluations.
# 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
Configure agent to endpoints policy
Because the core Google APIs for agent-weather were registered under a collective endpoint service in the registry (gapi.core.services), just a single policy is needed to grant agent egress permissions for endpoint access.
Create policy for agent to endpoint
# 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
Bind policy for agent to endpoint
# 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}
Verify IAM permissions
# 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}
This concludes the audit portion... next on to the Enforce section.
13. Enforce
The agent was able to make successful requests through the gateway in DRY_RUN mode. The access logs and endpoints were analyzed to create a set of governance policies allowing the necessary egress traffic from the agent. Now transition the Agent Gateway IAP authorization extension to ENFORCE mode by updating the authorization policy.
Update authorization extension
Create authz extension
# 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
# 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}
Verify authz extension
# list authz extensions (imported configs)
gcloud service-extensions authz-extensions list --location=${REGION}
Update authorization policy
Create authz policy
# 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
Bind authz policy
# 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}
Verify authz policy
# show authz policy details (verify enforced mode)
gcloud beta network-security authz-policies describe ${AGW_NAME}-authz-policy-profile-iap \
--location=${REGION}
Verify enforcement
Return to the agent Playground in the console UI.
- Click the "+ New Session" button to create a new chat session
Submit an additional test query...
What is the current temperature in Los Angeles?
Observe the agent requests to the Gemini foundation model (${REGION}-aiplatform.googleapis.com/...) and MCP server endpoint (mcp-weather-${PROJ_NO}.${REGION}.run.app/mcp) are passed with HTTP 200 OK status codes.
Analyze gateway logs
# 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)"
Check there are no requests being blocked. Look for any denied egress attempts with HTTP 403 Forbidden status codes in the gateway audit logs.
# 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
)"
View the Agent Gateway MCP logs and note how the MCP application payload (JSON-RPC) is inspected to expose the protocol metadata, including which which tools are being executed.
# 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
)"
Analyze firewall logs
View logs for network firewall policy rule priority 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
)"
Note the network-level view of the different traffic paths:
- Agent Gateway communicating with internal VPC network resources using
subnet-${REGION}-agw - The Cloud Run hosted MCP server making calls to external weather APIs using
subnet-${REGION}-crun
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
Analyze DNS logs
View DNS query logs for requests resolved by the private DNS zone (priv-zone-run).
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
)"
Note DNS lookups for the Cloud Run service (mcp-weather...run.app) originate from the VPC network using DNS peering and are successfully resolved to the internal PSC endpoint for Google APIs (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
This concludes the enforce portion... next on to the Cleanup section.
14. Cleanup
# 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
This concludes the cleanup portion... next on to the Conclusion!
15. Conclusion
Congratulations! You have successfully deployed Agent Gateway and governed outbound AI agent traffic!

Cosmopup thinks Codelabs are the cat's pajamas!
What is next?
- Check out the Gemini Enterprise Agent Platform docs for advanced features and tutorials
- Configure Model Armor guardrails on Agent Gateway for additional AI safety and security
- Explore Semantic Governance Policies to enforce business rules and compliance for natural language queries
Feel free to offer any comments, questions, or corrections by using this feedback form.
Thank you!