Tüm trafiğin VPC çıkışı ve Cloud NAT statik IP'si ile harici MCP sunucusuna yönelik Agent Gateway'li Gemini Enterprise

1. Giriş

Bu Codelab'de, agent-to-anywhere (çıkış) modunda Agent Gateway kullanılarak Gemini Enterprise için statik IP çıkış bağlantısı ele alınmaktadır. Bağlantı şablonu yapılandırması kullanarak tüm giden trafiği Agent Gateway üzerinden yönlendirerek, katı bir kaynak IP izin verilenler listesi ve OAuth 2.0 kimlik doğrulaması ile korunan özel bir Model Bağlam Protokolü (MCP) sunucusunu çağırmak için bir Gemini Enterprise uygulaması yapılandıracaksınız. Private Service Connect (PSC) ağ eki, Agent Gateway'i VPC ağına bağlar ve Cloud NAT, internet çıkış trafiği için sabit bir harici IP adresi sağlar.

Varsayılan olarak, Gemini Enterprise'dan herkese açık internet uç noktalarına yapılan giden bağlantılar, tek bir müşteriye ait IP izin verilenler listesi kuralına sabitlenemeyen dinamik ve paylaşılan Google IP adresi havuzlarından kaynaklanır. Agent Gateway'i ALL_TRAFFIC modunda bir AgentConnectivityTemplate ile eşleme, tüm giden aracı trafiğini VPC ağına yönlendirir. Burada Cloud NAT, internete bağlı bağlantıları kontrolünüzdeki ayrılmış statik harici IPv4 adresine çevirirken Agent Registry ve Identity-Aware Proxy (IAP) aracılığıyla merkezi MCP aracı yönetimini korur.

Ne oluşturacaksınız?

  • Agent Registry uç nokta doğrulaması ile çıkış (agent-to-anywhere) modunda çalışan Agent Connectivity Template (vpcEgress: ALL_TRAFFIC) ve Agent Gateway
  • VPC ağı, PSC ağ eki, Cloud Router ve ayrılmış statik harici IPv4 adresine bağlı Cloud NAT ağ geçidi
  • Caddy TLS tarafından desteklenen, güvenlik duvarı kurallarıyla Cloud NAT statik IP'siyle kesin olarak sınırlandırılmış ve kullanıcı tarafından yetkilendirilmiş Google OAuth 2.0 Bearer jetonlarını https://oauth2.googleapis.com/tokeninfo'ye karşı doğrulayan harici akışa aktarılabilir HTTP MCP kaynak sunucusu (mcp-sprockets)
  • Google Auth Platform OAuth 2.0 kullanıcı rızası ekranı ve Web uygulaması OAuth 2.0 istemci kimlik bilgileri (accounts.google.com ve oauth2.googleapis.com/token)
  • Agent Registry MCP sunucu kataloğu girişi ve araç spesifikasyonu (toolspec.json)
  • Identity-Aware Proxy (IAP) yetkilendirme uzantısı ve Agent Gateway için Gateway yetkilendirme politikası
  • Agent Gateway'e bağlı ve Agent Registry'den içe aktarılan bir OAuth 2.0 özel MCP sunucusu veri deposuna bağlı Gemini Enterprise uygulaması

figure1

Şekil 1. Codelab mimarisi

Öğrenecekleriniz

  • Tüm giden aracı ağ geçidi trafiğini bir VPC ağına yönlendirmek için AgentConnectivityTemplate ile vpcEgress: ALL_TRAFFIC nasıl yapılandırılır?
  • Statik bir harici IPv4 adresini ayırma ve PSC ağ eki alt ağında Cloud NAT'ye bağlama
  • Google OAuth 2.0 Bearer jetonlarını doğrulayan (oauth2.googleapis.com/tokeninfo) ve giriş güvenlik duvarını Cloud NAT statik IP'siyle (${NAT_EXT_IP}/32) sınırlayan harici bir akışa aktarılabilir HTTP MCP kaynak sunucusu dağıtma
  • Google Identity OAuth 2.0 istemci kimlik bilgilerini yapılandırma ve Agent Registry'de bir MCP sunucusunu ve araç şemasını kaydetme
  • Kayıtlı bir OAuth 2.0 MCP sunucusunu Gemini Enterprise'a bağlama ve kullanıcı tarafından temsil edilen araç çağrılarını Agent Gateway üzerinden yönlendirme
  • KSA komutlarını ve Cloud Logging'i kullanarak statik IP çevirisini, son kullanıcı OAuth 2.0 kimlik doğrulamasını (authenticated_user) ve ağ geçidi politikası zorunluluğunu doğrulama

İhtiyacınız olanlar

  • Faturalandırmanın etkin olduğu bir Google Cloud projesi
  • Etkin bir Gemini Enterprise lisansı veya 30 günlük deneme sürümü
  • Ağ iletişimi hizmetleri, kuruluş politikaları, Gemini Enterprise ve Agent Platform kaynaklarını sağlama için IAM izinleri
  • Google Cloud KSA (gcloud), curl ve jq yüklü bir POSIX uyumlu kabuk (bash veya zsh)

Giriş bölümünü tamamladık. Şimdi Kavramlar bölümüne geçiyoruz.

2. Kavramlar

Dağıtım sırası

Bu Codelab'de, MCP araçları Gemini Enterprise'a kaydedilip bağlanmadan önce statik IP çıkış yollarının ve ağ geçidi kontrollerinin çalışır durumda olması için önce ağ ve yönetim altyapısı dağıtılır:

  1. Ağ altyapısı: Statik harici IPv4 adresleri ayırın ve çıkış VPC'sini, PSC eki alt ağını, PSC ağ ekini, Cloud Router'ı, Cloud NAT ağ geçidini ve harici MCP ağ güvenlik duvarı kurallarını sağlayın.
  2. Agent Connectivity Template ve Agent Gateway: Çıkış modunda (AGENT_TO_ANYWHERE) Agent Registry entegrasyonu (registries) ile AgentConnectivityTemplate (vpcEgress: ALL_TRAFFIC) ve bölgesel AgentGateway dağıtın.
  3. Yetkilendirme politikaları: IAP yetkilendirme uzantısını (AuthzExtension), Gateway yetkilendirme politikasını (AuthzPolicy) ve IAM v3 Birleşik Erişim Politikası'nı (AccessPolicy ve PolicyBinding) yapılandırın.
  4. MCP sunucusunu dağıtma ve kaydetme: Harici mcp-sprockets OAuth 2.0 kaynak sunucusunu Caddy TLS'nin arkasına dağıtın, Google OAuth 2.0 tokeninfo zorunluluğunu doğrulayın, giriş güvenlik duvarını Cloud NAT statik IP'siyle (${NAT_EXT_IP}/32) sıkı bir şekilde kilitleyin ve hizmet ile araç spesifikasyonlarını (get_sprockets ve get_sprocket_by_id) Agent Registry'ye kaydedin.
  5. Gemini Enterprise uygulaması ve OAuth 2.0 istemcisi: Google Identity sağlayıcıyı, deneme lisansını, OAuth 2.0 kullanıcı rızası ekranını ve web uygulaması istemci kimlik bilgilerini (OAUTH_CLIENT_ID ve OAUTH_CLIENT_SECRET) yapılandırın, Gemini Enterprise uygulamasını oluşturun (Engine) ve giden çıkışı Agent Gateway'e bağlayın (agentGatewaySetting).
  6. Özel MCP veri bağlayıcısını içe aktarma: Kayıtlı MCP sunucusunu destekleyen veri deposunu Gemini Enterprise uygulamasına bağlamak için REGISTRY_MCP veri bağlayıcısını (:setUpDataConnector) auth_type: "OAUTH" ile yapılandırıp oluşturun ve etkinleştirin.
  7. Doğrulama: Tek seferlik kullanıcı OAuth 2.0 izin akışını tamamlayın, Gemini Enterprise asistanı aracılığıyla MCP araçlarını çağırın (hem egress_source_ip hem de authenticated_user onaylayarak) ve Cloud Logging'de politika zorunluluğunu ve statik IP NAT çevirisini doğrulayın.

Merkezi IdP + OAuth ile korunan MCP kaynak sunucusu mimarisi

Kurumsal dağıtımlarda, kimlik yönetimi ve araç yürütme, merkezi kimlik sağlayıcı (yetkilendirme sunucusu) ile korunan MCP kaynak sunucusu arasındaki rollerin standart OAuth 2.0 ayrımına göre yapılır:

OAuth 2.0 Rolü

Bu Codelab'deki Bileşen

Sorumluluk

Kaynak sahibi

Son Kullanıcı (${USER_IDENTITY})

Gemini Enterprise web uygulamasında oturum açar ve tek seferlik 3 bacaklı OAuth 2.0 yetkilendirme akışı sırasında izin verir.

OAuth 2.0 İstemcisi

Gemini Enterprise custom_mcp Veri Bağlayıcısı

OAUTH_CLIENT_ID ve OAUTH_CLIENT_SECRET değerlerini tutar, oauth2.googleapis.com/token adresinde yetkilendirme kodunu değiştirir, kullanıcı OAuth 2.0 jetonlarını saklar ve her giden MCP aracı çağrısında Authorization: Bearer [access_token] değerini sunar.

Yetkilendirme sunucusu

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

Tarayıcı izni yönlendirmesi sırasında kullanıcının kimliğini doğrular ve Gemini Enterprise'a OAuth 2.0 erişim ve yenileme jetonlarını verir.

Kaynak Sunucusu

Harici mcp-sprockets Sunucu (https://mcp.[MCP_EXT_IP].sslip.io/mcp)

VPC güvenlik duvarını (${NAT_EXT_IP}/32) kullanarak 3. katman ağ kimliğini ve Authorization: Bearer [access_token] üstbilgisini https://oauth2.googleapis.com/tokeninfo ile karşılaştırarak doğrulayarak 7. katman kullanıcı kimliğini zorunlu kılar.

Tarayıcı izni yönlendirmesi (accounts.google.com) ve arka kanal jetonu değişimi (oauth2.googleapis.com/token) Google tarafından yönetilen OAuth 2.0 uç noktalarına karşı gerçekleştiğinden harici MCP sunucusu güvenlik duvarı yalnızca Cloud NAT aracılığıyla Agent Gateway'den çalışma zamanı MCP JSON-RPC istekleri (POST /mcp) alır. Bu sayede giriş güvenlik duvarının kesinlikle ${NAT_EXT_IP}/32 ile sınırlandırılmasına olanak tanır.

Discovery Engine kaynak modeli

Gemini Enterprise uygulaması (Discovery Engine API'de Engine kaynağı olarak gösterilir), son kullanıcılar için merkezi düzenleme katmanı ve etkileşimli arayüzdür. Kullanıcı sohbet oturumlarını yönetir, üretken modelleri kurumsal verilerle temellendirir ve dinamik araç yürütme işlemlerini koordine eder.

Gemini Enterprise uygulamaları, veri depoları aracılığıyla veriler ve sistemlerle etkileşim kurar:

  • Bilgi veri depoları: Almayla artırılmış üretim (RAG) için statik içerikleri (ör. Cloud Storage, Google Drive, BigQuery) alma ve dizine ekleme.
  • Veri bağlayıcıları (işlem sağlayıcılar): Dinamik üçüncü taraf veya özel API'lere bağlanın. Özel bir MCP sunucusu veri deposu, Model Context Protocol (MCP) tarafından tanımlanan araçları kullanıma sunarak modelin bir sohbet sırasında harici işlevleri dinamik olarak çağırmasına olanak tanır.

Gemini Enterprise çıkışı

Gemini Enterprise, hem Engine üzerindeki agentGatewaySetting hem de DataConnector üzerindeki use_agent_gateway_egress: true yapılandırıldığında özel MCP sunucusu araç isteklerini Agent Gateway'e yönlendirir.

figure2

Şekil 2. Gemini Enterprise çıkış mimarisi

Gemini Enterprise uygulaması, araç yönlendirmeyi dört temel alana göre düzenler:

  1. Widget (default_search_widget_config):
    • Web istemcisi arayüzüne hizmet verir. Widget, kullanıcıdan istemler alır, bir araç yetkilendirme gerektirdiğinde tek seferlik OAuth 2.0 kullanıcı izni yönlendirmesini tetikler ve temel motorla sohbet oturumları başlatır.
  2. Core Assistant (assistants/default_assistant/agents/default/core_assistant):
    • Motorun içindeki temel etkileşimli akıl yürütme ajanı. Temel Asistan, kullanıcı sorgusunu değerlendirirken mevcut araçları inceler ve yürütme işlemini sentezlenmiş Agent Gateway alt aracısına devreder.
  3. Veri Deposu ve Veri Bağlayıcı:
    • DataStore: :setUpDataConnector çalışırken özel bir Collection içinde sağlanan bu araç, içe aktarılan Agent Registry aracı şemalarını (get_sprockets, get_sprocket_by_id), bağımsız değişken türlerini ve aracı talimatlarını Gemini Enterprise'a (Engine) bağlar (dataStoreIds).
    • DataConnector: Uzak MCP sunucusuna (instance_uri) REGISTRY_MCP işlem bağlantısını (createBapConnection: true) yönetir, Agent Registry MCP sunucu kaynağını (registry_mcp_server_name) çözer, kullanıcı kasasında saklanan OAuth 2.0 Bearer jetonunu (Authorization: Bearer [access_token]) ekler ve Agent Gateway çıkışını (use_agent_gateway_egress: true) etkinleştirir.
  4. Temsilci Kimliği, Temsilci Kayıt Defteri ve Temsilci Ağ Geçidi:
    • Veri Bağlayıcı, giden araç çağrısını gönderdiğinde trafiği agentGatewaySetting içinde belirtilen ağ geçidine yönlendirir. Core Assistant, iş yükü kimliğini onaylayan bir SPIFFE kimlik jetonu oluşturur: principal://agents.global.org-.../agents/default/core_assistant.
    • Agent Gateway, hedef uç noktaları ve kayıtlı araç şemalarını dinamik olarak çözmek için registries alanını kullanarak Agent Registry ile entegre olur, IAP kullanarak yetkilendirme politikalarını değerlendirir ve izin verilen istekleri (kullanıcı Authorization: Bearer üstbilgisini koruyarak) AgentConnectivityTemplate kullanarak VPC ağına yönlendirir.

Ağ geçidi VPC bağlantısı ve statik IP NAT

Agent Gateway, ağ geçidinde agentConnectivityTemplate tarafından referans verilen bir AgentConnectivityTemplate kaynağı kullanarak VPC ağı bağlantısını destekler. Şablon egressNetworkConfig, trafiğin bir PSC ağ eki üzerinden VPC'nize nasıl girdiğini tanımlar:

  • PRIVATE_RANGES_ONLY (varsayılan): Yalnızca RFC 1918, RFC 6598 ve E sınıfı özel IP aralıklarını PSC ağ ekinden yönlendirir. İnternete yönelik trafik, VPC'nizi atlayarak doğrudan Google'ın varsayılan internet çıkışı üzerinden çıkar.
  • ALL_TRAFFIC (Bu Codelab'de kullanılır): Agent Gateway'den çıkan tüm trafiği (kamu interneti ve harici iş ortağı MCP uç noktaları dahil) PSC ağ eki (10.10.10.2) aracılığıyla VPC alt ağınıza yönlendirir.

ALL_TRAFFIC modunda çalışırken PSC ekli alt ağının iki yapılandırması gerekir:

  • Özel Google Erişimi (--enable-private-ip-google-access): Google Cloud API'lerine (*.googleapis.com) yapılan dahili çağrıların Google ağı içinde özel olarak yönlendirilmeye devam etmesini sağlar.
  • Cloud Router ve Cloud NAT (MANUAL_ONLY): PSC eki alt ağına giren internete bağlı trafik, Cloud NAT üzerinden varsayılan rotayı (0.0.0.0/0) izler. Cloud NAT, ayrılmış statik harici IPv4 adresiniz (${NAT_EXT_IP}) için Kaynak Ağı Adresi Çevirisi (SNAT) gerçekleştirir. Bu nedenle, harici güvenlik duvarları gelen erişimi yalnızca ${NAT_EXT_IP}/32 ile sınırlandırabilir.

Sınırlamalar ve şartlar

Gemini Enterprise uygulamasının konumu

Agent Gateway ve NAT konumu

Agent Registry konumu

global

us-central1

us-central1, us veya global

us

us-central1

us-central1 veya us

eu

europe-west1

europe-west1 veya eu

Kavramlar bölümü burada sona eriyor. Şimdi Kurulum bölümüne geçiyoruz.

3. Kurulum

Gerekli IAM rolleri

Bu Codelab'i tamamlamak için aşağıdaki roller gereklidir:

Alan

Gerekli IAM rolleri

Proje ve IAM

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

Ağ ve Ağ Geçidi

roles/networkservices.admin
roles/networksecurity.admin
roles/serviceextensions.admin
roles/iap.admin
roles/compute.networkAdmin
roles/compute.securityAdmin

Gemini Enterprise ve Registry

roles/discoveryengine.admin
roles/agentregistry.admin

İş yükleri

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

Gözlemlenebilirlik

roles/logging.viewer

Alternatif olarak, roles/owner tek başına kuruluş politikalarını değiştiremediğinden roles/orgpolicy.policyAdmin ile birlikte roles/owner gibi geniş kapsamlı bir temel rol kullanın.

Projenize erişme

Bu Codelab'de tek bir Google Cloud projesi kullanılır. Yapılandırma adımlarında gcloud KSA ve Linux kabuk komutları kullanılır.

Google Cloud projenizin komut satırına erişerek başlayın:

Proje kimliğinizi ayarlama

# set target project id
gcloud config set project SET_YOUR_PROJECT_ID_HERE

Oturumun kimliğini doğrulama

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

Kabuk ortamı değişkenlerini ayarlama

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

Aracı kimliği güven alanlarını ayarlama

if-then-else ifadesi, asıl aracı kimlikleri için doğru güven alanını ayarlamak amacıyla projenin bir kuruluşa ait olup olmadığını kontrol eder.

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

Faturalandırma ve kota projesini ayarlama

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

Yapılandırma dosyaları için yerel dizin oluşturma

# create config folder
mkdir -p cfg

Google Cloud SDK'nın kendi kendine yönetilen bir yüklemesini (ör. Cloud Shell dışında) çalıştırıyorsanız bileşenleri en son sürüme güncelleyin.

# update gcloud cli
gcloud components update

API hizmetlerini etkinleştirme

# 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

Kuruluş politikaları

Varsayılan Google Cloud yönetilen kuruluş politikası kısıtlamaları ve korumalı alan politikaları, bu codelab'de kullanılan özellikleri kısıtlayabilir:

  • compute.vmExternalIpAccess: Kilitli korumalı alan kuruluşlarındaki Compute Engine sanal makinelerinde harici IPv4 adreslerini kısıtlar.
  • discoveryengine.managed.disableCustomMcpServerConnector: Veri kaynağı olarak özel bir MCP sunucusu (custom_mcp) kullanan veri bağlayıcılarının oluşturulmasını kısıtlar (varsayılan olarak uygulanır).
  • discoveryengine.managed.allowedEgressFqdns: VPC Hizmet Kontrolleri (VPC-SC) etkin olduğunda veya proje enforcedProjects içinde listelendiğinde veri bağlayıcıları için giden çıkış alanlarını (instance_uri FQDN) kısıtlar.
  • discoveryengine.managed.allowedDataSources: VPC-SC etkin olduğunda veya proje enforcedProjects içinde listelendiğinde izin verilen veri bağlayıcı türlerini (dataSource) kısıtlar.

Devralınan kuruluş politikası kısıtlamalarını proje düzeyinde geçersiz kılabilirsiniz.

Özel MCP kısıtlamasını devre dışı bırakma

# 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

Koşullu veri bağlayıcı kısıtlamalarını devre dışı bırakma

# 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

Erişim politikası kısıtlamasını devre dışı bırakma

# 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

Harici IP adreslerine izin verme

# 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

Kuruluş politikalarını doğrulama

compute.vmExternalIpAccess ayarının allowAll: True olarak belirlendiğini ve diğer politikaların enforce: False olduğunu kontrol edin:

# 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

Hizmet aracısı bağlamalarını doğrulama (önlem amaçlı)

Yeni bir projede, networkservices.googleapis.com ilk kez etkinleştirildiğinde Google Cloud, Agent Gateway hizmet aracısını otomatik olarak sağlar ve roles/agentgateway.serviceAgent izni verir. Önceki temizleme işlemlerinde varsayılan hizmet aracısı bağlamalarının kaldırılmış olabileceği mevcut bir projeyi yeniden kullanıyorsanız kimlik ve rol bağlamasının bozulmamış olduğundan emin olmak için aşağıdaki komutları yedek olarak çalıştırın:

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

Kurulum bölümünü tamamladık. Şimdi Ağ bölümüne geçiyoruz.

4. Ağ

Bu bölümde, statik harici IPv4 adreslerini ayıracak, dahili çıkış VPC ağı ile yalıtılmış harici VPC ağını oluşturacak, PSC ağ ekini sağlayacak, Cloud NAT'i yapılandıracak ve güvenlik duvarı kuralları oluşturacaksınız.

Statik harici IP adreslerini ayırma

Cloud NAT ve harici MCP sunucusu VM'si için iki bölgesel statik harici IPv4 adresi ayırın:

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

Statik harici IP adreslerini doğrulama

Gemini Enterprise, uzak MCP uç noktalarının herkese açık olarak güvenilen bir TLS sertifikasıyla HTTPS kullanmasını gerektirir. Bu laboratuvar için özel bir alan kaydetmek yerine, IP adresi içeren herhangi bir ana makine adını (ör. mcp.[IP].sslip.io) doğrudan bu IP'ye geri yönlendiren ücretsiz bir joker karakter DNS hizmeti olan sslip.io'yi kullanırsınız. Let's Encrypt gibi sertifika yetkilileri, çıplak IP adreslerine sertifika vermediğinden bu sslip.io ana makine adı, Caddy ters proxy'sine MCP sunucusu için güvenilir bir TLS sertifikasını otomatik olarak sağlamak üzere geçerli bir alan adı verir.

Hem IPv4 adreslerini dışa aktarın hem de harici MCP sunucusu için sslip.io alan adını ve URL'yi oluşturun:

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

Örnek çıkış:

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

Dahili ağ oluşturma

Agent Gateway bağlantı şablonu, egressNetworkConfig ile networkAttachment kullanacak şekilde yapılandırıldığında PSC ağ ekini barındıran alt ağ en az /28 CIDR bloku olmalı ve Özel Google Erişimi (--enable-private-ip-google-access) etkinleştirilmiş olmalıdır.

Dahili aracı ağ geçidi çıkışı için genel bir VPC ağı oluşturun:

# 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

Dahili güvenlik duvarı kuralları oluşturma

Günlüğün etkin olduğu tüm çıkış trafiğine izin veren bir güvenlik duvarı politikası oluşturun. Bu, Agent Gateway'den dahili VPC ağına çıkan trafiği izlemek için kullanılır. Cloud NGFW, ağ güvenliği ve trafik izleme için hem Essentials hem de Standard katmanlarını destekler.

# 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

PSC ağ eki oluşturma

Agent Gateway'den gelen bağlantıları otomatik olarak kabul edecek şekilde yapılandırılmış bir Private Service Connect (PSC) ağ eki oluşturun. Ağ eki, giden çıkış trafiği için Agent Gateway üretici tarafıyla güvenli bir şekilde bağlantı kurmak üzere bağlantının tüketici VPC ağı tarafını oluşturur. Alt ağ koşulları ve IP aralığı spesifikasyonları hakkında daha fazla bilgi için VPC bağlantısını yapılandırma başlıklı makaleyi inceleyin.

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

PSC ağ ekini doğrulama

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

PSC ağ eklerinin kaynak URI'sini alın ve PSC_NA_URI ortam değişkeninde saklayın. Bu URI, VPC ağına ağ çıkışı için PSC arayüzünü sağlamak üzere Agent Gateway yapılandırmasında (networkConfig.egress.networkAttachment) referans olarak kullanılır:

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

Cloud NAT oluşturma

Cloud NAT, Agent Gateway çıkış trafiğinin kaynak IP adresini herkese açık internet üzerinden yönlendirme için ayrılmış genel IP adresine çevirmek üzere kullanılır.

Yalnızca Agent Gateway çıkış ağı ekleme alt ağındaki kaynaklar Cloud NAT kullanmaya uygun olarak tanımlanır.

# 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

Cloud NAT'yi doğrulama

Cloud NAT durumunu ve beklenen natIP kaynağının yapılandırıldığını kontrol edin:

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

Örnek çıkış:

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

Harici ağ oluşturma

Harici MCP sunucusu VM'sini barındırmak için ayrı ve izole bir VPC ağı oluşturun.

# 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

Harici güvenlik duvarı kuralları oluşturma

Harici VPC ağında iki giriş güvenlik duvarı kuralı oluşturun:

  • 2001: 80 gelen TCP bağlantı noktasına izin verir. Böylece Let's Encrypt, ${MCP_DOMAIN} için ACME HTTP-01 alan doğrulama zorluğunu tamamlayabilir.
  • 2002: Başlangıçta, 443 numaralı gelen TCP bağlantı noktasına 0.0.0.0/0 üzerinden izin vererek TLS hazırlığını ve OAuth 2.0 tokeninfo zorunluluğunu yerel kabuktan doğruladıktan sonra bağlantı noktasını ${NAT_EXT_IP}/32 ile sınırlı tutar.
# 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

Ağ bölümünü tamamladık. Şimdi Agent Gateway bölümüne geçiyoruz.

5. Agent Gateway

Bu bölümde, vpcEgress: ALL_TRAFFIC ile Agent Connectivity Template'i dağıtacak, bölgesel Agent Gateway'i dağıtacak, yetkilendirmeyi Identity-Aware Proxy'ye (IAP) devredecek ve giden ağ isteklerini yönetmek için IAM Unified Access Policy kurallarını tanımlayacaksınız.

Bağlantı şablonu oluşturma

Bağlantı şablonu spesifikasyonu şunları tanımlar:

  • egressNetworkConfig.networkAttachment: Agent Gateway'i VPC ağınıza bağlayarak PSC ağ ekini gösterir.
  • egressNetworkConfig.vpcEgress: ALL_TRAFFIC olarak ayarlayın. Böylece, genel internet MCP uç noktaları da dahil olmak üzere tüm giden aracı bağlantıları VPC ağına yönlendirilir ve Cloud NAT kaynak IP adresi çevirisi kullanılarak çıkar.

Bağlantı şablonu yapılandırma dosyasını oluşturun ve içe aktarın:

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

Agent Gateway oluşturma

Agent Gateway spesifikasyonu şunları tanımlar:

  • agentConnectivityTemplate: Bağlantı şablonunu gösterir. Böylece ağ geçidi, VPC bağlantısı için PSC ağ ekini kullanabilir.
  • registries: Kataloglanmış MCP uç noktalarını ve araç şemalarını çözmek için ağ geçidini bölgesel Agent Registry ile ilişkilendirir.

Aracı Ağ Geçidi yapılandırma dosyasını oluşturun ve içe aktarın:

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

Agent Gateway dağıtımını doğrulama

Aracı kaydı ve bağlantı şablonu yapılandırmasını onaylayın:

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

Örnek çıkış:

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

Ağ geçidi bağlantısını onaylamak için PSC ağ ekini inceleyin:

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

Örnek çıkış:

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

Yetki verilmiş kullanıcı izni

Agent Gateway, Identity-Aware Proxy (IAP) Unified Access Policies (UAP) ile entegre edilmiş yetkilendirme politikalarını (networksecurity.authzPolicies) kullanarak giden araç trafiğini güvenli hale getirir ve yönetir.

Agent Gateway, temel satır içi ALLOW ve DENY kurallarını desteklese de kurumsal ortamlarda merkezi, kimlik odaklı yönetim gerekir. IAM Birleşik Erişim Politikaları (veya Erişim Politikaları) ile çıkış erişimi kurallarını standart IAM v3 erişim politikalarını kullanarak yönetirsiniz.

figure3

Şekil 3. Yetkilendirme mimarisi

Yetkilendirme akışı üç bileşeni birbirine bağlar:

  1. Ağ geçidi yetkilendirme politikası (authzPolicy):
    • Agent Gateway'i hedefleyen bölgesel bir kaynak.
    • Tüm giden yetkilendirme kontrollerini IAP yetkilendirme uzantısına yönlendirmek için policyProfile: REQUEST_AUTHZ ve action: CUSTOM ile yapılandırılır.
  2. Uygulama içi satın alma hizmeti uzantısı (authzExtension):
    • İstek yetkilendirmesini Identity-Aware Proxy'ye (iap.googleapis.com) devreden bölgesel bir kaynak.
    • ENFORCE modundaki politikaları V2 politika sürümünü kullanarak değerlendirir.
  3. IAM Unified Access Policy and Binding (accessPolicy & policyBinding):
    • Ayrıntılı erişim kuralları içeren global IAM v3 kaynakları.
    • Arayan aracının SPIFFE asıl kimliğini doğrular, evrensel iap.googleapis.com/resources.egressViaIAP iznini doğrular ve Common Expression Language (CEL) koşullarını hedef özelliklerine göre değerlendirir.

Yetkilendirme uzantısını dağıtma

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

Yetkilendirme uzantısını doğrulama

Yetkilendirme uzantısının etkin olup olmadığını kontrol edin:

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

Yetkilendirme politikasını dağıtma

Agent Gateway'i hedefleyen ve istek doğrulamasını IAP için yetkilendirme uzantısına devreden bir network-security yetkilendirme politikası yapılandırması oluşturun:

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

Yetkilendirme politikasını doğrulama

Yetkilendirme politikasının etkin olup olmadığını kontrol edin:

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

IAM erişim politikaları oluşturma

Agent Gateway artık yetkilendirme kontrollerini IAP'ye devreder ve hedef meta verilerini Agent Registry'den çözer. Ardından, giden araç yürütme işlemlerini yönetmek için bir IAM Birleşik Erişim Politikası kuralı tanımlayın.

IAP, CEL özelliği ifadelerini aşağıdaki Agent Registry hedef özelliklerine göre değerlendirir:

  • Kayıtlı durum (destination.is_registered):
    • Hedefin Agent Registry'de kataloglanıp kataloglanmadığını belirten Boole değeri (true/false).
  • MCP sunucu adı (destination.agent_registry.mcp_server.name):
    • Agent Registry'de kayıtlı standart MCP sunucusu kaynak adı.
  • Çoklu ödeme yöntemi (destination.agent_registry.mcp_server.method):
    • Çağrılan MCP yöntemi (ör. tools/call, tools/list, initialize).
  • Aracın adı (destination.agent_registry.mcp_server.tool.name):
    • Çağrılan aracın adı (ör. get_sprocket_by_id veya get_sprockets), kayıtlı MCP sunucularında ayrıntılı ve araç düzeyinde yetkilendirme yapılmasını sağlar.

IAM erişim politikası kuralını tanımlama

IAM politika kuralı manifesti şunları belirtir:

  • Asıl öğeler: Gemini Enterprise'ın temel asistan aracısını temsil eden SPIFFE asıl öğe kimliği.
  • İzinler: Tüm uygulama içi satın alma işlemlerinin yönettiği çıkış trafiği için gerekli olan evrensel iap.googleapis.com/resources.egressViaIAP izni.
  • Koşullar: Ajanın yalnızca Ajan Kayıt Defteri'nde kataloglanan uç noktaları çağırabilmesini sağlayan bir CEL ifadesi (destination.is_registered == true).

Politika kuralı manifest dosyasını oluşturun:

# 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

IAM erişim politikasını dağıtma

Manifest dosyasında tanımlanan kuralları kullanarak genel IAM erişim politikasını oluşturun:

# 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

IAM erişim politikasını doğrulama

IAM erişim politikasının başarıyla oluşturulduğunu kontrol edin ve kural ayrıntılarını inceleyin:

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

Örnek çıkış:

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

IAM erişim politikasını projeye bağlama

Projenizdeki tüm aracı ağ geçitelerinde zorlamayı etkinleştirmek için IAM erişim politikasını proje kaynağına ekleyen bir politika bağlama oluşturun:

# 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

IAM erişim politikası bağlamasını doğrulama

Etkin politika bağlama noktalarının doğru politikaya ve hedefe yönlendirdiğini kontrol edin:

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

Agent Gateway bölümünü tamamladık. Şimdi MCP sunucusu bölümüne geçiyoruz.

6. MCP sunucusu

Bu bölümde, get_sprockets ve get_sprocket_by_id araçlarını kullanıma sunan harici bir FastMCP OAuth 2.0 Kaynak Sunucusu (mcp-sprockets) dağıtacak, Google OAuth 2.0 Bearer jetonlarını https://oauth2.googleapis.com/tokeninfo'ya karşı kriptografik olarak doğruladığını onaylayacaksınız. Ardından, harici güvenlik duvarı kuralını Cloud NAT statik IP'siyle sınırlayacaksınız.

Harici MCP sunucusu dağıtma

Başlangıç komut dosyası Caddy ve FastMCP'yi yükler, mcp-sprockets sunucusunu 127.0.0.1:8080 üzerinde başlatır ve Caddy'yi ${MCP_DOMAIN} üzerinde HTTPS yayınlayacak şekilde yapılandırır.

Gemini Enterprise, bir MCP aracını (ör. get_sprockets ve get_sprocket_by_id) her çağırdığında sunucu:

  1. Arayan kaynağının IP'sini X-Forwarded-For başlığından (egress_source_ip) okuyun.
  2. Authorization: Bearer [access_token] üstbilgisini ayıklayın ve jetonu Google OAuth 2.0 doğrulama uç noktasına (https://oauth2.googleapis.com/tokeninfo?access_token=[token]) göre doğrulayın.
  3. "authenticated_user" ([user_email]) ile birlikte "egress_source_ip" değerini döndürün. Bu, harici MCP sunucusunun hem Cloud NAT statik IP'sini hem de son kullanıcı Google OAuth 2.0 kimliğini doğruladığını gösterir.
# 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"

MCP sunucusunun hazır olduğunu ve OAuth 2.0 tokeninfo doğrulamasını onaylayın.

Başlangıç komut dosyasının FastMCP ve Caddy'yi yüklemesi ve Let's Encrypt TLS sertifikasını sağlaması için birkaç dakika bekleyin.

# 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

sslip.io DNS çözümlemesini, Caddy tarafından sunulan Let's Encrypt TLS sertifikasını ve FastMCPtools/list yanıtını doğrulayın:

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

Örnek çıkış:

* 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}}]}}

Harici güvenlik duvarını kilitlemeden önce, mcp-sprockets kimlik doğrulamasının jetonu https://oauth2.googleapis.com/tokeninfo ile doğruladığını ve arayanın kaynak IP adresiyle birlikte "authenticated_user" e-posta adresinizi döndürdüğünü doğrulamak için Google OAuth 2.0 Bearer jetonu (gcloud auth print-access-token) ile bir test tools/call çalıştırın:

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

Örnek çıktı (güvenlik duvarı kilitlenmeden önce doğrudan Cloud Shell IP'nizi ve doğrulanmış Google OAuth e-postanızı gösterir):

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

Güvenlik duvarını Cloud NAT statik IP'siyle sınırlama

Harici VPC ağ güvenlik duvarı politikasını, TCP bağlantı noktası 443'nın trafiği yalnızca Cloud NAT statik harici IP'sinden (${NAT_EXT_IP}/32) kabul edecek şekilde güncelleyin:

# 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

Harici güvenlik duvarı politikası kurallarının mevcut olup olmadığını kontrol edin:

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

Cloud NAT statik IP'si dışındaki doğrudan bağlantıların artık engellendiğini kontrol edin:

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

Örnek çıkış:

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

MCP sunucusu bölümünü tamamladık. Şimdi Agent Registry bölümüne geçiyoruz.

7. Agent Registry

Agent Registry, yapay zeka ekosistemindeki tüm aracıların, MCP sunucularının ve uç noktaların (API'ler) merkezi bir envanteridir. Ayrıca, yapay zeka uygulamalarının kullanabileceği diğer kayıtlı araç ve hizmetleri listelemek, aramak ve keşfetmek için kullanılabilecek bir katalogdur. Agent Gateway, çıkış erişim denetimini zorunlu kılmak için kayıt veri modelini yönetim çerçevesi olarak kullanır. Çağrı aracısı ana hesabı için IAM rolü verme işlemleri, kayıt kaynağına bağlı politika ile karşılaştırılır.

Bu bölümde, MCP sunucusunu ve araç şemasını (toolspec.json) Agent Registry'ye kaydedeceksiniz. Gemini Enterprise'ın Agent Gateway aracılığıyla Google API'leri ve Hizmetleri ile etkileşimini desteklemek için, Gemini Enterprise'ın jetonlar için yetkilendirme kodu alışverişinde kullandığı Google API arayüzlerini belirten tek bir kayıt uç noktası hizmeti (oauth2-googleapis) de oluşturacaksınız.

MCP sunucusunu kaydetme

Gemini Enterprise'ın MCP sunucusunda bulunan araçları keşfetmesine izin vermek için hizmeti Agent Registry'ye kaydederken bir araç spesifikasyonları dosyası (cfg/toolspec.json) sağlayın.

MCP aracı spesifikasyonu oluşturma

# 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

MCP sunucusu hizmeti oluşturma

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

Agent Registry'de MCP sunucusunu doğrulama

Hizmetin, bölgedeki kayıtlı bir MCP sunucusu olarak listelendiğini, uç nokta URL'sini ve mevcut araçlarını doğrulayın:

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

Örnek çıkış:

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

Her araç için tam araç tanımlarını, giriş şemalarını ve davranış ek açıklamalarını kaydettiğini görmek üzere hizmet yapılandırma spesifikasyonunu görüntüleyin:

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

OAuth uç noktasını kaydetme

Gemini Enterprise DataConnector arka ucunun (yetkilendirme akışında OAuth istemcisi olarak hareket eder) Agent Gateway üzerinden Google OAuth 2.0 yetkilendirme sunucusuna (https://oauth2.googleapis.com/token) POST istekleri göndermesine izin vermek için jeton uç noktasının Agent Registry'ye kaydedilmesi gerekir. Böylece IAP, destination.is_registered == true'ı değerlendirebilir.

Uç nokta hizmeti oluşturma

# 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

Uç nokta kaydını doğrulama

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

Beklenen çıkış:

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

IAM erişim politikası

IAM erişim politikası, Gemini Enterprise uygulaması core_assistant aracısı kimliği tarafından istenen tüm kayıtlı hizmetler için bir izin politikası tanımladığından OAuth jetonu değişimi için ek IAM politikası bağlamaları gerekmez.

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

Ajan Kayıt Defteri bölümünü tamamladık. Şimdi Gemini Enterprise bölümüne geçiyoruz.

8. Gemini Enterprise

Bu bölümde, kimlik sağlayıcıyı, deneme lisansını ve Google Identity OAuth 2.0 istemci kimlik bilgilerini yapılandırır, Gemini Enterprise uygulaması (${GE_APP_ID}) oluşturur, giden çıkışı Agent Gateway'inize (${AGW_URI}) bağlar ve kayıtlı sprockets MCP sunucusunu OAuth 2.0 özel MCP veri deposu olarak bağlarsınız.

Gemini Enterprise uygulaması oluşturma

Aşağıdaki yöntemde, Gemini Enterprise uygulama kaynaklarını ve yapılandırmasını oluşturmak için discoveryengine.googleapis.com API'si kullanılır. Google Cloud Console kullanıcı arayüzünü kullanarak yapılandırma hakkında talimatlar için Uygulama oluşturma başlıklı makaleyi inceleyin.

# 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

Uygulama oluşturmayı doğrulama

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

Oluşturulan yapılandırmayı görmek için motor ayrıntılarını görüntüleyin:

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

Kimlik sağlayıcıyı etkinleştirme

Gemini Enterprise uygulamanızda son kullanıcı kimlik doğrulaması için kimlik sağlayıcı olarak Google Identity'yi etkinleştirin.

Aşağıdaki yöntemde, Gemini Enterprise uygulama kimlik sağlayıcısını yapılandırmak için discoveryengine.googleapis.com API'si kullanılır. Google Cloud Console kullanıcı arayüzünü kullanarak yapılandırmak için talimatları Kimlik sağlayıcıyı yapılandırma başlıklı makalede bulabilirsiniz.

# 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

Kimlik sağlayıcıyı doğrulama

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

Çıkış "idpType": "GSUITE", Google Identity sağlayıcısına karşılık gelir.

(İsteğe bağlı) Gemini Enterprise deneme lisansını etkinleştirme

Gemini Enterprise lisanslarının atandığı bir proje kullanıyorsanız bu adımı atlayabilirsiniz. Lisansı olmayan yeni bir proje kullanıyorsanız devam edin ve aşağıdaki adımları uygulayın.

Gemini Enterprise kullanıcı koltuklarına 30 gün boyunca hak kazandırmak için bir lisans yapılandırma kaynağı oluşturun. Bu işlem, varsayılan lisansı yeni deneme sürümüne ayarlar. Böylece, oturum açan her kullanıcıya otomatik olarak yer verilir:

# 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

Lisansın uygulandığını doğrulama

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

"subscriptionTerm": "SUBSCRIPTION_TERM_ONE_MONTH" ve "freeTrial": true olup olmadığını kontrol edin.

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

../free_trial_gemini" ve "enableLicenseAutoRegister": true olup olmadığını kontrol edin.

Gemini Enterprise'ın (OAuth 2.0 istemcisi) kullanıcı tarafından yetkilendirilmiş bir Google OAuth 2.0 hamiline ait jeton almasına ve bunu sizin adınıza mcp-sprocketskaynak sunucusuna sunmasına izin vermek için Google Auth Platform OAuth kullanıcı rızası ekranını yapılandırın ve projenizde bir web uygulaması OAuth 2.0 istemci kimliği oluşturun.

Projenizdeki Google Auth Platform Overview (Google Kimlik Doğrulama Platformuna Genel Bakış) için doğrudan Google Cloud Console URL'sini yazdırın:

# print google auth platform consent screen url
echo "https://console.cloud.google.com/auth/overview?project=${PROJ_ID}"
  1. URL'yi tarayıcınızda açın ve Başlayın'ı tıklayın (projeniz için henüz yapılandırılmadıysa).
  2. Uygulama Bilgileri bölümünde Uygulama adı'nı mcp-sprockets-oauth olarak ayarlayın ve e-posta adresinizi (${USER_IDENTITY}) Kullanıcı destek e-postası olarak seçip Sonraki'yi tıklayın.
  3. Kitle bölümünde Dahili'yi (hesabınız bir Google Workspace kuruluşuna aitse önerilir) veya Harici'yi (kişisel hesap kullanıyorsanız; Harici'yi seçerseniz **Kitle Test kullanıcıları** bölümüne ${USER_IDENTITY} ekleyin) seçin, ardından Sonraki'yi tıklayın.
  4. İletişim bilgileri bölümüne e-posta adresinizi girin, politika sözleşmesini kabul edin ve Oluştur'u tıklayın.

2. Web uygulaması OAuth 2.0 istemci kimliğini oluşturma

Clients (Müşteriler) sayfasının doğrudan Google Cloud Console URL'sini yazdırın:

# print google auth platform clients url
echo "https://console.cloud.google.com/auth/clients?project=${PROJ_ID}"
  1. URL'yi açın ve + İstemci oluştur'u tıklayın.
  2. Uygulama türü olarak Web uygulaması'nı seçin ve Ad'ı ge-mcp-sprockets-client olarak ayarlayın.
  3. Kullanıcılar adına hareket eden yapay zeka ajanı iş akışları için OAuth istemcisini belirlemek üzere Bu istemci, yapay zeka destekli bir ajan tarafından kullanılacak onay kutusunu işaretleyin.
  4. Yetkilendirilmiş yönlendirme URI'leri bölümünde + URI ekle'yi tıklayın ve Gemini Enterprise OAuth geri çağırma URI'sini ekleyin:
    • https://vertexaisearch.cloud.google.com/oauth-redirect
  5. Oluştur'u tıklayın, oluşturulan istemci kimliğini ve istemci gizli anahtarını kopyalayın ve bunları kabuk oturumunuza aktarın:

Önceki adımda oluşturulan OAuth 2.0 istemci kimliğini ve istemci gizli anahtarını ayarlayın:

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

İstemci kimliğinin ayarlandığını kontrol edin:

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

Agent Gateway'e bağlama

Gemini Enterprise'dan çıkan trafiği Agent Gateway üzerinden yönlendirmek, tüm yapay zeka temsilcisi aracı çağrıları için merkezi bir zorunluluk ve statik IP yönlendirme sınırı oluşturur:

  • Merkezi politika zorunluluğu: Agent Gateway, trafiğin aracı ortamından ayrılmadan önce giden araç isteklerini yetkilendirme politikalarına göre değerlendiren bir satır içi proxy görevi görür.
  • Belirleyici VPC ve Cloud NAT çıkışı: Gemini Enterprise'ı vpcEgress: ALL_TRAFFIC ile yapılandırılmış bir Agent Gateway'e bağlamak, araç çağrılarının PSC ağ eki üzerinden yönlendirilmesini ve ayrılmış Cloud NAT statik IP'niz kullanılarak çıkış yapılmasını sağlar.
  • Birleşik denetlenebilirlik: Bağlı tüm MCP sunucularında merkezi istek günlüğü ve denetim izleri sağlar.

Aşağıdakileri etkinleştirmek için motoru agentGatewaySetting yamalayın:

# 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

Temsilci ağ geçidi bağlamasını doğrulama

agentGatewaySetting bağlamasını onaylamak için uygulama yapılandırmasını alın:

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

Örnek çıkış:

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

Özel MCP sunucusu veri deposu oluşturma

Bu bölümde, Google Identity (https://accounts.google.com/o/oauth2/v2/auth ve https://oauth2.googleapis.com/token) ile yapılandırılmış bir OAuth 2.0 özel MCP veri deposu oluşturarak mcp-sprockets sunucusunu Gemini Enterprise'a bağlayacaksınız.

Discovery Engine API'yi kullanırken bu işlem iki adımdan oluşur:

  1. Oluşturma (:setUpDataConnector): Özel bir Collection kaynağı (${MCP_NAME}-collection-%timestamp) oluşturur, DataConnector (custom_mcp) ile auth_type: "OAUTH" öğesini ekler ve destekleyen DataStore (..._mcp_data) öğesini sağlar.
  2. Etkinleştir (PATCH .../dataConnector?updateMask=actionConfig): Ajan Kayıt Defteri aracı spesifikasyonunu ve Google Kimliği OAuth 2.0 parametrelerini kullanarak bağlayıcı işlemi çalışma zamanını (actionState: "ACTIVE") etkinleştirir ve DataStore (dataStoreIds) öğesini Gemini Enterprise Engine'ınıza bağlar.
# 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}"

Veri bağlayıcısı oluşturma

# 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

Veri bağlayıcı oluşturma işlemini doğrulama

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

"registry_mcp_server_name" alanının MCP sunucusu için Agent Registry UUID'siyle doldurulduğunu ve "auth_type" değerinin OAUTH olduğunu kontrol edin:

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

Google Cloud Console kullanıcı arayüzünde MCP sunucu kayıt defteri girişini görüntüleyin:

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

Veri bağlayıcısını etkinleştirme

# 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

Özel MCP sunucusu bağlantılarını doğrulama

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

Bağlı veri deposunu "dataStoreIds": ["mcp-sprockets-collection-[EPOCH]_mcp_data"] kontrol edin.

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

"state": "ACTIVE" ve "auth_type": "OAUTH" olup olmadığını kontrol edin.

Araç işlemleri

Gemini Enterprise kontrol panelinde mcp-sprockets-collection veri deposunu incelediğinizde İşlemler sekmesinin kullanılmadığını ve ↻ Özel işlemleri yeniden yükle düğmesinin devre dışı olduğunu görürsünüz. Bu, beklenen bir davranıştır.

Google Cloud Console kullanıcı arayüzünde veri deposu ayrıntıları sayfasını görüntüleyin:

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

Özel bir MCP sunucusunu Gemini Enterprise'a nasıl bağladığınıza bağlı olarak araç keşfi ve yönetimi iki şekilde ele alınır:

  • Doğrudan özel MCP (BYO_MCP iş akışı): Özel bir MCP sunucusunu Agent Registry olmadan doğrudan Gemini Enterprise'da yapılandırdığınızda araç kataloğunu (connectorModes: ["FEDERATED", "ACTIONS"]) veri deposu yönetir. tools/list şemasını getirmek için İşlemler sekmesini açıp ↻ Özel işlemleri yeniden yükle'yi tıklamanız ve kullanıcı arayüzünde tek tek araçları (add ve subtract) manuel olarak açıp kapatmanız gerekir.
  • Agent Registry'den İçe Aktarma (REGISTRY_MCP bu codelab'de kullanılan iş akışı): Agent Registry'den bir MCP sunucusu içe aktardığınızda Agent Registry, MCP uç noktası, arayüz meta verileri ve araç kataloğu (connectorModes: ["FEDERATED"]) için yetkili doğru kaynak olarak görev yapar. Gemini Enterprise, Agent Gateway ayarı aracılığıyla kayıtlı MCP araçlarını çalışma zamanında otomatik olarak etkinleştirir. Bu sayede, veri deposu kullanıcı arayüzünde işlemleri manuel olarak yeniden yüklemeniz veya değiştirmeniz gerekmez.

Gemini Enterprise bölümünü tamamladık. Şimdi Doğrulama bölümüne geçiyoruz.

9. Doğrula

Bu bölümde, tek seferlik Google OAuth 2.0 kullanıcı izni akışını tamamlayacak, Gemini Enterprise'dan harici mcp-sprockets sunucusunda MCP araçlarını çağıracak ve harici MCP sunucusunun, ayrılmış Cloud NAT statik IP'nizi (egress_source_ip) ve Google OAuth 2.0 kimliğinizi (authenticated_user) her ikisini de doğruladığını onaylayacaksınız.

Kullanıcı erişimi

Gemini Enterprise web uygulamasının URL'sini oluşturun:

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

Ajanı sorgulamadan önce, Gemini Enterprise'a Google kimliğiniz için erişim jetonu alma izni veren tek seferlik bir OAuth 2.0 izin akışını (${USER_IDENTITY}) tamamlamanız gerekir. Bu sayede Gemini Enterprise, giden araç çağrılarını Agent Gateway üzerinden doğrulayabilir. Böylece harici mcp-sprockets sunucusu, her istekte kimliğinizi doğrulayabilir.

  1. Tarayıcınızda ${GE_APP_USER_URL} adresini açıp Başlayın'ı tıklayın.
  2. Sohbet kutusunda Bağlayıcılar simgesini (yapboz parçası simgesi) ve mcp-sprockets-collection'nin yanındaki Yetkilendir'i tıklayın.
  3. Devam etmek için bir hesap seçmenizi isteyen yeni bir pencere açılır mcp-sprockets-oauth (yapılandırdığınız OAuth kullanıcı rızası ekranı uygulama adı). Burada kullanıcı hesabınızı (${USER_IDENTITY}) seçin.
  4. Google OAuth kullanıcı rızası ekranında, Google'ın (Kimlik Sağlayıcı) kullanıcı kimliğinizi (openid, email, profile) mcp-sprockets-oauth ile paylaşmasına izin veren istenen izinleri inceleyin, ardından Devam'ı tıklayın.
  5. Bağlayıcılar simgesini tekrar tıklayın ve mcp-sprockets-collection için açma/kapatma düğmesinin etkinleştirildiğini doğrulayarak yetkilendirmenin başarılı olduğunu onaylayın.

Test temsilcisi sorguları

Asistan sohbeti kullanıcı arayüzü testleri

Sohbette aşağıdaki test sorgusunu gönderin:

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

Sohbette ikinci bir sorgu deneyin:

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

Yardımcının doğru yanıtlar döndürdüğünü ve etkileşimli bir işlem alıntı rozeti gösterdiğini doğrulayın.

Örneğin, her yanıtın altındaki "Sprocket Lookup SPK-105 (5s)MCP aracı simgesiAgent Gatewaydaire içinde onay işareti simgesi" simgesi, aracın çalıştırıldığını onaylar.

Asistanın, "authenticated_user" ile eşleşen ${USER_IDENTITY} ve ayrılmış ${NAT_EXT_IP} ile eşleşen "egress_source_ip" dişli özelliklerini döndürdüğünü görün.

Asistan streamAssist API testleri

Kullanıcı hesabınız OAuth 2.0 bağlayıcısını yetkilendirdikten sonra default_assistant:streamAssist API'sini doğrudan CLI'dan da çağırabilir ve harici mcp-sprockets sunucusunun Cloud NAT statik IP'nizi (${NAT_EXT_IP}) ve doğrulanmış Google OAuth 2.0 kimliğinizi (${USER_IDENTITY}) birlikte döndürdüğünü doğrulayabilirsiniz:

Aşağıdaki test sorgusunu gönderin:

# 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

Örnek çıkış:

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

Başka bir sorgu deneyin:

# 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

Cloud Logging'deki günlükleri inceleme

Cloud Logging'deki günlükleri inceleyerek Gemini Enterprise'ın araç çağrılarını Agent Gateway, PSC ağ eki ve Cloud NAT üzerinden yönlendirdiğini doğrulayın.

Aracı ağ geçidi günlüklerini doğrulama

Agent Gateway'in isteği yakaladığını, Agent Registry'deki hedefi çözdüğünü, yetkilendirme politikasını değerlendirdiğini ve araç çağrısını ilettiğini doğrulayın:

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

Örnek çıkış:

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

Çıktının aşağıdakileri içerdiğini doğrulayın:

  • STATUS: 200 (başarılı yürütme) ve 202 (notifications/initialized el sıkışması).
  • SERVER_IP: Harici MCP sunucusu IP'si ve bağlantı noktası (${MCP_EXT_IP}:443).
  • MCP_METHOD & TOOL: MCP protokol dizisi (initialize, notifications/initialized, tools/list ve tools/call ile get_sprocket_by_id).
  • AUTHZ: ALLOWED (IAP yetkilendirmesi çıkışa izin veriyor).
  • REGISTRY_MCP: Çözümlenmiş aracı kayıt defteri kaynak kimliği (agentregistry-...).

Cloud NAT günlüklerini doğrulama

${MCP_EXT_IP}:443'ye bağlanırken Cloud NAT'in, giden bağlantıyı Agent Gateway PSC ağ eki IP'sinden (10.10.10.2) ayrılmış statik harici IPv4 adresinize (${NAT_EXT_IP}) çevirdiğini onaylayın:

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

Örnek çıkış:

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

Güvenlik duvarı günlüklerini doğrulama

Dahili güvenlik duvarı politikasının (fw-policy-${SLUG}-internal) aracı ağ geçidinden internet hedefine giden trafiğe izin verdiğini doğrulayın:

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

Harici güvenlik duvarı politikasının (fw-policy-${SLUG}-external), dahili ağın herkese açık NAT IP adresinden MCP sunucusuna giriş trafiğine izin verdiğini doğrulayın:

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

Doğrulama bölümünü tamamladık. Şimdi Temizleme bölümüne geçiyoruz.

10. Temizleme

Bu laboratuvarda oluşturulan kaynakları ve yapılandırmaları silmek için aşağıdaki adımları uygulayın.

Gemini Enterprise bileşenlerini kaldırma

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

OAuth 2.0 istemci kimlik bilgilerini (ge-mcp-sprockets-client) kaldırmak için Google Auth Platform Clients sayfasını açın ve ge-mcp-sprockets-client'nın yanındaki Sil (çöp kutusu) simgesini tıklayın:

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

MCP sunucusunu ve Agent Registry bileşenlerini kaldırma

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

Ajan ağ geçidi bileşenlerini kaldırma

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

Güvenlik duvarı bileşenlerini kaldırma

# 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

Ağ bileşenlerini kaldırma

# 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

Kuruluş politikası geçersiz kılmalarını ve yerel dosyaları kaldırma

# 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

Temizleme çalışması sona erdi. Şimdi Sonuç bölümüne geçiyoruz.

11. Sonuç

Tebrikler! Gemini Enterprise uygulamasının, harici IP izin verilenler listesine eklenmiş ve OAuth 2.0 ile korunmuş özel bir MCP sunucusundaki araçları güvenli bir şekilde keşfedip çağırmasını sağlayan uçtan uca bir mimari oluşturdunuz:

  • Statik IP VPC çıkışı (ALL_TRAFFIC & Cloud NAT): Tüm giden aracı ağ geçidi trafiği, bir PSC ağ eki (10.10.10.2) üzerinden yönlendirildi ve internete yönelik istekler, Cloud NAT kullanılarak ayrılmış bir statik harici IPv4 adresine (${NAT_EXT_IP}) çevrildi.
  • OAuth 2.0 MCP Kaynak Sunucusu ve Agent Registry: Katı bir kaynak IP güvenlik duvarı izin verilenler listesi (${NAT_EXT_IP}/32) ve Google OAuth 2.0 tokeninfo doğrulaması ile korunan harici bir akışa aktarılabilir HTTP FastMCP sunucusu (mcp-sprockets) dağıtıldı ve uç noktası ile araç şeması (get_sprockets ve get_sprocket_by_id) Agent Registry'ye kaydedildi.
  • Gemini Enterprise OAuth 2.0 entegrasyonu ve yönetimi: Gemini Enterprise uygulaması sağlandı, giden araç trafiği Agent Gateway'e bağlandı, kayıtlı MCP sunucusu OAuth 2.0 REGISTRY_MCP veri bağlayıcısı olarak eklendi ve Cloud Logging telemetrisiyle birlikte hem egress_source_ip hem de authenticated_user doğrulandı.

cosmopup

Cosmopup, Codelab'lerin çok iyi olduğunu düşünüyor.

Sırada ne var?

Bu geri bildirim formunu kullanarak yorum, soru veya düzeltme önerilerinizi paylaşabilirsiniz.

Teşekkürler!