Gemini Enterprise dengan traffic keluar VPC semua traffic Agent Gateway dan IP statis Cloud NAT ke server MCP eksternal

1. Pengantar

Codelab ini membahas konektivitas keluar IP statis untuk Gemini Enterprise menggunakan Agent Gateway dalam mode agent-to-anywhere (keluar). Anda akan mengonfigurasi aplikasi Gemini Enterprise untuk memanggil server Model Context Protocol (MCP) kustom, yang dilindungi oleh daftar yang diizinkan IP sumber yang ketat dan autentikasi OAuth 2.0, dengan merutekan semua traffic keluar melalui Agent Gateway menggunakan konfigurasi template konektivitas. Lampiran jaringan Private Service Connect (PSC) menghubungkan Agent Gateway ke jaringan VPC dan Cloud NAT menyediakan alamat IP eksternal yang stabil untuk traffic keluar internet.

Secara default, koneksi keluar dari Gemini Enterprise ke endpoint internet publik berasal dari kumpulan alamat IP Google bersama yang dinamis dan tidak dapat disematkan ke satu aturan daftar yang diizinkan IP milik pelanggan. Memasangkan Agent Gateway dengan AgentConnectivityTemplate dalam mode ALL_TRAFFIC akan merutekan semua traffic agen keluar ke Jaringan VPC, tempat Cloud NAT menerjemahkan koneksi yang terikat ke internet ke alamat IPv4 eksternal statis yang dicadangkan di bawah kendali Anda sambil mempertahankan tata kelola alat MCP terpusat melalui Agent Registry dan Identity-Aware Proxy (IAP).

Yang Anda bangun

  • Template Konektivitas Agen (vpcEgress: ALL_TRAFFIC) dan Agent Gateway yang beroperasi dalam mode egress (agent-to-anywhere) dengan verifikasi endpoint Agent Registry
  • Jaringan VPC, lampiran jaringan PSC, Cloud Router, dan gateway Cloud NAT yang terikat ke alamat IPv4 eksternal statis yang dicadangkan
  • Server Resource MCP HTTP yang dapat di-streaming eksternal (mcp-sprockets) yang di-front-end oleh Caddy TLS, dibatasi oleh aturan firewall secara ketat ke IP statis Cloud NAT, dan memverifikasi token Bearer Google OAuth 2.0 yang didelegasikan pengguna terhadap https://oauth2.googleapis.com/tokeninfo
  • Layar izin OAuth 2.0 Platform Auth Google dan kredensial klien OAuth 2.0 Aplikasi web (accounts.google.com dan oauth2.googleapis.com/token)
  • Entri katalog server MCP Agent Registry dan spesifikasi alat (toolspec.json)
  • Ekstensi otorisasi Identity-Aware Proxy (IAP) dan kebijakan otorisasi Gateway untuk Agent Gateway
  • Aplikasi Gemini Enterprise yang terikat ke Agent Gateway dan terhubung ke penyimpanan data server MCP kustom OAuth 2.0 yang diimpor dari Agent Registry

figure1

Gambar 1. Arsitektur codelab

Yang Anda pelajari

  • Cara mengonfigurasi AgentConnectivityTemplate dengan vpcEgress: ALL_TRAFFIC untuk merutekan semua traffic keluar Agent Gateway ke dalam jaringan VPC
  • Cara mencadangkan alamat IPv4 eksternal statis dan mengikatnya ke Cloud NAT di subnet network attachment PSC
  • Cara men-deploy Server Resource MCP HTTP eksternal yang dapat di-streaming yang memverifikasi token Bearer OAuth 2.0 Google (oauth2.googleapis.com/tokeninfo) dan membatasi firewall ingress-nya secara ketat ke IP statis Cloud NAT (${NAT_EXT_IP}/32)
  • Cara mengonfigurasi kredensial klien OAuth 2.0 Google Identity dan mendaftarkan server MCP serta skema alatnya di Agent Registry
  • Cara menghubungkan server MCP OAuth 2.0 yang terdaftar ke Gemini Enterprise dan merutekan panggilan alat yang didelegasikan pengguna melalui Agent Gateway
  • Cara memvalidasi terjemahan IP statis, verifikasi identitas OAuth 2.0 pengguna akhir (authenticated_user), dan penerapan kebijakan gateway menggunakan perintah CLI dan Cloud Logging

Yang Anda perlukan

  • Project Google Cloud yang mengaktifkan penagihan
  • Lisensi Gemini Enterprise yang aktif atau uji coba 30 hari
  • Izin IAM untuk menyediakan layanan jaringan, Kebijakan Organisasi, Gemini Enterprise, dan resource Agent Platform
  • Shell yang kompatibel dengan POSIX (bash atau zsh) dengan Google Cloud CLI (gcloud), curl, dan jq yang diinstal

Bagian pengantar ini telah selesai... selanjutnya kita akan membahas bagian Konsep.

2. Konsep

Urutan deployment

Codelab ini men-deploy infrastruktur jaringan dan tata kelola terlebih dahulu sehingga jalur keluar IP statis dan kontrol gateway dapat beroperasi sebelum mendaftarkan dan menghubungkan alat MCP dengan Gemini Enterprise:

  1. Infrastruktur jaringan: Mencadangkan alamat IPv4 eksternal statis dan menyediakan VPC keluar, subnet lampiran PSC, lampiran jaringan PSC, Cloud Router, gateway Cloud NAT, dan aturan firewall jaringan MCP eksternal.
  2. Template Konektivitas Agen & Agent Gateway: Deploy AgentConnectivityTemplate (vpcEgress: ALL_TRAFFIC) dan AgentGateway regional dalam mode keluar (AGENT_TO_ANYWHERE) dengan integrasi Agent Registry (registries).
  3. Kebijakan otorisasi: Konfigurasi ekstensi otorisasi IAP (AuthzExtension), kebijakan otorisasi Gateway (AuthzPolicy), dan Kebijakan Akses Terpadu IAM v3 (AccessPolicy dan PolicyBinding).
  4. Deploy & daftarkan server MCP: Deploy Server Resource OAuth 2.0 mcp-sprockets eksternal di belakang Caddy TLS, verifikasi penerapan tokeninfo Google OAuth 2.0, kunci firewall ingress-nya secara ketat ke IP statis Cloud NAT (${NAT_EXT_IP}/32), dan daftarkan spesifikasi layanan dan alat (get_sprockets dan get_sprocket_by_id) di Agent Registry.
  5. Aplikasi Gemini Enterprise & klien OAuth 2.0: Konfigurasi penyedia Google Identity, lisensi uji coba, serta layar izin OAuth 2.0 dan kredensial klien Aplikasi web (OAUTH_CLIENT_ID dan OAUTH_CLIENT_SECRET), buat aplikasi Gemini Enterprise (Engine), dan ikat egress keluar ke Agent Gateway (agentGatewaySetting).
  6. Impor konektor data MCP kustom: Buat dan aktifkan konektor data REGISTRY_MCP (:setUpDataConnector) yang dikonfigurasi dengan auth_type: "OAUTH" untuk menautkan penyimpanan data pendukung server MCP terdaftar ke aplikasi Gemini Enterprise.
  7. Validasi: Selesaikan alur pemberian izin OAuth 2.0 pengguna satu kali, panggil alat MCP melalui asisten Gemini Enterprise (konfirmasi egress_source_ip dan authenticated_user), serta verifikasi penerapan kebijakan dan terjemahan NAT IP statis di Cloud Logging.

Arsitektur Server Resource MCP yang dilindungi OAuth + IdP terpusat

Dalam deployment perusahaan, pengelolaan identitas dan eksekusi alat mengikuti pemisahan peran OAuth 2.0 standar antara Penyedia Identitas (Server Otorisasi) terpusat dan Server Resource MCP yang dilindungi:

Peran OAuth 2.0

Komponen dalam Codelab Ini

Tanggung jawab

Pemilik Resource

Pengguna Akhir (${USER_IDENTITY})

Login ke aplikasi web Gemini Enterprise dan memberikan izin selama alur otorisasi OAuth 2.0 3-legged satu kali.

Klien OAuth 2.0

Gemini Enterprise custom_mcp Data Connector

Menyimpan OAUTH_CLIENT_ID dan OAUTH_CLIENT_SECRET, menukarkan kode otorisasi di oauth2.googleapis.com/token, menyimpan token OAuth 2.0 pengguna, dan menampilkan Authorization: Bearer [access_token] pada setiap panggilan alat MCP keluar.

Server Otorisasi

OAuth 2.0 Identitas Google (accounts.google.com & oauth2.googleapis.com/token)

Mengautentikasi pengguna selama pengalihan izin browser dan mengeluarkan token akses dan refresh OAuth 2.0 ke Gemini Enterprise.

Server Resource

Server mcp-sprockets Eksternal (https://mcp.[MCP_EXT_IP].sslip.io/mcp)

Menerapkan identitas jaringan Lapisan 3 menggunakan firewall VPC-nya (${NAT_EXT_IP}/32) dan identitas pengguna Lapisan 7 dengan memverifikasi header Authorization: Bearer [access_token] terhadap https://oauth2.googleapis.com/tokeninfo.

Karena pengalihan izin browser (accounts.google.com) dan pertukaran token saluran kembali (oauth2.googleapis.com/token) terjadi terhadap endpoint OAuth 2.0 yang dikelola Google, firewall server MCP eksternal hanya menerima permintaan JSON-RPC MCP runtime (POST /mcp) dari Agent Gateway melalui Cloud NAT, sehingga firewall ingress-nya dapat dikunci secara ketat ke ${NAT_EXT_IP}/32.

Model resource Discovery Engine

Aplikasi Gemini Enterprise (diwakili sebagai resource Engine di Discovery Engine API) adalah lapisan orkestrasi pusat dan antarmuka percakapan untuk pengguna akhir. Komponen ini mengelola sesi chat pengguna, mendasarkan model generatif pada data perusahaan, dan mengoordinasikan eksekusi alat dinamis.

Aplikasi Gemini Enterprise berinteraksi dengan data dan sistem melalui penyimpanan data:

  • Penyimpanan data pengetahuan: Menyerap dan mengindeks konten statis (misalnya, Cloud Storage, Google Drive, BigQuery) untuk retrieval-augmented generation (RAG).
  • Konektor data (penyedia tindakan): Terhubung ke API pihak ketiga atau kustom yang dinamis. Penyimpanan data server MCP kustom mengekspos alat yang ditentukan oleh Model Context Protocol (MCP), sehingga memungkinkan model memanggil fungsi eksternal secara dinamis selama percakapan.

Egress Gemini Enterprise

Gemini Enterprise merutekan permintaan alat server MCP kustom ke Agent Gateway jika agentGatewaySetting di Engine dan use_agent_gateway_egress: true di DataConnector dikonfigurasi.

figure2

Gambar 2. Arsitektur keluar Gemini Enterprise

Aplikasi Gemini Enterprise mengatur perutean alat di empat area utama:

  1. Widget (default_search_widget_config):
    • Menyajikan antarmuka klien web. Widget menerima perintah dari pengguna, memicu pengalihan izin pengguna OAuth 2.0 satu kali saat alat memerlukan otorisasi, dan memulai sesi chat dengan mesin yang mendasarinya.
  2. Asisten Inti (assistants/default_assistant/agents/default/core_assistant):
    • Agen penalaran percakapan root dalam mesin. Saat mengevaluasi kueri pengguna, Asisten Inti akan memeriksa alat yang tersedia dan mendelegasikan eksekusi ke sub-agen Agent Gateway yang disintesis.
  3. Data Store dan Data Connector:
    • DataStore: Disediakan di dalam Collection khusus saat :setUpDataConnector berjalan, dan menautkan (dataStoreIds) skema alat Agent Registry yang diimpor (get_sprockets, get_sprocket_by_id), jenis argumen, dan petunjuk agen ke Engine Gemini Enterprise.
    • DataConnector: Mengelola koneksi tindakan REGISTRY_MCP (createBapConnection: true) ke server MCP jarak jauh (instance_uri), menyelesaikan resource server MCP Agent Registry (registry_mcp_server_name), melampirkan token OAuth 2.0 Bearer yang disimpan pengguna (Authorization: Bearer [access_token]), dan mengaktifkan keluar Agent Gateway (use_agent_gateway_egress: true).
  4. Identitas Agen, Agent Registry, dan Agent Gateway:
    • Saat mengirimkan panggilan alat keluar, Konektor Data akan merutekan traffic ke gateway yang ditentukan di agentGatewaySetting. Core Assistant membuat token identitas SPIFFE yang menegaskan identitas workload-nya: principal://agents.global.org-.../agents/default/core_assistant.
    • Agent Gateway terintegrasi dengan Agent Registry menggunakan kolom registries untuk menyelesaikan endpoint tujuan dan skema alat terdaftar secara dinamis, mengevaluasi kebijakan otorisasi menggunakan IAP, dan meneruskan permintaan yang diizinkan (dengan mempertahankan header Authorization: Bearer pengguna) ke jaringan VPC menggunakan AgentConnectivityTemplate.

Konektivitas VPC gateway dan NAT IP statis

Agent Gateway mendukung konektivitas jaringan VPC menggunakan resource AgentConnectivityTemplate yang dirujuk oleh agentConnectivityTemplate di gateway. Template egressNetworkConfig menentukan cara traffic memasuki VPC Anda melalui lampiran jaringan PSC:

  • PRIVATE_RANGES_ONLY (default): Hanya merutekan rentang IP pribadi RFC 1918, RFC 6598, dan Class E melalui lampiran jaringan PSC. Traffic yang ditujukan ke internet melewati VPC Anda dan keluar langsung melalui egress internet default Google.
  • ALL_TRAFFIC (digunakan dalam Codelab ini): Merutekan semua traffic keluar dari Agent Gateway—termasuk internet publik dan endpoint MCP partner eksternal—ke subnet VPC Anda melalui lampiran jaringan PSC (10.10.10.2).

Saat beroperasi dalam mode ALL_TRAFFIC, subnet lampiran PSC memerlukan dua konfigurasi:

  • Akses Google Pribadi (--enable-private-ip-google-access): Memastikan panggilan internal ke Google Cloud API (*.googleapis.com) terus dirutekan secara pribadi dalam jaringan Google.
  • Cloud Router dan Cloud NAT (MANUAL_ONLY): Traffic yang terikat internet yang memasuki subnet lampiran PSC mengikuti rute default (0.0.0.0/0) melalui Cloud NAT, yang melakukan Penerjemahan Alamat Jaringan Sumber (SNAT) ke alamat IPv4 eksternal statis yang dicadangkan (${NAT_EXT_IP}). Oleh karena itu, firewall eksternal dapat membatasi akses masuk secara ketat ke ${NAT_EXT_IP}/32.

Batasan & persyaratan

  • Khusus StreamableHTTP: Transportasi Server-Sent Events (SSE) lama tidak didukung. Server MCP harus menggunakan StreamableHTTP.
  • Penggantian kebijakan org: Anda harus secara eksplisit mengganti kebijakan organisasi untuk penyimpanan data MCP Kustom sebelum mendaftarkan konektor data.
  • Penyelarasan regional: Gemini Enterprise menerapkan penyelarasan regional antara lokasi aplikasi, Agent Gateway, dan Agent Registry:

Lokasi aplikasi Gemini Enterprise

Lokasi Agent Gateway & NAT

Lokasi Agent Registry

global

us-central1

us-central1, us, atau global

us

us-central1

us-central1 atau us

eu

europe-west1

europe-west1 atau eu

Bagian konsep ini telah selesai... selanjutnya ke bagian Penyiapan.

3. Penyiapan

Peran IAM yang diperlukan

Peran berikut diperlukan untuk menyelesaikan Codelab ini:

Domain

Peran IAM yang diperlukan

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/iap.admin
roles/compute.networkAdmin
roles/compute.securityAdmin

Gemini Enterprise & Registry

roles/discoveryengine.admin
roles/agentregistry.admin

Beban kerja

roles/compute.instanceAdmin.v1 (atau roles/compute.admin)

Kemampuan observasi

roles/logging.viewer

Atau gunakan peran dasar yang luas seperti roles/owner yang dikombinasikan dengan roles/orgpolicy.policyAdmin (karena roles/owner saja tidak dapat mengubah kebijakan organisasi).

Mengakses project Anda

Codelab ini menggunakan satu project Google Cloud. Langkah-langkah konfigurasi menggunakan perintah CLI gcloud dan shell Linux.

Mulailah dengan mengakses command line project Google Cloud Anda:

Menetapkan Project ID

# set target project id
gcloud config set project SET_YOUR_PROJECT_ID_HERE

Mengautentikasi sesi

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

Menetapkan variabel lingkungan shell

# set custom var for slug (eg, "foo") and region preference
export SLUG="foo"
export REGION="us-central1"
export ZONE="us-central1-a"

echo ${SLUG}
echo ${REGION}
echo ${ZONE}
# 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 MCP_NAME="mcp-sprockets"

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

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

Menetapkan domain tepercaya identitas agen

Pernyataan if-then-else memeriksa apakah project termasuk dalam organisasi untuk menetapkan domain tepercaya yang benar bagi identitas agen utama.

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

Menetapkan project penagihan dan kuota

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

Buat direktori lokal untuk file konfigurasi

# create config folder
mkdir -p cfg

Jika menjalankan penginstalan Google Cloud SDK yang dikelola sendiri (yaitu, di luar Cloud Shell), update komponen ke versi terbaru.

# update gcloud cli
gcloud components update

Mengaktifkan layanan API

# enable google cloud apis
gcloud services enable \
  agentregistry.googleapis.com \
  aiplatform.googleapis.com \
  cloudapiregistry.googleapis.com \
  cloudresourcemanager.googleapis.com \
  compute.googleapis.com \
  discoveryengine.googleapis.com \
  dns.googleapis.com \
  iam.googleapis.com \
  iap.googleapis.com \
  logging.googleapis.com \
  monitoring.googleapis.com \
  networkconnectivity.googleapis.com \
  networksecurity.googleapis.com \
  networkservices.googleapis.com \
  orgpolicy.googleapis.com \
  serviceextensions.googleapis.com \
  serviceusage.googleapis.com

Kebijakan organisasi

Batasan kebijakan organisasi terkelola Google Cloud default dan kebijakan sandbox dapat membatasi fitur yang digunakan dalam Codelab ini:

  • compute.vmExternalIpAccess: Membatasi alamat IPv4 eksternal pada VM Compute Engine di organisasi sandbox yang dikunci.
  • discoveryengine.managed.disableCustomMcpServerConnector: Membatasi pembuatan konektor data yang menggunakan server MCP kustom (custom_mcp) sebagai sumber data (diterapkan secara default).
  • discoveryengine.managed.allowedEgressFqdns: Membatasi domain keluar (FQDN instance_uri) untuk konektor data saat Kontrol Layanan VPC (VPC-SC) aktif atau project tercantum di enforcedProjects.
  • discoveryengine.managed.allowedDataSources: Membatasi jenis konektor data yang diizinkan (dataSource) saat VPC-SC aktif atau project tercantum di enforcedProjects.

Ganti batasan kebijakan organisasi yang diwarisi di tingkat project.

Menonaktifkan batasan MCP kustom

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

Menonaktifkan batasan konektor data bersyarat

# disable egress fqdn constraint on project
gcloud org-policies set-policy "/dev/stdin" <<EOF
name: projects/${PROJ_ID}/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_ID}/policies/discoveryengine.managed.allowedDataSources
spec:
  rules:
  - enforce: false
EOF

Menonaktifkan batasan kebijakan akses

# 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

Mengizinkan alamat IP eksternal

# allow external ip address for vms on project
gcloud org-policies set-policy "/dev/stdin" <<EOF
name: projects/${PROJ_ID}/policies/compute.vmExternalIpAccess
spec:
  rules:
  - allowAll: true
EOF

Memverifikasi kebijakan organisasi

Pastikan compute.vmExternalIpAccess disetel ke allowAll: True dan kebijakan lainnya adalah enforce: False:

# verify effective org policy constraints on project
for policy in \
  discoveryengine.managed.disableCustomMcpServerConnector \
  discoveryengine.managed.allowedEgressFqdns \
  discoveryengine.managed.allowedDataSources \
  iam.managed.disableAccessPolicyBinding \
  compute.vmExternalIpAccess; do
  gcloud org-policies describe ${policy} \
    --project=${PROJ_ID} \
    --effective \
    --format="flattened[no-pad](name.basename(),spec.rules[0])"
done

Memverifikasi binding agen layanan (sebagai tindakan pencegahan)

Di project baru, Google Cloud akan otomatis menyediakan agen layanan Agent Gateway dan memberikan roles/agentgateway.serviceAgent saat networkservices.googleapis.com diaktifkan untuk pertama kalinya. Jika Anda menggunakan kembali project yang ada yang pembersihan sebelumnya mungkin telah menghapus binding agen layanan default, jalankan perintah berikut sebagai tindakan antisipasi untuk memastikan binding identitas dan peran tetap utuh:

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

Ini mengakhiri bagian penyiapan... selanjutnya ke bagian Network.

4. Jaringan

Di bagian ini, Anda akan mencadangkan alamat IPv4 eksternal statis, membuat jaringan VPC egress internal dan jaringan VPC eksternal terisolasi, menyediakan lampiran jaringan PSC, mengonfigurasi Cloud NAT, dan membuat aturan firewall.

Mereservasi alamat IP eksternal statis

Cadangkan dua alamat IPv4 eksternal statis regional untuk Cloud NAT dan VM server MCP eksternal:

# reserve static external ipv4 address for cloud nat
gcloud compute addresses create ip-${SLUG}-nat \
  --region=${REGION}

# reserve static external ipv4 address for the mcp server
gcloud compute addresses create ip-${SLUG}-mcp \
  --region=${REGION}

Memverifikasi alamat IP eksternal statis

Gemini Enterprise mewajibkan endpoint MCP jarak jauh menggunakan HTTPS dengan sertifikat TLS yang dipercaya secara publik. Daripada mendaftarkan domain kustom untuk lab ini, Anda akan menggunakan sslip.io, layanan DNS sembarang gratis yang me-resolve nama host yang berisi alamat IP (seperti mcp.[IP].sslip.io) langsung kembali ke IP tersebut. Karena Certificate Authority seperti Let's Encrypt tidak menerbitkan sertifikat ke alamat IP kosong, nama host sslip.io ini memberikan nama domain yang valid kepada proxy terbalik Caddy untuk menyediakan sertifikat TLS tepercaya secara otomatis untuk server MCP.

Ekspor kedua alamat IPv4 dan buat nama domain serta URL sslip.io untuk server MCP eksternal:

# export static ip addresses and set vars for domain
export NAT_EXT_IP=$(gcloud compute addresses describe ip-${SLUG}-nat \
  --region=${REGION} \
  --format="value(address)")

export MCP_EXT_IP=$(gcloud compute addresses describe ip-${SLUG}-mcp \
  --region=${REGION} \
  --format="value(address)")

export MCP_DOMAIN="mcp.${MCP_EXT_IP}.sslip.io"
export MCP_URL="https://${MCP_DOMAIN}/mcp"

echo "cloud nat external ip    : ${NAT_EXT_IP}"
echo "mcp server external ip   : ${MCP_EXT_IP}"
echo "mcp url                  : ${MCP_URL}"

Contoh output:

cloud nat external ip    : 203.0.113.10
mcp server external ip   : 203.0.113.20
mcp url                  : https://mcp.203.0.113.20.sslip.io/mcp

Membuat jaringan internal

Jika template konektivitas Agent Gateway dikonfigurasi untuk menggunakan egressNetworkConfig dengan networkAttachment, subnet yang menghosting lampiran jaringan PSC harus berupa blok CIDR /28 dan mengaktifkan Akses Google Pribadi (--enable-private-ip-google-access).

Buat jaringan VPC global untuk keluar dari Agent Gateway internal:

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

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

Membuat aturan firewall internal

Buat kebijakan firewall untuk mengizinkan semua traffic keluar dengan pengelogan diaktifkan. Hal ini akan digunakan untuk memantau traffic keluar dari Agent Gateway ke jaringan VPC internal. Cloud NGFW mendukung tingkatan Essentials dan Standard untuk keamanan jaringan dan pemantauan traffic.

# create fw policy
gcloud compute network-firewall-policies create fw-policy-${SLUG}-internal --global
# create fw policy rule
gcloud compute network-firewall-policies rules create 1001 \
  --description="allow all out and log" \
  --firewall-policy=fw-policy-${SLUG}-internal \
  --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}-internal \
  --firewall-policy=fw-policy-${SLUG}-internal \
  --network=vnet-${SLUG}-internal \
  --global-firewall-policy

Membuat lampiran jaringan PSC

Buat lampiran jaringan Private Service Connect (PSC) yang dikonfigurasi untuk menerima koneksi secara otomatis dari Agent Gateway. Lampiran jaringan membuat sisi koneksi jaringan VPC konsumen untuk ditautkan secara aman dengan sisi produsen Agent Gateway untuk traffic keluar. Untuk mengetahui informasi tambahan tentang persyaratan subnet dan spesifikasi rentang IP, lihat Mengonfigurasi konektivitas VPC.

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

Verifikasi lampiran jaringan PSC

# show psc network attachment details
gcloud compute network-attachments describe psc-na-${REGION}-agw --region=${REGION}

Ambil URI resource lampiran jaringan PSC dan simpan di variabel lingkungan PSC_NA_URI. URI ini akan dirujuk dalam konfigurasi Agent Gateway (networkConfig.egress.networkAttachment) untuk menyediakan Antarmuka PSC untuk traffic keluar jaringan ke jaringan VPC:

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

Buat Cloud NAT

Cloud NAT digunakan untuk menerjemahkan alamat IP sumber traffic keluar Agent Gateway ke alamat IP publik yang dicadangkan untuk perutean melalui internet publik.

Hanya sumber dari subnet lampiran jaringan keluar Agent Gateway yang ditentukan sebagai memenuhi syarat untuk menggunakan Cloud NAT.

# create router for nat
gcloud compute routers create cr-nat-${SLUG}-${REGION} \
  --network=vnet-${SLUG}-internal \
  --asn=16550 \
  --region=${REGION}

# create nat
gcloud compute routers nats create nat-${SLUG}-${REGION} \
  --router=cr-nat-${SLUG}-${REGION} \
  --region=${REGION} \
  --nat-custom-subnet-ip-ranges="subnet-${REGION}-agw" \
  --nat-external-ip-pool="ip-${SLUG}-nat" \
  --enable-logging \
  --log-filter=ALL

Memverifikasi Cloud NAT

Periksa status Cloud NAT dan pastikan sumber natIP yang diharapkan telah dikonfigurasi:

# verify cloud nat configuration
gcloud compute routers nats describe nat-${SLUG}-${REGION} \
  --router=cr-nat-${SLUG}-${REGION} \
  --region=${REGION} \
  --format="yaml(name,natIps,subnetworks.name)"

Contoh output:

name: nat-foo-us-central1
natIps:
- https://www.googleapis.com/compute/v1/projects/[PROJ_ID]/regions/us-central1/addresses/ip-foo-nat

Membuat jaringan eksternal

Buat jaringan VPC terpisah dan terisolasi untuk menghosting VM server MCP eksternal.

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

# create subnet for mcp server
gcloud compute networks subnets create subnet-${REGION}-mcp \
  --network=vnet-${SLUG}-external \
  --range=240.240.240.0/24 \
  --region=${REGION} \
  --enable-private-ip-google-access

Membuat aturan firewall eksternal

Buat dua aturan firewall ingress di jaringan VPC eksternal:

  • 2001: Mengizinkan port TCP masuk 80 sehingga Let's Encrypt dapat menyelesaikan tantangan validasi domain ACME HTTP-01 untuk ${MCP_DOMAIN}.
  • 2002: Awalnya mengizinkan port TCP masuk 443 dari 0.0.0.0/0 untuk memverifikasi kesiapan TLS dan penerapan tokeninfo OAuth 2.0 dari shell lokal sebelum menguncinya secara ketat ke ${NAT_EXT_IP}/32.
# create fw policy
gcloud compute network-firewall-policies create fw-policy-${SLUG}-external --global
# create fw policy rules
gcloud compute network-firewall-policies rules create 2001 \
  --description="allow in any http" \
  --firewall-policy=fw-policy-${SLUG}-external \
  --global-firewall-policy \
  --action=allow \
  --direction=INGRESS \
  --layer4-configs=tcp:80 \
  --src-ip-ranges=0.0.0.0/0 \
  --dest-ip-ranges=240.240.240.0/24 \
  --enable-logging

gcloud compute network-firewall-policies rules create 2002 \
  --description="allow in any https" \
  --firewall-policy=fw-policy-${SLUG}-external \
  --global-firewall-policy \
  --action=allow \
  --direction=INGRESS \
  --layer4-configs=tcp:443 \
  --src-ip-ranges=0.0.0.0/0 \
  --dest-ip-ranges=240.240.240.0/24 \
  --enable-logging
# bind fw policy to network
gcloud compute network-firewall-policies associations create \
  --name=fw-policy-bind-${SLUG}-external \
  --firewall-policy=fw-policy-${SLUG}-external \
  --network=vnet-${SLUG}-external \
  --global-firewall-policy

Bagian jaringan ini telah selesai... selanjutnya ke bagian Agent Gateway.

5. Agent Gateway

Di bagian ini, Anda akan men-deploy Agent Connectivity Template dengan vpcEgress: ALL_TRAFFIC, men-deploy Agent Gateway regional, mendelegasikan otorisasi ke Identity-Aware Proxy (IAP), dan menentukan aturan Kebijakan Akses Terpadu IAM untuk mengatur permintaan jaringan keluar.

Membuat template konektivitas

Spesifikasi template konektivitas menentukan:

  • egressNetworkConfig.networkAttachment: Menunjuk ke lampiran jaringan PSC, yang menghubungkan Agent Gateway ke jaringan VPC Anda.
  • egressNetworkConfig.vpcEgress: Setel ke ALL_TRAFFIC agar semua koneksi agen keluar (termasuk endpoint MCP internet publik) akan dirutekan ke jaringan VPC dan keluar menggunakan terjemahan alamat IP sumber Cloud NAT.

Buat dan impor file konfigurasi template konektivitas:

# create connectivity template config file (vpcEgress: ALL_TRAFFIC)
cat > cfg/act-${AGW_NAME}.yaml << EOF
accessPath: AGENT_TO_ANYWHERE
name: projects/${PROJ_NO}/locations/${REGION}/agentConnectivityTemplates/act-${AGW_NAME}
deploymentModel: CENTRALIZED
egressNetworkConfig:
  networkAttachment: ${PSC_NA_URI}
  vpcEgress: ALL_TRAFFIC
EOF
# import connectivity template file (create template)
gcloud network-services agent-connectivity-templates import act-${AGW_NAME} \
  --source="cfg/act-${AGW_NAME}.yaml" \
  --location=${REGION}

Buat Agent Gateway

Spesifikasi Agent Gateway menentukan:

  • agentConnectivityTemplate: Menunjuk ke template konektivitas, sehingga gateway dapat menggunakan lampiran jaringan PSC untuk konektivitas VPC.
  • registries: Mengaitkan gateway dengan Agent Registry regional untuk menyelesaikan skema alat dan endpoint MCP yang dikatalogkan.

Buat dan impor file konfigurasi Agent Gateway:

# create agent gateway config file
cat > cfg/${AGW_NAME}.yaml << EOF
name: ${AGW_NAME}
protocols:
  - MCP
googleManaged:
  governedAccessPath: AGENT_TO_ANYWHERE
agentConnectivityTemplate: projects/${PROJ_NO}/locations/${REGION}/agentConnectivityTemplates/act-${AGW_NAME}
registries:
  - "//agentregistry.googleapis.com/projects/${PROJ_ID}/locations/${REGION}"
EOF
# import agent gateway config file (create gateway)
gcloud network-services agent-gateways import ${AGW_NAME} \
  --source="cfg/${AGW_NAME}.yaml" \
  --location=${REGION}

Memverifikasi deployment Agent Gateway

Konfirmasi konfigurasi template konektivitas dan Agent Registry:

# verify agent gateway deployment details
gcloud network-services agent-gateways describe ${AGW_NAME} \
  --location=${REGION} \
  --format="yaml(name,agentConnectivityTemplate,registries)"

Contoh output:

agentConnectivityTemplate: projects/[PROJ_NO]/locations/us-central1/agentConnectivityTemplates/act-foo-us-central1
name: projects/[PROJ_ID]/locations/us-central1/agentGateways/agw-foo-us-central1-ata
registries:
- //agentregistry.googleapis.com/projects/[PROJ_ID]/locations/us-central1

Periksa lampiran jaringan PSC untuk mengonfirmasi koneksi gateway:

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

Contoh output:

connectionEndpoints:
- ipAddress: 10.10.10.2
  projectIdOrNum: '[TENANT_PROJ_NO]'
  status: ACCEPTED
  subnetwork: https://www.googleapis.com/compute/v1/projects/[PROJ_ID]/regions/us-central1/subnetworks/subnet-us-central1-agw

Mendelegasikan otorisasi

Agent Gateway mengamankan dan mengatur traffic alat keluar menggunakan Kebijakan Otorisasi (networksecurity.authzPolicies) yang terintegrasi dengan Kebijakan Akses Terpadu (UAP) Identity-Aware Proxy (IAP).

Meskipun Agent Gateway mendukung aturan inline ALLOW dan DENY dasar, lingkungan perusahaan memerlukan tata kelola terpusat yang berfokus pada identitas. Dengan Kebijakan Akses Terpadu IAM (atau Kebijakan Akses), Anda dapat mengelola aturan akses keluar menggunakan kebijakan akses IAM v3 standar.

figure3

Gambar 3. Arsitektur otorisasi

Alur otorisasi menghubungkan tiga komponen:

  1. Kebijakan otorisasi gateway (authzPolicy):
    • Resource regional yang menargetkan Agent Gateway.
    • Dikonfigurasi dengan policyProfile: REQUEST_AUTHZ dan action: CUSTOM untuk merutekan semua pemeriksaan otorisasi keluar ke ekstensi otorisasi IAP.
  2. Ekstensi layanan IAP (authzExtension):
    • Resource regional yang mendelegasikan otorisasi permintaan ke Identity-Aware Proxy (iap.googleapis.com).
    • Mengevaluasi kebijakan dalam mode ENFORCE menggunakan versi kebijakan V2.
  3. Kebijakan dan Binding Akses Terpadu IAM (accessPolicy & policyBinding):
    • Resource IAM v3 global yang berisi aturan akses terperinci.
    • Mengautentikasi identitas utama SPIFFE dari agen yang memanggil, memverifikasi izin iap.googleapis.com/resources.egressViaIAP universal, dan mengevaluasi kondisi Common Expression Language (CEL) terhadap atribut tujuan.

Men-deploy ekstensi otorisasi

# 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 authz extension config file (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}

Memverifikasi ekstensi otorisasi

Periksa apakah ekstensi otorisasi aktif:

# list authz extensions
gcloud service-extensions authz-extensions list \
  --location=${REGION} \
  --format="table(
    name.basename():label=NAME,
    createTime.date(tz=LOCAL):label=CREATED,
    service:label=SERVICE,
    metadata:label=METADATA,
    timeout:label=TIMEOUT
  )"

Men-deploy kebijakan otorisasi

Buat konfigurasi kebijakan otorisasi network-security yang menargetkan Agent Gateway dan mendelegasikan verifikasi permintaan ke ekstensi otorisasi untuk IAP:

# create authz policy config file
cat > cfg/${AGW_NAME}-authz-policy-iap.yaml << EOF
name: ${AGW_NAME}-authz-policy-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"
EOF
# import authz policy config file (create authz policy)
gcloud network-security authz-policies import ${AGW_NAME}-authz-policy-iap \
  --source=cfg/${AGW_NAME}-authz-policy-iap.yaml \
  --location=${REGION}

Memverifikasi kebijakan otorisasi

Periksa apakah kebijakan otorisasi aktif:

# list authz policies
gcloud network-security authz-policies list \
  --location=${REGION} \
  --format="table(
    name.basename():label=NAME,
    action:label=ACTION,
    policyProfile:label=POLICY_PROFILE,
    customProvider.authzExtension.resources[0].basename():label=CUSTOM_PROVIDER_RESOURCE
  )"

Membuat kebijakan akses IAM

Agent Gateway kini mendelegasikan pemeriksaan otorisasi ke IAP dan menyelesaikan metadata tujuan dari Agent Registry. Selanjutnya, tentukan aturan Kebijakan Akses Terpadu IAM untuk mengatur eksekusi alat keluar.

IAP mengevaluasi ekspresi atribut CEL berdasarkan atribut tujuan Agent Registry berikut:

  • Status terdaftar (destination.is_registered):
    • Boolean (true/false) yang menunjukkan apakah tujuan dicatat dalam Agent Registry.
  • Nama server MCP (destination.agent_registry.mcp_server.name):
    • Nama resource server MCP kanonis yang terdaftar di Agent Registry.
  • Metode MCP (destination.agent_registry.mcp_server.method):
    • Metode MCP yang dipanggil (misalnya, tools/call, tools/list, initialize).
  • Nama alat (destination.agent_registry.mcp_server.tool.name):
    • Nama alat spesifik yang dipanggil (misalnya, get_sprocket_by_id atau get_sprockets), yang memungkinkan otorisasi tingkat alat yang terperinci di server MCP terdaftar.

Menentukan aturan kebijakan akses IAM

Manifes aturan kebijakan IAM menentukan:

  • Principal: Identitas principal SPIFFE yang merepresentasikan agen asisten inti Gemini Enterprise.
  • Izin: Izin iap.googleapis.com/resources.egressViaIAP universal yang diperlukan untuk semua traffic keluar yang diatur IAP.
  • Kondisi: Ekspresi CEL (destination.is_registered == true) yang memastikan agen hanya dapat memanggil endpoint yang tercantum dalam Agent Registry.

Buat file manifes aturan kebijakan:

# create access policy rule file
cat > cfg/uap-policy-${SLUG}-rules.json << EOF
[
  {
    "description": "allow ge assistant to any registered service",
    "effect": "ALLOW",
    "principals": [
      "principal://${TRUST_DOMAIN}/resources/discoveryengine/projects/${PROJ_NO}/locations/global/engines/${GE_APP_INIT}/assistants/default_assistant/agents/default/core_assistant"
    ],
    "operation": {
      "permissions": [
        "iap.googleapis.com/resources.egressViaIAP"
      ]
    },
    "conditions": {
      "iap.googleapis.com": {
        "expression": \
        "destination.is_registered == true"
      }
    }
  }
]
EOF

Men-deploy kebijakan akses IAM

Buat kebijakan akses IAM global menggunakan aturan yang ditentukan dalam file manifes:

# create iam access policy
gcloud iam access-policies create uap-policy-${SLUG} \
  --details-rules=cfg/uap-policy-${SLUG}-rules.json \
  --project=${PROJ_ID} \
  --location=global

Memverifikasi kebijakan akses IAM

Periksa apakah kebijakan akses IAM berhasil dibuat dan periksa detail aturan:

# show iam access policy details
gcloud iam access-policies describe uap-policy-${SLUG} \
  --project=${PROJ_ID} \
  --location=global

Contoh output:

details:
  rules:
  - conditions:
      iap.googleapis.com:
        expression: destination.is_registered == true
    description: allow ge assistant to any registered service
    effect: ALLOW
    operation:
      permissions:
      - iap.googleapis.com/resources.egressViaIAP
    principals:
    - principal://agents.global.org-[ORG_ID].system.id.goog/resources/discoveryengine/projects/[PROJ_NO]/locations/global/engines/app-foo-global_[EPOCH]/assistants/default_assistant/agents/default/core_assistant
name: projects/[PROJ_ID]/locations/global/accessPolicies/uap-policy-foo

Mengikat kebijakan akses IAM ke project

Untuk mengaktifkan penerapan di semua Gateway Agen dalam project Anda, buat binding kebijakan yang melampirkan kebijakan akses IAM ke resource project:

# bind iam access policy to project resource
gcloud iam policy-bindings create uap-bind-${SLUG} \
  --policy="projects/${PROJ_ID}/locations/global/accessPolicies/uap-policy-${SLUG}" \
  --target-resource="//cloudresourcemanager.googleapis.com/projects/${PROJ_ID}" \
  --project=${PROJ_ID} \
  --location=global

Memverifikasi binding kebijakan akses IAM

Periksa titik pengikatan kebijakan aktif ke kebijakan dan target yang benar:

# show policy binding details
gcloud iam policy-bindings describe uap-bind-${SLUG} \
  --project=${PROJ_ID} \
  --location=global

Bagian Agent Gateway telah selesai... selanjutnya ke bagian server MCP.

6. Server MCP

Di bagian ini, Anda akan men-deploy Server Resource OAuth 2.0 FastMCP eksternal (mcp-sprockets) yang mengekspos alat get_sprockets dan get_sprocket_by_id, serta memverifikasi bahwa server tersebut memvalidasi token Bearer OAuth 2.0 Google secara kriptografis terhadap https://oauth2.googleapis.com/tokeninfo. Selanjutnya, Anda akan mengunci aturan firewall eksternal secara ketat ke IP statis Cloud NAT.

Men-deploy server MCP eksternal

Skrip startup menginstal Caddy dan FastMCP, meluncurkan server mcp-sprockets di 127.0.0.1:8080, dan mengonfigurasi Caddy untuk menayangkan HTTPS di ${MCP_DOMAIN}.

Setiap kali Gemini Enterprise memanggil alat MCP (misalnya, get_sprockets dan get_sprocket_by_id), server akan:

  1. Membaca IP sumber pemanggil dari header X-Forwarded-For (egress_source_ip).
  2. Ekstrak header Authorization: Bearer [access_token] dan verifikasi token terhadap endpoint verifikasi Google OAuth 2.0 (https://oauth2.googleapis.com/tokeninfo?access_token=[token]).
  3. Mengembalikan "authenticated_user" ([user_email]) bersama "egress_source_ip", yang membuktikan bahwa server MCP eksternal memverifikasi IP statis Cloud NAT dan identitas OAuth 2.0 Google pengguna akhir.
# create startup script for the sprockets mcp server vm
cat > cfg/server-startup.sh << 'EOF'
#!/bin/bash
set -euo pipefail

MCP_DOMAIN=$(curl -s -H "Metadata-Flavor: Google" \
  http://metadata.google.internal/computeMetadata/v1/instance/attributes/mcp-domain)

export DEBIAN_FRONTEND=noninteractive
apt-get update -y
apt-get install -y caddy python3-venv curl

mkdir -p /opt/mcp-sprockets
python3 -m venv /opt/mcp-sprockets/venv
/opt/mcp-sprockets/venv/bin/pip install --upgrade pip
/opt/mcp-sprockets/venv/bin/pip install "fastmcp>=2.14.0" "uvicorn>=0.34.0"

cat <<'PYEOF' > /opt/mcp-sprockets/main.py
import json
import urllib.parse
import urllib.request
from typing import Any, Dict
from fastmcp import FastMCP
from fastmcp.server.dependencies import get_http_headers
from mcp.types import ToolAnnotations

mcp = FastMCP("mcp-sprockets")

SPROCKETS = {
    "SPK-101": {"id": "SPK-101", "model": "ANSI-40-12T", "teeth": 12, "pitch_in": 0.5, "material": "1045 Carbon Steel", "stock": 140, "unit_price": 18.50},
    "SPK-102": {"id": "SPK-102", "model": "ANSI-40-24T", "teeth": 24, "pitch_in": 0.5, "material": "1045 Carbon Steel", "stock": 85, "unit_price": 29.00},
    "SPK-103": {"id": "SPK-103", "model": "ANSI-60-16T", "teeth": 16, "pitch_in": 0.75, "material": "304 Stainless Steel", "stock": 60, "unit_price": 42.00},
    "SPK-104": {"id": "SPK-104", "model": "ANSI-60-32T", "teeth": 32, "pitch_in": 0.75, "material": "304 Stainless Steel", "stock": 35, "unit_price": 68.00},
    "SPK-105": {"id": "SPK-105", "model": "ANSI-80-20T", "teeth": 20, "pitch_in": 1.0, "material": "4140 Alloy Steel", "stock": 50, "unit_price": 95.00}
}

def verify_google_oauth_token(headers: Dict[str, str]) -> str:
    token = headers.get("authorization", "")[7:].strip() if headers.get("authorization", "").lower().startswith("bearer ") else ""
    if not token:
        return "unauthenticated (missing Bearer token)"
    url = "https://oauth2.googleapis.com/tokeninfo?" + urllib.parse.urlencode({"access_token": token})
    with urllib.request.urlopen(url, timeout=5) as resp:
        info = json.loads(resp.read().decode("utf-8"))
        return info.get("email", info.get("sub", "verified-oauth-user"))

@mcp.tool(
    description="list all sprockets in the inventory catalog",
    annotations=ToolAnnotations(
        readOnlyHint=True,
        destructiveHint=False,
        idempotentHint=True,
        openWorldHint=False
    )
)
def get_sprockets() -> Dict[str, Any]:
    headers = get_http_headers(include_all=True)
    caller_ip = headers.get("x-forwarded-for", "unknown").split(",")[0].strip()
    try:
        user_email = verify_google_oauth_token(headers)
    except Exception as exc:
        return {"egress_source_ip": caller_ip, "authenticated_user": None, "error": f"OAuth token verification failed: {exc}"}
    return {
        "egress_source_ip": caller_ip,
        "authenticated_user": user_email,
        "sprockets": list(SPROCKETS.values())
    }

@mcp.tool(
    description="fetch details of a specific sprocket by its ID (eg, SPK-101)",
    annotations=ToolAnnotations(
        readOnlyHint=True,
        destructiveHint=False,
        idempotentHint=True,
        openWorldHint=False
    )
)
def get_sprocket_by_id(sprocket_id: str) -> Dict[str, Any]:
    headers = get_http_headers(include_all=True)
    caller_ip = headers.get("x-forwarded-for", "unknown").split(",")[0].strip()
    try:
        user_email = verify_google_oauth_token(headers)
    except Exception as exc:
        return {"egress_source_ip": caller_ip, "authenticated_user": None, "error": f"OAuth token verification failed: {exc}"}
    sprocket = SPROCKETS.get(sprocket_id.upper())
    if sprocket:
        return {
            "egress_source_ip": caller_ip,
            "authenticated_user": user_email,
            "sprocket": sprocket
        }
    return {
        "egress_source_ip": caller_ip,
        "authenticated_user": user_email,
        "error": f"Sprocket '{sprocket_id}' not found."
    }

app = mcp.http_app(stateless_http=True)
PYEOF

cat <<'SVCEOF' > /etc/systemd/system/mcp-sprockets.service
[Unit]
Description=Sprockets FastMCP Server
After=network.target

[Service]
Type=simple
WorkingDirectory=/opt/mcp-sprockets
ExecStart=/opt/mcp-sprockets/venv/bin/uvicorn main:app --host 127.0.0.1 --port 8080 --forwarded-allow-ips="*"
Restart=always

[Install]
WantedBy=multi-user.target
SVCEOF

systemctl daemon-reload
systemctl enable --now mcp-sprockets.service
systemctl restart mcp-sprockets.service

cat <<CADDYEOF > "/etc/caddy/Caddyfile"
${MCP_DOMAIN} {
    reverse_proxy 127.0.0.1:8080
}
CADDYEOF

systemctl restart caddy
EOF
# create vm instance
gcloud compute instances create vm-${MCP_NAME} \
  --zone=${ZONE} \
  --machine-type=e2-micro \
  --image-family=debian-12 \
  --image-project=debian-cloud \
  --shielded-secure-boot \
  --network-interface="subnet=subnet-${REGION}-mcp,address=${MCP_EXT_IP}" \
  --metadata="mcp-domain=${MCP_DOMAIN}" \
  --metadata-from-file="startup-script=cfg/server-startup.sh"

Memverifikasi kesiapan server MCP dan validasi tokeninfo OAuth 2.0

Tunggu beberapa menit hingga skrip startup menginstal FastMCP dan Caddy serta menyediakan sertifikat TLS Let's Encrypt.

# poll until caddy serves valid tls and fastmcp responds to tools/list
for i in $(seq 1 30); do
  RESP=$(curl -s -X POST "${MCP_URL}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json, text/event-stream" \
    -d '{"jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {}}' || true)
  if echo "${RESP}" | grep -q "get_sprockets"; then
    echo "mcp server and let's encrypt tls ready"
    break
  fi
  echo "...waiting for mcp server and let's encrypt tls (attempt ${i}/30)..."
  sleep 5
done

Validasi resolusi DNS sslip.io, sertifikat TLS Let's Encrypt yang ditayangkan oleh Caddy, dan respons FastMCP tools/list:

# query mcp server for tools list
curl -v -X POST "${MCP_URL}" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {}}' \
  2>&1 | grep -E "Connected to|subject:|issuer:|SSL certificate|HTTP/|event:|data:"

Contoh output:

* Connected to mcp.203.0.113.20.sslip.io (203.0.113.20) port 443
*  subject: CN=mcp.203.0.113.20.sslip.io
*  issuer: C=US; O=Let's Encrypt; CN=E5
*  SSL certificate verify ok.
> POST /mcp HTTP/2
< HTTP/2 200
event: message
data: {"jsonrpc":"2.0","id":1,"result":{"tools":[{"name":"get_sprockets","description":"list all sprockets in the inventory catalog","inputSchema":{"properties":{},"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true}},{"name":"get_sprocket_by_id","description":"fetch details of a specific sprocket by its ID (eg, SPK-101)","inputSchema":{"properties":{"sprocket_id":{"type":"string"}},"required":["sprocket_id"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true}}]}}

Sebelum mengamankan firewall eksternal, jalankan pengujian tools/call yang meneruskan token Bearer OAuth 2.0 Google (gcloud auth print-access-token) untuk memverifikasi bahwa mcp-sprockets memvalidasi token terhadap https://oauth2.googleapis.com/tokeninfo dan menampilkan email "authenticated_user" Anda bersama dengan alamat IP sumber pemanggil:

# query mcp server (test tools/call with google oauth 2.0 bearer token)
curl -s -X POST "${MCP_URL}" \
  -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/call",
    "params": {
      "name": "get_sprocket_by_id",
      "arguments": {"sprocket_id": "SPK-105"}
    }
  }' | sed -n 's/^data: //p' | jq '.result.structuredContent'

Contoh output (menampilkan IP Cloud Shell langsung Anda sebelum penguncian firewall dan email Google OAuth terverifikasi Anda):

{
  "egress_source_ip": "198.51.100.154",
  "authenticated_user": "user@example.com",
  "sprocket": {
    "id": "SPK-105",
    "model": "ANSI-80-20T",
    "teeth": 20,
    "pitch_in": 1.0,
    "material": "4140 Alloy Steel",
    "stock": 50,
    "unit_price": 95.0
  }
}

Mengunci firewall ke IP statis Cloud NAT

Perbarui kebijakan firewall jaringan VPC eksternal sehingga port TCP 443 menerima traffic hanya dari IP eksternal statis Cloud NAT (${NAT_EXT_IP}/32):

# create fw policy rule allowing https only from cloud nat static ip
gcloud compute network-firewall-policies rules create 2003 \
  --description="allow in any https from nat ip" \
  --firewall-policy=fw-policy-${SLUG}-external \
  --global-firewall-policy \
  --action=allow \
  --direction=INGRESS \
  --layer4-configs=tcp:443 \
  --src-ip-ranges="${NAT_EXT_IP}/32" \
  --dest-ip-ranges=240.240.240.0/24 \
  --enable-logging
# delete temporary open fw policy rules
gcloud compute network-firewall-policies rules delete 2001 \
  --firewall-policy=fw-policy-${SLUG}-external \
  --global-firewall-policy

gcloud compute network-firewall-policies rules delete 2002 \
  --firewall-policy=fw-policy-${SLUG}-external \
  --global-firewall-policy

Periksa apakah aturan kebijakan firewall eksternal sudah diterapkan:

# list all rules in the global network firewall policy
gcloud compute network-firewall-policies describe fw-policy-${SLUG}-external \
  --global \
  --flatten="rules[]" \
  --format="table(
    rules.priority:label=RULE,
    rules.action:label=ACTION,
    rules.direction:label=DIRECTION,
    firstof(
      rules.match.srcIpRanges,
      rules.match.srcAddressGroups,
      rules.match.srcSecureTags.name
    ).map().sub('projects/[^/]+/(locations/global/|global/)', '').list():label=SRC,
    firstof(
      rules.targetForwardingRules,
      rules.match.destIpRanges,
      rules.targetType
    ).map().sub('projects/[^/]+/(locations/global/|global/)', '').list():label=DST
  )"

Pastikan koneksi langsung di luar IP statis Cloud NAT kini diblokir:

# query mcp server
curl -i --connect-timeout 5 "${MCP_URL}" \
  || echo "Expected: Direct access blocked (not originating from ${NAT_EXT_IP})"

Contoh output:

curl: (28) Connection timed out after 5001 milliseconds
Expected: Direct access blocked (not originating from 203.0.113.10)

Bagian server MCP ini telah selesai... selanjutnya ke bagian Agent Registry.

7. Agent Registry

Agent Registry adalah inventaris terpusat dari semua agen, server MCP, dan endpoint (API) dalam ekosistem AI. Tool Registry juga merupakan katalog yang dapat digunakan untuk mencantumkan, menelusuri, dan menemukan alat serta layanan terdaftar lainnya untuk digunakan oleh aplikasi AI. Agent Gateway menggunakan model data registri sebagai framework tata kelola untuk menerapkan kontrol akses keluar. Pemberian peran IAM untuk agen panggilan utama diperiksa berdasarkan kebijakan yang terikat ke resource registry.

Di bagian ini, Anda akan mendaftarkan server MCP dan skema alatnya (toolspec.json) di Agent Registry. Untuk mendukung interaksi Gemini Enterprise dengan API dan Layanan Google melalui Agent Gateway, Anda juga akan membuat satu layanan endpoint registri (oauth2-googleapis) yang menentukan antarmuka Google API yang digunakan oleh Gemini Enterprise untuk menukar kode auth dengan token.

Mendaftarkan server MCP

Agar Gemini Enterprise dapat menemukan alat yang tersedia di server MCP, berikan file spesifikasi alat (cfg/toolspec.json) saat mendaftarkan layanan di Agent Registry.

Buat spesifikasi alat MCP

# create tool spec file for the sprockets mcp server
cat <<'EOF' > cfg/toolspec.json
{
  "tools": [
    {
      "name": "get_sprockets",
      "description": "List all sprockets in the inventory catalog.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      },
      "isReadOnly": true,
      "isDestructive": false,
      "isIdempotent": true,
      "isOpenWorld": false
    },
    {
      "name": "get_sprocket_by_id",
      "description": "Fetch details of a specific sprocket by its ID (e.g., SPK-101).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "sprocket_id": {
            "type": "string",
            "description": "The sprocket identifier (e.g., SPK-101, SPK-105)."
          }
        },
        "required": [
          "sprocket_id"
        ]
      },
      "isReadOnly": true,
      "isDestructive": false,
      "isIdempotent": true,
      "isOpenWorld": false
    }
  ]
}
EOF

Membuat layanan server MCP

# create registry service (mcp server)
gcloud agent-registry services create ${MCP_NAME} \
  --project=${PROJ_ID} \
  --location=${REGION} \
  --display-name="${MCP_DOMAIN}" \
  --description="MANDATORY SPROCKETS INVENTORY & CATALOG AGENT: You MUST \
ALWAYS invoke this tool (get_sprockets or get_sprocket_by_id) for ANY question \
about sprockets, inventory catalog listings, sprocket IDs (SPK-101 through \
SPK-105), ANSI models (ANSI-40, ANSI-60, ANSI-80), tooth counts, pitch, \
material, stock levels, unit prices, authenticated_user, or egress_source_ip \
verification. NEVER guess or fabricate inventory data yourself and NEVER \
transfer sprocket queries to file_and_coding_agent or web search. Always \
delegate every sprocket or inventory lookup to this tool." \
  --mcp-server-spec-type=tool-spec \
  --mcp-server-spec-content=cfg/toolspec.json \
  --interfaces=protocolBinding=JSONRPC,url="${MCP_URL}"

Memverifikasi server MCP di Agent Registry

Pastikan layanan tercantum sebagai server MCP terdaftar di region bersama dengan URL endpoint dan alat yang tersedia:

# list registry regional mcp servers
gcloud agent-registry mcp-servers list \
  --location=${REGION} \
  --project=${PROJ_ID} \
  --format="table(
    name.basename():label=REGISTRY_ID,
    displayName:label=DISPLAY_NAME,
    interfaces[0].url:label=ENDPOINT_URL,
    tools[].name.list():label=TOOLS
  )"

Contoh output:

REGISTRY_ID                                          DISPLAY_NAME               ENDPOINT_URL                          TOOLS
agentregistry-00000000-0000-0000-5c39-1f6e542bb2b8   mcp.203.0.113.20.sslip.io  https://mcp.203.0.113.20.sslip.io/mcp  get_sprockets,get_sprocket_by_id

Lihat spesifikasi konfigurasi layanan untuk melihat bahwa layanan tersebut mendaftarkan definisi alat, skema input, dan anotasi perilaku yang tepat untuk setiap alat:

# describe mcp server tool specs
gcloud agent-registry services describe ${MCP_NAME} \
  --location=${REGION} \
  --project=${PROJ_ID} \
  --format="yaml(mcpServerSpec.content.tools)"

Mendaftarkan endpoint OAuth

Agar backend DataConnector Gemini Enterprise (yang bertindak sebagai klien OAuth dalam alur otorisasi) dapat mengirim permintaan POST ke server otorisasi Google OAuth 2.0 (https://oauth2.googleapis.com/token) melalui Agent Gateway, endpoint token harus didaftarkan di Agent Registry agar IAP dapat mengevaluasi destination.is_registered == true.

Membuat layanan endpoint

# create registry service (endpoint)
gcloud agent-registry services create oauth2-googleapis \
  --project=${PROJ_ID} \
  --location=${REGION} \
  --display-name="oauth2.googleapis.com" \
  --description="google oauth2 endpoint" \
  --endpoint-spec-type=no-spec \
  --interfaces=protocolBinding=JSONRPC,url=https://oauth2.googleapis.com

Memverifikasi pendaftaran endpoint

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

Output yang diharapkan:

DISPLAY_NAME           ENDPOINT_ID                                         URL
oauth2.googleapis.com  agentregistry-00000000-0000-0000-0012-3456789abcde  https://oauth2.googleapis.com

Kebijakan akses IAM

Karena kebijakan akses IAM menentukan kebijakan izin untuk layanan terdaftar yang diminta oleh identitas agen core_assistant aplikasi Gemini Enterprise, tidak ada binding kebijakan IAM tambahan yang diperlukan untuk pertukaran token OAuth.

  - conditions:
      iap.googleapis.com:
        expression: destination.is_registered == true
    description: allow ge assistant to any registered service
    effect: ALLOW

Bagian Agent Registry telah selesai... selanjutnya kita akan membahas bagian Gemini Enterprise.

8. Gemini Enterprise

Di bagian ini, Anda akan mengonfigurasi penyedia identitas, lisensi uji coba, dan kredensial klien OAuth 2.0 Google Identity, membuat aplikasi Gemini Enterprise (${GE_APP_ID}), mengikat keluar keluar ke Agent Gateway (${AGW_URI}), dan menghubungkan server MCP sprockets yang terdaftar sebagai penyimpanan data MCP kustom OAuth 2.0.

Membuat aplikasi Gemini Enterprise

Metode berikut menggunakan Gemini API discoveryengine.googleapis.com untuk membuat resource dan konfigurasi aplikasi Gemini Enterprise. Untuk mengonfigurasi menggunakan UI Konsol Google Cloud, lihat Membuat aplikasi untuk mengetahui petunjuknya.

# create engine (ge app)
curl -s -X POST "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines?engineId=${GE_APP_INIT}" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "displayName": "${GE_APP_DISPLAY_NAME}",
  "dataStoreIds": [],
  "solutionType": "SOLUTION_TYPE_SEARCH",
  "industryVertical": "GENERIC",
  "appType": "APP_TYPE_INTRANET",
  "searchEngineConfig": {
    "searchTier": "SEARCH_TIER_ENTERPRISE",
    "searchAddOns": [
      "SEARCH_ADD_ON_LLM"
    ]
  },
  "commonConfig": {
    "companyName": "${GE_APP_ORG_NAME}"
  },
  "observabilityConfig": {
    "observabilityEnabled": true,
    "sensitiveLoggingEnabled": true
  }
}
EOF

Memverifikasi pembuatan aplikasi

# fetch engine (ge app) id
export GE_APP_ID=$(curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" -H "X-Goog-User-Project: ${PROJ_ID}" \
  | jq -r --arg name "${GE_APP_DISPLAY_NAME}" '.engines[] | select(.displayName==$name) | .name | split("/") | last')

echo "engine (ge app) id: ${GE_APP_ID}"

Lihat detail mesin untuk melihat konfigurasi yang dibuat:

# get engine (ge app) details
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}"

Mengaktifkan penyedia identitas

Aktifkan Google Identity sebagai penyedia identitas untuk autentikasi pengguna akhir di aplikasi Gemini Enterprise Anda.

Metode berikut menggunakan discoveryengine.googleapis.com API untuk mengonfigurasi penyedia identitas aplikasi Gemini Enterprise. Untuk mengonfigurasi menggunakan UI Konsol Google Cloud, lihat Mengonfigurasi penyedia identitas untuk mengetahui petunjuknya.

# set identity provider
curl -s -X PATCH "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/aclConfig" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "idpConfig": {
    "idpType": "GSUITE"
  }
}
EOF

Memverifikasi penyedia identitas

# show identity provider
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/aclConfig" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}"

Output "idpType": "GSUITE" sesuai dengan penyedia Google Identity.

(Opsional) Aktifkan lisensi uji coba Gemini Enterprise

Jika Anda menggunakan project yang telah ditetapkan lisensi Gemini Enterprise, Anda dapat melewati langkah ini. Jika Anda menggunakan project baru tanpa lisensi, lanjutkan dan ikuti langkah-langkah berikut.

Buat resource konfigurasi lisensi untuk memberikan hak atas kursi pengguna Gemini Enterprise selama 30 hari. Tindakan ini akan menyetel lisensi default ke uji coba baru, sehingga setiap pengguna yang login akan otomatis diberi tempat:

# configure free trial subscription
curl -s -X POST "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/licenseConfigs?licenseConfigId=free_trial_gemini" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "subscriptionTier": "SUBSCRIPTION_TIER_SEARCH_AND_ASSISTANT",
  "freeTrial": true
}
EOF

Memverifikasi bahwa lisensi telah diterapkan

# show license config
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/licenseConfigs/free_trial_gemini" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}"

Periksa "subscriptionTerm": "SUBSCRIPTION_TERM_ONE_MONTH" dan "freeTrial": true.

# verify auto-registration enabled on default user store
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/userStores/default_user_store" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}"

Periksa ../free_trial_gemini" dan "enableLicenseAutoRegister": true.

Untuk mengizinkan Gemini Enterprise (Klien OAuth 2.0) mendapatkan token Bearer OAuth 2.0 Google yang didelegasikan pengguna dan menyajikannya ke mcp-sprocketsServer Resource atas nama Anda, konfigurasi layar izin OAuth Platform Auth Google dan buat Client ID OAuth 2.0 Aplikasi web di project Anda.

Cetak URL Konsol Google Cloud langsung untuk Ringkasan Google Auth Platform di project Anda:

# print google auth platform consent screen url
echo "https://console.cloud.google.com/auth/overview?project=${PROJ_ID}"
  1. Buka URL di browser Anda, lalu klik Mulai (jika belum dikonfigurasi untuk project Anda).
  2. Di bagian App Information, tetapkan App name ke mcp-sprockets-oauth dan pilih alamat email Anda (${USER_IDENTITY}) sebagai User support email, lalu klik Next.
  3. Di bagian Audience, pilih Internal (direkomendasikan jika akun Anda termasuk dalam organisasi Google Workspace) atau External (jika menggunakan akun pribadi; jika Anda memilih External, tambahkan ${USER_IDENTITY} di bagian **Pengguna Pengujian audiens**), lalu klik Next.
  4. Masukkan alamat email Anda di bagian Contact Information, setujui perjanjian kebijakan, lalu klik Create.

2. Buat Client ID OAuth 2.0 Aplikasi web

Cetak URL Konsol Google Cloud langsung untuk halaman Clients:

# print google auth platform clients url
echo "https://console.cloud.google.com/auth/clients?project=${PROJ_ID}"
  1. Buka URL, lalu klik + Buat klien.
  2. Pilih aplikasi web sebagai Application type dan tetapkan Name ke ge-mcp-sprockets-client.
  3. Centang kotak untuk Klien ini akan digunakan oleh agen yang didukung AI untuk menetapkan klien OAuth bagi alur kerja agen AI yang bertindak atas nama pengguna.
  4. Di bagian Authorized redirect URIs, klik + Add URI, lalu tambahkan URI callback OAuth Gemini Enterprise:
    • https://vertexaisearch.cloud.google.com/oauth-redirect
  5. Klik Create, salin Client ID dan Client secret yang dihasilkan, lalu ekspor keduanya di sesi shell Anda:

Tetapkan client ID dan rahasia klien OAuth 2.0 yang dihasilkan dari langkah sebelumnya:

# set oauth 2.0 client id (paste in id)
export OAUTH_CLIENT_ID="SET_YOUR_OAUTH_CLIENT_ID_HERE"
# set oauth 2.0 client secret (paste in secret)
export OAUTH_CLIENT_SECRET="SET_YOUR_OAUTH_CLIENT_SECRET_HERE"

Periksa apakah client ID telah ditetapkan:

# print oauth 2.0 client id
echo "oauth client id: ${OAUTH_CLIENT_ID}"

Mengikat ke Agent Gateway

Merutekan traffic keluar dari Gemini Enterprise melalui Agent Gateway akan membuat batas perutean IP statis dan penegakan terpusat untuk semua pemanggilan alat agen AI:

  • Penegakan kebijakan terpusat: Agent Gateway bertindak sebagai proxy inline yang mengevaluasi permintaan alat keluar berdasarkan kebijakan otorisasi sebelum traffic keluar dari lingkungan agen.
  • Traffic keluar VPC & Cloud NAT yang deterministik: Mengikat Gemini Enterprise ke Agent Gateway yang dikonfigurasi dengan vpcEgress: ALL_TRAFFIC memastikan panggilan alat dirutekan melalui lampiran jaringan PSC dan keluar menggunakan IP statis Cloud NAT yang Anda cadangkan.
  • Kemampuan audit terpadu: Menyediakan jejak audit dan pencatatan permintaan terpusat di semua server MCP yang terhubung.

Patch mesin agentGatewaySetting untuk mengaktifkan:

# bind engine (ge app) to agent gateway
curl -s -X PATCH "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}?updateMask=agentGatewaySetting.defaultEgressAgentGateway.name" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "agentGatewaySetting": {
    "defaultEgressAgentGateway": {
      "name": "${AGW_URI}"
    }
  }
}
EOF

Memverifikasi binding Agent Gateway

Ambil konfigurasi aplikasi untuk mengonfirmasi pengikatan agentGatewaySetting:

# verify engine (ge app) agent gateway configuration
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}" \
  -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  | jq '{name: .name, displayName: .displayName, agentGatewaySetting: .agentGatewaySetting}'

Contoh output:

{
  "name": "projects/[PROJ_NO]/locations/global/collections/default_collection/engines/app-foo-global_[EPOCH]",
  "displayName": "foo global app",
  "agentGatewaySetting": {
    "defaultEgressAgentGateway": {
      "name": "projects/[PROJ_ID]/locations/us-central1/agentGateways/agw-foo-us-central1-ata"
    }
  }
}

Membuat penyimpanan data server MCP kustom

Di bagian ini, Anda akan menghubungkan server mcp-sprockets ke Gemini Enterprise dengan membuat penyimpanan data MCP kustom OAuth 2.0 yang dikonfigurasi dengan Google Identity (https://accounts.google.com/o/oauth2/v2/auth dan https://oauth2.googleapis.com/token).

Menggunakan Discovery Engine API, proses ini terdiri dari dua langkah:

  1. Buat (:setUpDataConnector): Membuat resource Collection khusus (${MCP_NAME}-collection-%timestamp), melampirkan DataConnector (custom_mcp) dengan auth_type: "OAUTH", dan menyediakan DataStore (..._mcp_data) pendukungnya.
  2. Aktifkan (PATCH .../dataConnector?updateMask=actionConfig): Mengaktifkan runtime tindakan konektor (actionState: "ACTIVE") menggunakan spesifikasi alat Agent Registry, parameter OAuth 2.0 Google Identity, dan mengikat DataStore (dataStoreIds) ke Engine Gemini Enterprise Anda.
# fetch mcp server agent registry resource name
export MCP_REGISTRY_URI=$(gcloud agent-registry mcp-servers list \
  --location=${REGION} \
  --project=${PROJ_ID} \
  --filter="displayName:${MCP_DOMAIN}" \
  --format="value(name)")

echo "mcp registry name: ${MCP_REGISTRY_URI}"
echo "mcp url: ${MCP_URL}"

Membuat konektor data

# create custom mcp data connector with google identity oauth 2.0 and link to engine
curl -s -X POST "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/${GE_LOCATION}:setUpDataConnector" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "collectionId": "${MCP_NAME}-collection-$(date +%s)",
  "collectionDisplayName": "${MCP_NAME}-collection",
  "dataConnector": {
    "dataSource": "custom_mcp",
    "dataSourceVersion": 1,
    "params": {
      "oauth_access_token": "unused"
    },
    "refreshInterval": "86400s",
    "entities": [
      {
        "entityName": "mcp_data"
      }
    ],
    "connectorModes": [
      "FEDERATED"
    ],
    "actionConfig": {
      "isActionConfigured": true,
      "createBapConnection": true,
      "actionParams": {
        "auth_type": "OAUTH",
        "instance_uri": "${MCP_URL}",
        "auth_uri": "https://accounts.google.com/o/oauth2/v2/auth",
        "auth_uri_params": "&access_type=offline&prompt=consent",
        "token_uri": "https://oauth2.googleapis.com/token",
        "client_id": "${OAUTH_CLIENT_ID}",
        "client_secret": "${OAUTH_CLIENT_SECRET}",
        "scopes": "openid email profile",
        "client_secret_basic_override": true,
        "mcp_server_source": "REGISTRY_MCP",
        "registry_mcp_server_name": "${MCP_REGISTRY_URI}",
        "mcp_agent_instructions": "MANDATORY SPROCKETS INVENTORY & CATALOG AGENT: Always invoke get_sprockets or get_sprocket_by_id for any question about sprockets, inventory catalog listings, sprocket IDs (SPK-101 through SPK-105), ANSI models (ANSI-40, ANSI-60, ANSI-80), tooth counts, pitch, material, stock levels, unit prices, authenticated_user, or egress_source_ip verification.",
        "use_agent_gateway_egress": true,
        "agent_gateway_engine": "projects/${PROJ_ID}/locations/global/collections/default_collection/engines/${GE_APP_ID}"
      }
    }
  }
}
EOF

Memverifikasi pembuatan konektor data

# fetch collection id
export GE_COLLECTION_ID=$(curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  | jq -r --arg dname "${MCP_NAME}-collection" '.collections[] | select(.displayName == $dname) | .name | split("/") | last' | head -n 1)

echo "ge collection id: ${GE_COLLECTION_ID}"

Periksa apakah kolom "registry_mcp_server_name" diisi dengan UUID Agent Registry untuk server MCP dan "auth_type" adalah OAUTH:

# show data connector details
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/${GE_COLLECTION_ID}/dataConnector" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  | jq '{name, state, actionState, connectorModes, bapConfig, auth_type: .actionConfig.actionParams.auth_type, registry_mcp_server_name: .actionConfig.actionParams.registry_mcp_server_name}'

Lihat entri pendaftaran server MCP di UI Konsol Google Cloud:

echo "mcp server registry page url: https://console.cloud.google.com/agent-platform/agent-registry/mcp-servers/${REGION}/${MCP_REGISTRY_URI##*/}/overview?project=${PROJ_ID}"

Mengaktifkan konektor data

# activate and bind data connector with google identity oauth 2.0
curl -s -X PATCH "https://discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/global/collections/${GE_COLLECTION_ID}/dataConnector?updateMask=actionConfig" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "name": "projects/${PROJ_ID}/locations/global/collections/${GE_COLLECTION_ID}/dataConnector",
  "actionConfig": {
    "isActionConfigured": true,
    "createBapConnection": true,
    "actionParams": {
      "auth_type": "OAUTH",
      "instance_uri": "${MCP_URL}",
      "auth_uri": "https://accounts.google.com/o/oauth2/v2/auth",
      "auth_uri_params": "&access_type=offline&prompt=consent",
      "token_uri": "https://oauth2.googleapis.com/token",
      "client_id": "${OAUTH_CLIENT_ID}",
      "client_secret": "${OAUTH_CLIENT_SECRET}",
      "scopes": "openid email profile",
      "client_secret_basic_override": true,
      "mcp_server_source": "REGISTRY_MCP",
      "registry_mcp_server_name": "${MCP_REGISTRY_URI}",
      "mcp_agent_instructions": "MANDATORY SPROCKETS INVENTORY & CATALOG AGENT: Always invoke get_sprockets or get_sprocket_by_id for any question about sprockets, inventory catalog listings, sprocket IDs (SPK-101 through SPK-105), ANSI models (ANSI-40, ANSI-60, ANSI-80), tooth counts, pitch, material, stock levels, unit prices, authenticated_user, or egress_source_ip verification.",
      "use_agent_gateway_egress": true,
      "agent_gateway_engine": "projects/${PROJ_ID}/locations/global/collections/default_collection/engines/${GE_APP_ID}"
    }
  }
}
EOF

Memverifikasi penautan server MCP kustom

# show engine (ge app) details
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  | jq '{name: .name, dataStoreIds: .dataStoreIds, agentGatewaySetting: .agentGatewaySetting}'

Periksa penyimpanan data tertaut "dataStoreIds": ["mcp-sprockets-collection-[EPOCH]_mcp_data"].

# show collection details
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  | jq --arg app "${GE_APP_ID}" '.collections[] | select(.dataConnector.actionConfig.actionParams.agent_gateway_engine // "" | endswith($app)) | .dataConnector | {name: .name, state: .state, actionState: .actionState, connectorModes: .connectorModes, auth_type: .actionConfig.actionParams.auth_type}'

Periksa "state": "ACTIVE" dan "auth_type": "OAUTH".

Tindakan alat

Saat memeriksa penyimpanan data mcp-sprockets-collection di dasbor Gemini Enterprise, Anda akan melihat bahwa tab Tindakan tidak digunakan dan tombol ↻ Muat ulang tindakan kustom dinonaktifkan. Ini adalah perilaku yang diharapkan.

Lihat halaman detail penyimpanan data di UI Konsol Google Cloud:

echo "data store details page url: https://console.cloud.google.com/gemini-enterprise/locations/${GE_LOCATION}/collections/${GE_COLLECTION_ID}/connector/details?project=${PROJ_ID}"

Bergantung pada cara Anda menghubungkan server MCP kustom ke Gemini Enterprise, penemuan dan tata kelola alat ditangani dengan salah satu dari dua cara:

  • MCP Kustom Langsung (BYO_MCP alur kerja): Saat Anda mengonfigurasi server MCP kustom langsung di dalam Gemini Enterprise tanpa Agent Registry, penyimpanan data itu sendiri mengelola katalog alat (connectorModes: ["FEDERATED", "ACTIONS"]). Anda harus membuka tab Tindakan, mengklik ↻ Muat ulang tindakan kustom untuk mengambil skema tools/list, dan mengaktifkan atau menonaktifkan setiap alat secara manual (add dan subtract) di UI.
  • Impor Agent Registry (alur kerja REGISTRY_MCP yang digunakan dalam codelab ini): Saat Anda mengimpor server MCP dari Agent Registry, Agent Registry berfungsi sebagai sumber tepercaya untuk endpoint MCP, metadata antarmukanya, dan katalog alatnya (connectorModes: ["FEDERATED"]). Gemini Enterprise secara otomatis mengaktifkan alat MCP terdaftar saat runtime melalui setelan Agent Gateway mesin tanpa mengharuskan Anda memuat ulang atau mengalihkan tindakan secara manual di UI penyimpanan data.

Bagian Gemini Enterprise telah selesai... selanjutnya ke bagian Validasi.

9. Validasi

Di bagian ini, Anda akan menyelesaikan alur izin pengguna OAuth 2.0 Google satu kali, memanggil alat MCP di server mcp-sprockets eksternal dari Gemini Enterprise, dan memverifikasi bahwa server MCP eksternal memvalidasi kedua IP statis Cloud NAT yang dicadangkan (egress_source_ip) dan identitas OAuth 2.0 Google Anda (authenticated_user).

Akses pengguna

Buat URL untuk aplikasi web Gemini Enterprise:

# fetch app user url
export GE_WIDGET_ID=$(curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}/widgetConfigs/default_search_widget_config" \
  -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  -H "Content-Type: application/json" \
  | jq -r '.configId')

export GE_APP_USER_URL="https://vertexaisearch.cloud.google.com/home/cid/${GE_WIDGET_ID}"

echo "app user url: ${GE_APP_USER_URL}"

Sebelum membuat kueri agen, Anda harus menyelesaikan alur izin OAuth 2.0 satu kali yang memberikan izin kepada Gemini Enterprise untuk mendapatkan token akses bagi identitas Google Anda (${USER_IDENTITY}). Hal ini memungkinkan Gemini Enterprise mengautentikasi panggilan alat keluar melalui Agent Gateway sehingga server mcp-sprockets eksternal dapat memverifikasi identitas Anda pada setiap permintaan.

  1. Buka ${GE_APP_USER_URL} di browser Anda, lalu klik Mulai.
  2. Di kotak chat, klik ikon Connectors (ikon potongan puzzle), lalu klik Authorize di samping mcp-sprockets-collection.
  3. Jendela baru akan muncul yang meminta Anda untuk Pilih akun untuk melanjutkan ke mcp-sprockets-oauth (nama aplikasi layar izin OAuth yang Anda konfigurasi). Di sana, pilih akun pengguna Anda (${USER_IDENTITY}).
  4. Di layar izin OAuth Google, tinjau izin yang diminta yang memungkinkan Google (Penyedia Identitas) membagikan identitas pengguna Anda (openid, email, profile) kepada mcp-sprockets-oauth, lalu klik Lanjutkan.
  5. Klik ikon Connectors lagi dan pastikan tombol untuk mcp-sprockets-collection diaktifkan, yang mengonfirmasi bahwa otorisasi berhasil.

Menguji kueri agen

Pengujian UI percakapan Asisten

Kirimkan kueri pengujian berikut dalam chat:

look up sprocket SPK-105 and confirm the model, material, unit_price, authenticated_user, and egress_source_ip

Coba kueri kedua di percakapan:

list all sprockets in the inventory catalog and report the authenticated_user and egress_source_ip

Pastikan asisten menampilkan jawaban yang benar dan menampilkan badge kutipan tindakan interaktif.

Misalnya, "Sprocket Lookup SPK-105 (5s)Ikon alat MCPAgent Gatewayikon centang dalam lingkaran" di bawah setiap respons, mengonfirmasi bahwa alat telah dijalankan.

Pastikan asisten menampilkan spesifikasi sprocket bersama dengan "authenticated_user" yang cocok dengan ${USER_IDENTITY} dan "egress_source_ip" yang cocok dengan ${NAT_EXT_IP} yang Anda pesan.

Pengujian API streamAssist Asisten

Setelah akun pengguna Anda mengizinkan konektor OAuth 2.0, Anda juga dapat memanggil default_assistant:streamAssist API langsung dari CLI dan memverifikasi bahwa server mcp-sprockets eksternal menampilkan kedua IP statis Cloud NAT (${NAT_EXT_IP}) dan identitas Google OAuth 2.0 terverifikasi (${USER_IDENTITY}):

Kirimkan kueri pengujian berikut:

# query engine (ge app) streamAssist
curl -s -X POST "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}/assistants/default_assistant:streamAssist" \
  -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  -H "Content-Type: application/json" \
  -d @- <<EOF | jq -r '.[].answer.replies[]?.groundedContent?.content?.text // empty'
{
  "query": {
    "text": "look up sprocket SPK-103 and confirm the model, material, unit_price, authenticated_user, and egress_source_ip"
  },
  "toolsSpec": {
    "vertexAiSearchSpec": {
      "dataStoreSpecs": [
        {
          "dataStore": "projects/${PROJ_NO}/locations/${GE_LOCATION}/collections/default_collection/dataStores/${GE_COLLECTION_ID}_mcp_data"
        }
      ]
    }
  }
}
EOF

Contoh output:

Here are the details for sprocket SPK-103 from the inventory catalog:
- Model: ANSI-60-16T
- Material: 304 Stainless Steel
- Unit Price: $42.00
- Authenticated User (Google OAuth 2.0): user@example.com
- Egress Source IP (Cloud NAT): 203.0.113.10

Coba kueri lain:

# query engine (ge app) streamAssist
curl -s -X POST "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}/assistants/default_assistant:streamAssist" \
  -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  -H "Content-Type: application/json" \
  -d @- <<EOF | jq -r '.[].answer.replies[]?.groundedContent?.content?.text // empty'
{
  "query": {
    "text": "find a sprocket model i can get for under \$20 and report the details, authenticated_user, and egress_source_ip"
  },
  "toolsSpec": {
    "vertexAiSearchSpec": {
      "dataStoreSpecs": [
        {
          "dataStore": "projects/${PROJ_NO}/locations/${GE_LOCATION}/collections/default_collection/dataStores/${GE_COLLECTION_ID}_mcp_data"
        }
      ]
    }
  }
}
EOF

Memeriksa log di Cloud Logging

Verifikasi bahwa Gemini Enterprise merutekan panggilan alat melalui Agent Gateway, lampiran jaringan PSC, dan Cloud NAT dengan memeriksa log di Cloud Logging.

Memverifikasi log Agent Gateway

Pastikan Agent Gateway mencegat permintaan, menyelesaikan target di Agent Registry, mengevaluasi kebijakan otorisasi, dan meneruskan panggilan alat:

# show agent gateway logs
gcloud logging read \
  "resource.type=networkservices.googleapis.com/Gateway
   AND resource.labels.location=${REGION}" \
  --project=${PROJ_ID} \
  --limit=8 \
  --format="table(
    timestamp.date('', tz=LOCAL):label=TIMESTAMP,
    httpRequest.status:label=STATUS,
    httpRequest.serverIp:label=SERVER_IP,
    jsonPayload.agentGatewayInfo.mcpInfo.method:label=MCP_METHOD,
    jsonPayload.agentGatewayInfo.mcpInfo.parameter:label=TOOL,
    jsonPayload.authzPolicyInfo.result:label=AUTHZ,
    jsonPayload.agentGatewayInfo.agentRegistryResource.basename():label=REGISTRY_MCP
  )"

Contoh output:

TIMESTAMP                STATUS  SERVER_IP         MCP_METHOD                 TOOL                AUTHZ    REGISTRY_MCP
YYYY-MM-DDTHH:MM:SS.ZZZ  200     203.0.113.20:443  tools/call                 get_sprocket_by_id  ALLOWED  agentregistry-00000000-0000-0000-5c39-1f6e542bb2b8
YYYY-MM-DDTHH:MM:SS.ZZZ  200     203.0.113.20:443  tools/list                                     ALLOWED  agentregistry-00000000-0000-0000-5c39-1f6e542bb2b8
YYYY-MM-DDTHH:MM:SS.ZZZ  202     203.0.113.20:443  notifications/initialized                      ALLOWED  agentregistry-00000000-0000-0000-5c39-1f6e542bb2b8
YYYY-MM-DDTHH:MM:SS.ZZZ  200     203.0.113.20:443  initialize                                     ALLOWED  agentregistry-00000000-0000-0000-5c39-1f6e542bb2b8

Pastikan output berisi:

  • STATUS: 200 (eksekusi berhasil) dan 202 (jabat tangan notifications/initialized).
  • SERVER_IP: IP dan port server MCP eksternal (${MCP_EXT_IP}:443).
  • MCP_METHOD & TOOL: Urutan protokol MCP (initialize, notifications/initialized, tools/list, dan tools/call dengan get_sprocket_by_id).
  • AUTHZ: ALLOWED (otorisasi IAP mengizinkan keluar).
  • REGISTRY_MCP: ID resource Agent Registry yang telah di-resolve (agentregistry-...).

Memverifikasi log Cloud NAT

Pastikan Cloud NAT menerjemahkan koneksi keluar dari IP network attachment PSC Agent Gateway (10.10.10.2) ke alamat IPv4 eksternal statis yang Anda cadangkan (${NAT_EXT_IP}) saat terhubung ke ${MCP_EXT_IP}:443:

# show cloud nat logs
gcloud logging read \
  "resource.type=nat_gateway
   AND resource.labels.gateway_name=nat-${SLUG}-${REGION}
   AND jsonPayload.connection.dest_ip=${MCP_EXT_IP}" \
  --project=${PROJ_ID} \
  --limit=8 \
  --format="table(
    timestamp.date('', tz=LOCAL):label=TIMESTAMP,
    jsonPayload.allocation_status:label=ALLOCATION_STATUS,
    jsonPayload.connection.src_ip:label=SRC_IP,
    jsonPayload.connection.nat_ip:label=NAT_IP,
    jsonPayload.connection.dest_ip:label=DEST_IP,
    jsonPayload.connection.dest_port:label=PORT
  )"

Contoh output:

TIMESTAMP                ALLOCATION_STATUS  SRC_IP      NAT_IP        DEST_IP       PORT
YYYY-MM-DDTHH:MM:SS.ZZZ  OK                 10.10.10.2  203.0.113.10  203.0.113.20  443

Memverifikasi log firewall

Pastikan kebijakan firewall internal (fw-policy-${SLUG}-internal) mengizinkan traffic keluar dari Agent Gateway ke tujuan internet:

# show firewall policy logs (internal)
gcloud logging read \
  "logName:compute.googleapis.com%2Ffirewall
   AND jsonPayload.rule_details.reference:fw-policy-${SLUG}-internal" \
  --project=${PROJ_ID} \
  --limit=8 \
  --format="table(
    timestamp.date('', tz=LOCAL):label=TIMESTAMP,
    jsonPayload.connection.src_ip:label=SRC_IP,
    jsonPayload.connection.dest_ip:label=DEST_IP,
    jsonPayload.connection.dest_port:label=PORT,
    jsonPayload.vpc.vpc_name:label=VPC_NETWORK,
    jsonPayload.rule_details.reference.basename():label=POLICY,
    jsonPayload.rule_details.priority:label=RULE,
    jsonPayload.rule_details.direction:label=DIRECTION,
    jsonPayload.disposition:label=DISPOSITION
  )"

Pastikan bahwa kebijakan firewall eksternal (fw-policy-${SLUG}-external) mengizinkan traffic ingress ke server MCP dari alamat IP NAT publik jaringan internal:

# show firewall policy logs (external)
gcloud logging read \
  "logName:compute.googleapis.com%2Ffirewall
   AND jsonPayload.rule_details.reference:fw-policy-${SLUG}-external" \
  --project=${PROJ_ID} \
  --limit=8 \
  --format="table(
    timestamp.date('', tz=LOCAL):label=TIMESTAMP,
    jsonPayload.connection.src_ip:label=SRC_IP,
    jsonPayload.connection.dest_ip:label=DEST_IP,
    jsonPayload.connection.dest_port:label=PORT,
    jsonPayload.vpc.vpc_name:label=VPC_NETWORK,
    jsonPayload.rule_details.reference.basename():label=POLICY,
    jsonPayload.rule_details.priority:label=RULE,
    jsonPayload.rule_details.direction:label=DIRECTION,
    jsonPayload.disposition:label=DISPOSITION
  )"

Ini mengakhiri bagian validasi... selanjutnya ke bagian Pembersihan.

10. Pembersihan

Ikuti langkah-langkah berikut untuk menghapus resource dan konfigurasi yang dibuat di lab ini.

Menghapus komponen Gemini Enterprise

# delete gemini enterprise engine (app)
curl -s -X DELETE "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}"

# delete custom mcp collection, data connector, and backing data store
curl -s -X DELETE "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/${GE_COLLECTION_ID}" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}"

# reset identity provider configuration
curl -s -X PATCH "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/aclConfig" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  -H "Content-Type: application/json" \
  -d '{"idpConfig":{"idpType":"IDP_TYPE_UNSPECIFIED"}}'

Untuk menghapus kredensial klien OAuth 2.0 (ge-mcp-sprockets-client), buka halaman Klien Platform Auth Google dan klik ikon Hapus (tempat sampah) di samping ge-mcp-sprockets-client:

# print google auth platform clients url
echo "https://console.cloud.google.com/auth/clients?project=${PROJ_ID}"

Menghapus komponen server MCP dan Agent Registry

# delete external mcp server vm
gcloud -q compute instances delete vm-${MCP_NAME} --zone=${ZONE}

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

# delete agent registry oauth2 endpoint
gcloud -q agent-registry services delete oauth2-googleapis --location=${REGION}

Menghapus komponen Agent Gateway

# delete gateway authz policy and iap service extension
gcloud -q network-security authz-policies delete ${AGW_NAME}-authz-policy-iap \
  --location=${REGION}

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

# delete agent gateway and connectivity template
gcloud -q network-services agent-gateways delete ${AGW_NAME} \
  --location=${REGION}

gcloud -q network-services agent-connectivity-templates delete act-${AGW_NAME} \
  --location=${REGION}
# delete iam unified access policy binding and access policy
gcloud -q iam policy-bindings delete uap-bind-${SLUG} \
  --location=global \
  --project=${PROJ_ID}

gcloud -q iam access-policies delete uap-policy-${SLUG} \
  --location=global \
  --project=${PROJ_ID}

Menghapus komponen firewall

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

gcloud -q compute network-firewall-policies associations delete \
  --name=fw-policy-bind-${SLUG}-external \
  --firewall-policy=fw-policy-${SLUG}-external \
  --global-firewall-policy

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

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

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

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

Menghapus komponen jaringan

# delete cloud nat gateway and cloud router
gcloud -q compute routers nats delete nat-${SLUG}-${REGION} \
  --router=cr-nat-${SLUG}-${REGION} \
  --region=${REGION}

gcloud -q compute routers delete cr-nat-${SLUG}-${REGION} \
  --region=${REGION}

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

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

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

# delete reserved static external ip addresses
gcloud -q compute addresses delete ip-${SLUG}-nat ip-${SLUG}-mcp \
  --region=${REGION}

# delete internal and external vpc networks
gcloud -q compute networks delete \
  vnet-${SLUG}-internal \
  vnet-${SLUG}-external

Menghapus penggantian kebijakan organisasi dan file lokal

# delete project-level organization policy overrides
for policy in \
  discoveryengine.managed.disableCustomMcpServerConnector \
  discoveryengine.managed.allowedEgressFqdns \
  discoveryengine.managed.allowedDataSources \
  iam.managed.disableAccessPolicyBinding \
  compute.vmExternalIpAccess; do
  gcloud -q org-policies delete ${policy} --project=${PROJ_ID} 2>/dev/null || true
done

# remove local project files
rm -rf cfg

Pembersihan telah selesai... selanjutnya kita akan membahas Kesimpulan.

11. Kesimpulan

Selamat! Anda telah membangun arsitektur end-to-end yang memungkinkan aplikasi Gemini Enterprise menemukan dan memanggil alat dengan aman di server MCP kustom yang dilindungi OAuth 2.0 dan memiliki IP yang diizinkan secara eksternal:

  • Traffic keluar VPC IP statis (ALL_TRAFFIC & Cloud NAT): Merutekan semua traffic keluar Agent Gateway melalui lampiran jaringan PSC (10.10.10.2) dan menerjemahkan permintaan yang ditujukan ke internet ke alamat IPv4 eksternal statis yang dicadangkan (${NAT_EXT_IP}) menggunakan Cloud NAT.
  • Server Resource MCP & Agent Registry OAuth 2.0: Men-deploy server FastMCP HTTP eksternal yang dapat di-streaming (mcp-sprockets) yang dilindungi oleh daftar yang diizinkan firewall IP sumber yang ketat (${NAT_EXT_IP}/32) dan verifikasi OAuth 2.0 Google tokeninfo, serta mendaftarkan endpoint dan skema alatnya (get_sprockets dan get_sprocket_by_id) di Agent Registry.
  • Integrasi & tata kelola OAuth 2.0 Gemini Enterprise: Menyediakan aplikasi Gemini Enterprise, mengikat traffic alat keluar ke Agent Gateway, melampirkan server MCP terdaftar sebagai konektor data OAuth 2.0 REGISTRY_MCP, dan memverifikasi egress_source_ip dan authenticated_user bersama telemetri Cloud Logging.

cosmopup

Cosmopup menganggap Codelab sangat keren!

Apa langkah selanjutnya?

Jangan ragu untuk memberikan komentar, pertanyaan, atau koreksi menggunakan formulir masukan ini.

Terima kasih!