Gemini Enterprise with Agent Gateway egress to private custom MCP server using Agent Registry

1. Introduction

This codelab explores private, governed egress connectivity for Gemini Enterprise using Agent Gateway in agent-to-anywhere (egress) mode. You will configure a Gemini Enterprise app to securely invoke a custom Model Context Protocol (MCP) server hosted on Cloud Run by routing traffic through Agent Gateway using Private Service Connect (PSC) interfaces to connect to a PSC endpoint for Google APIs in a VPC network.

In enterprise environments, granting autonomous agents direct network access risks data exfiltration and unvetted tool execution. Agent Gateway provides a centralized, platform-level zero-trust enforcement point that dynamically inspects streamable HTTP MCP tool payloads. Outbound requests are authenticated with a cryptographically verifiable Agent Identity and authorized through Identity-Aware Proxy (IAP) using IAM Unified Access Policies (UAP) with Common Expression Language (CEL) rules. This enables granular access control over specific MCP tools and methods without exposing backend workloads to the public internet.

What you build

  • Agent Gateway operating in egress (agent-to-anywhere) mode with Agent Registry endpoint verification
  • Cloud Run service hosting a private streamable HTTP MCP server (--ingress=internal) registered with its tool specifications in Agent Registry
  • Identity-Aware Proxy (IAP) authorization extension for Agent Gateway
  • IAM Unified Access Policies (UAP) with CEL conditions for MCP tool authorization
  • Gemini Enterprise app bound to Agent Gateway and connected to a custom MCP server data store imported from Agent Registry
  • VPC network resources, Cloud DNS zone, and PSC endpoint for Google APIs
  • PSC network attachment for Agent Gateway private VPC egress
  • Cloud Next Generation Firewall (NGFW) policy rules to secure VPC traffic

figure1

Fig 1. Codelab architecture

What you learn

  • How to deploy a private streamable HTTP MCP server from source on Cloud Run and register its endpoint and tool schema in Agent Registry
  • How to configure Agent Gateway with compliant registry entries and route Gemini Enterprise app tool calls through the gateway
  • How to establish private VPC egress using PSC network attachments and interfaces
  • How to delegate Agent Gateway authorization to Identity-Aware Proxy (IAP)
  • How to author and bind IAM Unified Access Policies (UAP) using destination.agent_registry.* and destination.is_registered CEL attributes to restrict MCP tool execution
  • How to validate policy enforcement and network egress using Cloud Logging

What you need

  • A Google Cloud project with billing enabled
  • An active Gemini Enterprise license or 30-day trial
  • IAM permissions to provision networking services, Gemini Enterprise, and Agent Platform resources
  • A POSIX-compatible shell (bash or zsh) with Google Cloud CLI (gcloud), curl, and jq installed

This concludes the introduction portion... next on to the Concepts section.

2. Concepts

Deployment sequence

This codelab deploys the infrastructure first so private network paths and governance controls are operational before registering and connecting MCP tools with Gemini Enterprise:

  1. Network infrastructure: Provision VPC subnets, a PSC endpoint, a PSC network attachment, Cloud NGFW policy rules, and private Cloud DNS zones.
  2. Agent Gateway: Deploy Agent Gateway in egress mode with Agent Registry integration (registries) and private VPC egress (networkAttachment).
  3. Authorization policies: Configure the IAP authorization extension, Gateway Authz policy, and IAM Unified Access Policy (UAP) using destination.is_registered and destination.agent_registry.* CEL conditions.
  4. Deploy & register MCP server: Deploy the math MCP server from source to Cloud Run (--ingress=internal) and register the service and tool specifications (add and subtract) in Agent Registry.
  5. Gemini Enterprise app: Create the Gemini Enterprise app (Engine), configure identity and observability settings, and bind outbound egress to Agent Gateway (agentGatewaySetting).
  6. Import custom MCP data connector: Create and activate the REGISTRY_MCP data connector (:setUpDataConnector) to link the registered MCP server's backing data store to the Gemini Enterprise app.
  7. Validate: Test allowed and denied tool executions in chat and verify policy enforcement across Agent Gateway, DNS, Firewall, and Cloud Run logs.

Gemini Enterprise egress

Gemini Enterprise routes custom MCP server tool requests to Agent Gateway when both agentGatewaySetting on the Engine and use_agent_gateway_egress: true on the DataConnector are configured.

figure2

Fig 2. Gemini Enterprise egress architecture

The Gemini Enterprise app organizes tool routing across four key areas:

  1. Widget (default_search_widget_config):
    • Serves the web client interface. The widget receives prompts from the user and initiates chat sessions with the underlying engine.
  2. Core Assistant (assistants/default_assistant/agents/default/core_assistant):
    • The root conversational reasoning agent within the engine. When evaluating a user query, the Core Assistant determines whether arithmetic calculation is required, inspects available tools, and delegates execution to the synthesized Agent Gateway sub-agent.
  3. Data Store and Data Connector:
    • DataStore: Provisioned inside a dedicated Collection when :setUpDataConnector runs, it links (dataStoreIds) the imported Agent Registry tool schemas (add, subtract), argument types, and agent instructions to the Gemini Enterprise Engine.
    • DataConnector: Manages the REGISTRY_MCP action connection (createBapConnection: true) to the remote MCP server (instance_uri), resolves the Agent Registry MCP server resource (registry_mcp_server_name), and enables Agent Gateway egress (use_agent_gateway_egress: true).
  4. Agent Identity, Agent Registry, and Agent Gateway:
    • When the Data Connector dispatches the outbound tool call, it routes traffic to the gateway specified in agentGatewaySetting. The Core Assistant mints a SPIFFE identity token asserting its identity: principal://agents.global.org-.../agents/default/core_assistant.
    • Agent Gateway integrates with Agent Registry using the registries field to dynamically resolve destination endpoints and registered tool schemas. It populates destination.is_registered and destination.agent_registry.* attributes and passes them to IAP v2 for evaluation against IAM Unified Access Policy (UAP) CEL rules before permitting transit into the VPC network.

Gateway VPC connectivity

Agent Gateway enables private VPC network connectivity using two YAML fields:

  • networkConfig.egress.networkAttachment: Directs private IP traffic to be routed through the PSC network attachment into the VPC network.
  • dnsPeeringConfig.domains: Peers DNS resolution with the VPC network Cloud DNS zone so target hostnames (*.run.app) resolve to the private PSC endpoint IP address defined in the VPC network.

Limitations & requirements

  • StreamableHTTP only: The legacy Server-Sent Events (SSE) transport is not supported. MCP servers must use StreamableHTTP.
  • Public CA TLS required: MCP endpoints must use TLS certificates signed by a publicly trusted CA, even when accessed privately over PSC.
  • Org policy override: You must explicitly override the organization policy for Custom MCP data stores before registering the data store.

This concludes the concepts portion... next on to the Setup section.

3. Setup

Required IAM roles

The following roles are required to complete Codelab:

Domain

Required IAM roles

Project & IAM

roles/orgpolicy.policyAdmin
roles/resourcemanager.projectIamAdmin
roles/iam.accessPolicyAdmin
roles/serviceusage.serviceUsageAdmin
roles/iam.serviceAccountUser

Networking & Gateway

roles/networkservices.admin
roles/networksecurity.admin
roles/serviceextensions.admin
roles/compute.networkAdmin
roles/dns.admin

Gemini Enterprise & Registry

roles/discoveryengine.admin
roles/agentregistry.admin (or roles/apphub.admin)

Workloads & Build

roles/run.admin
roles/cloudbuild.builds.editor
roles/artifactregistry.writer
roles/storage.admin

Observability

roles/logging.viewer
roles/logging.logWriter

Or use a broad basic role like roles/owner combined with roles/orgpolicy.policyAdmin (since roles/owner alone cannot modify organization policies).

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:

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"

echo ${SLUG}
echo ${REGION}
# 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 for agent platform (automatic)
export AGW_NAME="agw-${SLUG}-${REGION}-ata"
export AGW_URI="projects/${PROJ_ID}/locations/${REGION}/agentGateways/${AGW_NAME}"
export UAP_POLICY_NAME="uap-policy-${SLUG}"
export UAP_BINDING_NAME="uap-binding-${SLUG}"
export MCP_NAME="math-wizard"
export MCP_URL="https://${MCP_NAME}-${PROJ_NO}.${REGION}.run.app/mcp"

echo ${AGW_NAME}
echo ${AGW_URI}
echo ${UAP_POLICY_NAME}
echo ${UAP_BINDING_NAME}
echo ${MCP_NAME}
echo ${MCP_URL}
# create resource vars for gemini enterprise (automatic)
export GE_APP_DISPLAY_NAME="Codelab app"
export GE_APP_ORG_NAME="${SLUG}, Inc."
export GE_LOCATION="global"
export GE_APP_NAME="app-${SLUG}-${GE_LOCATION}"
export GE_APP_INIT="${GE_APP_NAME}_$(date +%s)"

echo ${GE_APP_DISPLAY_NAME}
echo ${GE_APP_ORG_NAME}
echo ${GE_LOCATION}
echo ${GE_APP_NAME}
echo ${GE_APP_INIT}

Set agent identity trust domains

The if-then-else statement checks if the project belongs to an organization in order to set the correct trust domain for the principal agent identities.

# set var for trust domain
if [[ -n "${ORG_ID}" ]]; then
  export TRUST_DOMAIN="agents.global.org-${ORG_ID}.system.id.goog"
else
  export TRUST_DOMAIN="agents.global.proj-${PROJ_NO}.system.id.goog"
fi

echo "trust domain: ${TRUST_DOMAIN}"

Set billing and quota project

# set cli quota project
gcloud config set billing/quota_project ${PROJ_ID}
# set api quota project
gcloud auth application-default set-quota-project ${PROJ_ID}

Create local directory for config files

# create config folder
mkdir -p cfg

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 (part 1)
gcloud services enable \
  agentregistry.googleapis.com \
  agentidentity.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 \
  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 (part 2)
gcloud services enable \
  artifactregistry.googleapis.com \
  cloudbuild.googleapis.com \
  discoveryengine.googleapis.com \
  dns.googleapis.com \
  orgpolicy.googleapis.com \
  run.googleapis.com \
  saasservicemgmt.googleapis.com \
  securitycenter.googleapis.com \
  storage.googleapis.com \
  telemetry.googleapis.com \
  texttospeech.googleapis.com

Organization Policies

Default Google Cloud managed organization policy constraints restrict features used in this Codelab:

Override any inherited organization policy restrictions on the project level by explicitly setting enforce: false.

Disable custom MCP constraint

# disable data connector constraint (allow custom mcp servers)
gcloud org-policies set-policy /dev/stdin << EOF
name: projects/${PROJ_NO}/policies/discoveryengine.managed.disableCustomMcpServerConnector
spec:
  rules:
  - enforce: false
EOF
# verify org policy constraint on project
gcloud org-policies describe discoveryengine.managed.disableCustomMcpServerConnector \
  --project=${PROJ_ID} --effective

Disable access policy constraint

# disable iam v3 constraint (allow v3 access policies)
gcloud org-policies set-policy /dev/stdin << EOF
name: projects/${PROJ_NO}/policies/iam.managed.disableAccessPolicyBinding
spec:
  rules:
  - enforce: false
EOF
# verify org policy constraint on project
gcloud org-policies describe iam.managed.disableAccessPolicyBinding \
  --project=${PROJ_ID} --effective

Check and disable conditional data connector constraints

By default, discoveryengine.managed.allowedEgressFqdns and discoveryengine.managed.allowedDataSources only block connector creation if your project is inside a VPC Service Controls (VPC SC) perimeter or if an organization administrator has added your project to enforcedProjects.

First, inspect the effective policies on your project:

# check effective egress fqdn constraint on project
gcloud org-policies describe discoveryengine.managed.allowedEgressFqdns \
  --project=${PROJ_ID} --effective
# check effective data source constraint on project
gcloud org-policies describe discoveryengine.managed.allowedDataSources \
  --project=${PROJ_ID} --effective

~~IF~~ these constraints are enforced, to ensure they do not block custom_mcp connector setup in a VPC SC or policy-restricted organization, set enforce: false on both policies for your project:

# disable egress fqdn constraint on project
gcloud org-policies set-policy /dev/stdin << EOF
name: projects/${PROJ_NO}/policies/discoveryengine.managed.allowedEgressFqdns
spec:
  rules:
  - enforce: false
EOF
# disable allowed data sources constraint on project
gcloud org-policies set-policy /dev/stdin << EOF
name: projects/${PROJ_NO}/policies/discoveryengine.managed.allowedDataSources
spec:
  rules:
  - enforce: false
EOF
# verify both constraints are disabled on project
gcloud org-policies describe discoveryengine.managed.allowedEgressFqdns \
  --project=${PROJ_ID} --effective

gcloud org-policies describe discoveryengine.managed.allowedDataSources \
  --project=${PROJ_ID} --effective

IAM permissions

Grant the required IAM roles to your user account and the Compute Engine default service account used by Cloud Build:

  • User account (${USER_IDENTITY}):
    • Requires permissions to deploy and invoke Cloud Run services (roles/run.admin, roles/run.invoker, roles/iam.serviceAccountUser), build container images (roles/cloudbuild.builds.editor), manage Gemini Enterprise (roles/discoveryengine.admin), and author Unified Access Policies (roles/iam.accessPolicyAdmin).
  • Compute Engine default service account(${PROJ_NO}-compute@developer.gserviceaccount.com):
    • Used by Cloud Build to stage source code in Cloud Storage (roles/storage.admin), push images to Artifact Registry (roles/artifactregistry.writer), and write build logs (roles/logging.logWriter).

Execute the following commands to assign the role bindings:

# grant roles to user account
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="user:${USER_IDENTITY}" \
  --role="roles/run.admin"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="user:${USER_IDENTITY}" \
  --role="roles/iam.serviceAccountUser"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="user:${USER_IDENTITY}" \
  --role="roles/run.invoker"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="user:${USER_IDENTITY}" \
  --role="roles/discoveryengine.admin"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="user:${USER_IDENTITY}" \
  --role="roles/iam.accessPolicyAdmin"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="user:${USER_IDENTITY}" \
  --role="roles/cloudbuild.builds.editor"
# grant roles to default compute (cloud build) service account
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="serviceAccount:${PROJ_NO}-compute@developer.gserviceaccount.com" \
  --role="roles/storage.admin"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="serviceAccount:${PROJ_NO}-compute@developer.gserviceaccount.com" \
  --role="roles/artifactregistry.writer"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="serviceAccount:${PROJ_NO}-compute@developer.gserviceaccount.com" \
  --role="roles/logging.logWriter"

Verify IAM permissions

Check for the six (6) role bindings on the user account.

# show iam policy on project for user account
gcloud projects get-iam-policy ${PROJ_ID} \
  --flatten="bindings[].members" \
  --filter="bindings.members:${USER_IDENTITY}" \
  --format="table(bindings.role:label=ROLE, bindings.members:label=PRINCIPAL_IDENTITY)"

Check for the three (3) role bindings on the default compute service account.

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

Verify service agent bindings (precautionary)

In a new project, Google Cloud automatically provisions the Agent Gateway service agent and grants it roles/agentgateway.serviceAgent when networkservices.googleapis.com is first enabled. If you are reusing an existing project where prior cleanup may have removed default service agent bindings, run the following commands as a fail-safe to ensure the identity and role binding are intact:

# ensure network services service account has been created
gcloud beta services identity create \
  --service=networkservices.googleapis.com \
  --project="${PROJ_ID}"

# ensure network services service account has service agent roles applied
gcloud projects add-iam-policy-binding "${PROJ_ID}" \
  --member="serviceAccount:service-${PROJ_NO}@gcp-sa-agentgateway.iam.gserviceaccount.com" \
  --role="roles/agentgateway.serviceAgent"

This concludes the setup portion... next on to the Network section.

4. Network

In this section you will deploy a VPC network using custom mode with a dedicated /28 subnet (192.168.10.0/28) supporting the PSC network attachment for Agent Gateway network egress into the VPC network.

The PSC endpoint for Google APIs is deployed using a single /32global internal IPv4 address (172.16.20.20) to support private internal access to Google APIs and services. In this Codelab, Agent Gateway targets Cloud Run using the PSC endpoint by resolving the run.app. domain by Cloud DNS peering.

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:

# 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 firewall rules

Create a firewall policy to allow all egress traffic with logging enabled. This will be used to monitor traffic egressing from Agent Gateway to the VPC network. Cloud NGFW supports both Essentials and Standard tiers for network security and traffic monitoring.

# 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
# bind fw policy to 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 Private Service Connect (PSC) network attachment configured to automatically accept connections from Agent Gateway. The network attachment establishes the consumer VPC network side of the connection to securely link with the Agent Gateway producer side for outbound egress traffic. For additional information on subnet requirements and IP range specifications, see Configure VPC connectivity.

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

Retrieve the resource URI of the PSC network attachment and store it in the PSC_NA_URI environment variable. This URI will be referenced in the Agent Gateway configuration (networkConfig.egress.networkAttachment) to provision the PSC Interface for network egress into the VPC network:

# fetch psc network attachment 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

A Private Service Connect (PSC) endpoint for Google APIs is used for Agent Gateway to establish private connectivity to the Cloud Run MCP server over an internal network path without exposing traffic to the public internet. Outbound tool calls egressing from Agent Gateway into the VPC network will resolve the target Cloud Run service URL (*.run.app) to this private endpoint IP address.

Reserve a global internal IPv4 address for the PSC endpoint. The IP address chosen must be a /32 address that does not overlap with any existing subnets in your VPC network:

# set env var for psc ep ip address
export PSC_EP_IP="172.16.20.20"
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

Cloud DNS is used to enable Agent Gateway to communicate privately with the Cloud Run hosted MCP server. When Agent Gateway evaluates outbound tool requests targeting Cloud Run, it uses DNS peering (dnsPeeringConfig.domains) to resolve DNS queries for *.run.app using your private Cloud DNS zone associated with your VPC network. The private DNS record returns the query with the internal PSC endpoint IP address (172.16.20.20), allowing MCP tool requests to be routed through a private network path.

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 run.app" \
  --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. DNS logging captures domain resolution requests originating from Agent Gateway within your VPC network, providing auditability and allowing you to verify that *.run.app tool requests correctly resolve to the internal PSC endpoint:

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

This concludes the network portion... next on to the Agent Gateway section.

5. Agent Gateway

Agent Gateway specifies registries for Agent Registry instances alongside the networkConfig fields that configure the PSC network attachment and DNS peering settings for private VPC connectivity:

  • registries: Associates the gateway with up to two Agent Registry instances: one regional (../locations/${REGION}) and one global (../locations/global). This integrates Agent Gateway with Agent Registry to resolve both regional deployments (such as Cloud Run MCP servers in ${REGION}) and global resources (such as Gemini Enterprise agents and global endpoints) for fine-grained IAP v2 policy enforcement. Regional entries take precedence over global entries when resolving destination URLs.
  • networkAttachment: Points to the PSC network attachment (psc-na-${REGION}-agw), connecting Agent Gateway into your VPC network for private egress.
  • dnsPeeringConfig.domains: Configures run.app. so that DNS queries originating from Agent Gateway for Cloud Run services use DNS peering to resolve hostnames to the private Google APIs PSC endpoint IP address (172.16.20.20) configured in your Cloud DNS private zone.

Deploy Agent Gateway

Create and import the Agent Gateway configuration file.

# create agent gateway config file
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 Agent Gateway deployment

Confirm the Agent Registry and network configuration:

# show agent gateway registries and network config
gcloud network-services agent-gateways describe ${AGW_NAME} \
  --location=${REGION} \
  --format="yaml(registries,networkConfig)"

Expected output:

networkConfig:
  dnsPeeringConfig:
    domains:
    - run.app.
    targetNetwork: projects/${PROJ_ID}/global/networks/vnet-${SLUG}
    targetProject: ${PROJ_ID}
  egress:
    networkAttachment: projects/${PROJ_ID}/regions/${REGION}/networkAttachments/psc-na-${REGION}-agw
registries:
- //agentregistry.googleapis.com/projects/${PROJ_ID}/locations/${REGION}

Verify that the output displays the required configuration details:

  • registries: Lists the regional (${REGION}) Agent Registry URI associated with the gateway.
  • egress.networkAttachment: Specifies the PSC network attachment URI for VPC egress.
  • dnsPeeringConfig.domains: Contains run.app. pointing to targetNetwork for private domain resolution.

Inspect the PSC network attachment to confirm the gateway connection:

# show psc network attachment details
gcloud compute network-attachments describe psc-na-${REGION}-agw \
  --region=${REGION} \
  --format="yaml(connectionEndpoints)"

Check there is an accepted connection endpoint:

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

Delegate authorization

Agent Gateway secures and governs outbound tool traffic using Authorization Policies (networksecurity.authzPolicies) integrated with Identity-Aware Proxy (IAP) Unified Access Policies (UAP).

While Agent Gateway supports basic inline ALLOW and DENY rules, enterprise environments require centralized, identity-centric governance. With IAM Unified Access Policies (or Access Policies), you manage egress access rules using standard IAM v3 access policies.

figure3

Fig 3. Authorization architecture

The authorization flow connects three components:

  1. Gateway Authorization Policy (authzPolicy):
    • A regional resource targeting Agent Gateway.
    • Configured with policyProfile: REQUEST_AUTHZ and action: CUSTOM to route all outbound authorization checks to the IAP Authz Extension.
  2. IAP Service Extension (authzExtension):
    • A regional resource that delegates request authorization to Identity-Aware Proxy (iap.googleapis.com).
    • Evaluates policies in ENFORCE mode using policy version V2.
  3. IAM Unified Access Policy and Binding (accessPolicy & policyBinding):
    • Global IAM v3 resources containing fine-grained access rules.
    • Authenticates the SPIFFE principal identity of the calling agent, verifies the universal iap.googleapis.com/resources.egressViaIAP permission, and evaluates Common Expression Language (CEL) conditions against destination attributes.

Deploy authorization extension

Create a service-extensions authorization extension configuration that delegates authorization decisions to the IAP service:

# create authz extension config file
cat > cfg/${AGW_NAME}-svc-ext-authz-iap.yaml << EOF
name: ${AGW_NAME}-svc-ext-authz-iap
service: iap.googleapis.com
failOpen: false
timeout: 1s
metadata:
  iapPolicyVersion: "V2"
EOF
# import iap authz extension (create authz extension)
gcloud service-extensions authz-extensions import ${AGW_NAME}-svc-ext-authz-iap \
  --source=cfg/${AGW_NAME}-svc-ext-authz-iap.yaml \
  --location=${REGION}

Verify authorization extension