Gemini Enterprise z bramą agenta, ruchem wychodzącym z sieci VPC i statycznym adresem IP Cloud NAT do zewnętrznego serwera MCP

1. Wprowadzenie

To ćwiczenie pokazuje, jak skonfigurować statyczne połączenie wychodzące IP dla Gemini Enterprise za pomocą Bramy agentów w trybie agent-to-anywhere (ruch wychodzący). Skonfigurujesz aplikację Gemini Enterprise tak, aby wywoływała niestandardowy serwer MCP (Model Context Protocol) chroniony przez ścisłą białą listę adresów IP źródła i uwierzytelnianie OAuth 2.0, kierując cały ruch wychodzący przez bramę agenta za pomocą konfiguracji szablonu łączności. Przyłącze sieci Private Service Connect (PSC) łączy bramę agenta z siecią VPC, a Cloud NAT zapewnia stabilny zewnętrzny adres IP dla ruchu wychodzącego z internetu.

Domyślnie połączenia wychodzące z Gemini Enterprise do publicznych punktów końcowych w internecie pochodzą z dynamicznych, współdzielonych pul adresów IP Google, których nie można przypiąć do pojedynczej reguły listy dozwolonych adresów IP należącej do klienta. Połączenie bramy agentów z AgentConnectivityTemplate w trybie ALL_TRAFFIC kieruje cały ruch wychodzący agenta do sieci VPC, w której Cloud NAT tłumaczy połączenia internetowe na zarezerwowany statyczny zewnętrzny adres IPv4 pod Twoją kontrolą, zachowując jednocześnie scentralizowane zarządzanie narzędziami MCP za pomocą Agent Registry i Identity-Aware Proxy (IAP).

Co utworzysz

  • Szablon łączności agenta (vpcEgress: ALL_TRAFFIC) i Brama agentów działająca w trybie ruchu wychodzącego (od agenta do dowolnego miejsca) z weryfikacją punktu końcowego Agent Registry
  • Sieć VPC, przyłącze sieci PSC, router Cloud Router i brama Cloud NAT powiązane z zarezerwowanym statycznym zewnętrznym adresem IPv4.
  • Zewnętrzny serwer zasobów HTTP MCP z możliwością przesyłania strumieniowego (mcp-sprockets) z protokołem TLS Caddy, ograniczony regułami zapory sieciowej ściśle do statycznego adresu IP Cloud NAT i weryfikujący tokeny dostępu Google OAuth 2.0 Bearer delegowane przez użytkownika względem https://oauth2.googleapis.com/tokeninfo
  • Ekran zgody OAuth 2.0 platformy Google Auth i dane uwierzytelniające klienta OAuth 2.0 aplikacji internetowej (accounts.google.com i oauth2.googleapis.com/token)
  • Wpis w katalogu serwerów MCP w Agent Registry i specyfikacja narzędzia (toolspec.json)
  • Rozszerzenie autoryzacji Identity-Aware Proxy (IAP) i zasady autoryzacji bramy dla bramy agentów
  • Aplikacja Gemini Enterprise powiązana z Bramą agentów i połączona z niestandardowym magazynem danych serwera MCP protokołu OAuth 2.0 zaimportowanym z Agent Registry

figure1

Rys. 1. Architektura ćwiczenia w Codelabs

Czego się dowiesz

  • Jak skonfigurować AgentConnectivityTemplate z vpcEgress: ALL_TRAFFIC, aby kierować cały ruch wychodzący z bramy agentów do sieci VPC
  • Jak zarezerwować statyczny zewnętrzny adres IPv4 i powiązać go z Cloud NAT w podsieci przyłącza sieci PSC
  • Jak wdrożyć zewnętrzny serwer zasobów HTTP MCP z możliwością przesyłania strumieniowego, który weryfikuje tokeny dostępu Google OAuth 2.0 (oauth2.googleapis.com/tokeninfo) i ogranicza zaporę sieciową wejścia do statycznego adresu IP Cloud NAT (${NAT_EXT_IP}/32)
  • Jak skonfigurować dane logowania klienta OAuth 2.0 Google Identity oraz zarejestrować serwer MCP i jego schemat narzędzia w Agent Registry
  • Jak połączyć zarejestrowany serwer MCP OAuth 2.0 z Gemini Enterprise i kierować wywołania narzędzi delegowane przez użytkownika przez bramę agenta
  • Jak weryfikować tłumaczenie statycznego adresu IP, weryfikację tożsamości użytkownika OAuth 2.0 (authenticated_user) i egzekwowanie zasad bramy za pomocą poleceń CLI i Cloud Logging

Wymagania

  • Projekt Google Cloud z włączonymi płatnościami
  • aktywną licencję Gemini Enterprise lub 30-dniowy okres próbny;
  • Uprawnienia IAM do udostępniania usług sieciowych, zasad organizacji, Gemini Enterprise i zasobów Agent Platform.
  • Powłoka zgodna z POSIX (bash lub zsh) z zainstalowanymi narzędziami Google Cloud CLI (gcloud), curl i jq.

To koniec wprowadzenia. Przejdźmy teraz do sekcji Pojęcia.

2. Pojęcia

Sekwencja wdrażania

To ćwiczenie wdraża najpierw infrastrukturę sieciową i zarządzania, aby ścieżki ruchu wychodzącego statycznego adresu IP i elementy sterujące bramą działały operacyjnie przed zarejestrowaniem i połączeniem narzędzi MCP z Gemini Enterprise:

  1. Infrastruktura sieciowa: rezerwuj statyczne zewnętrzne adresy IPv4 i udostępniaj sieć VPC ruchu wychodzącego, podsieć przyłącza PSC, przyłącze sieci PSC, router Cloud Router, bramę Cloud NAT i zewnętrzne reguły zapory sieciowej MCP.
  2. Szablon łączności agenta i brama agentów: wdróż AgentConnectivityTemplate (vpcEgress: ALL_TRAFFIC) i regionalny AgentGateway w trybie wychodzącym (AGENT_TO_ANYWHERE) z integracją z rejestrem agentów (registries).
  3. Zasady autoryzacji: skonfiguruj rozszerzenie autoryzacji IAP (AuthzExtension), zasadę autoryzacji bramy (AuthzPolicy) oraz ujednolicone zasady dostępu IAM w wersji 3 (AccessPolicy i PolicyBinding).
  4. Wdróż i zarejestruj serwer MCP: wdróż zewnętrzny mcp-sprockets serwer zasobów OAuth 2.0 za Caddy TLS, sprawdź jego egzekwowanie tokeninfo Google OAuth 2.0, zablokuj zaporę sieciową wejścia ściśle do statycznego adresu IP Cloud NAT (${NAT_EXT_IP}/32) i zarejestruj specyfikacje usługi i narzędzia (get_sprockets i get_sprocket_by_id) w Rejestrze agentów.
  5. Aplikacja Gemini Enterprise i klient OAuth 2.0: skonfiguruj dostawcę tożsamości Google, licencję próbną, ekran zgody OAuth 2.0 i dane uwierzytelniające klienta aplikacji internetowej (OAUTH_CLIENT_ID i OAUTH_CLIENT_SECRET), utwórz aplikację Gemini Enterprise (Engine) i powiąż wychodzący ruch z Agent Gateway (agentGatewaySetting).
  6. Importowanie niestandardowego łącznika danych MCP: utwórz i aktywuj REGISTRY_MCP łącznik danych (:setUpDataConnector) skonfigurowany za pomocą auth_type: "OAUTH", aby połączyć zarejestrowany serwer MCP obsługujący magazyn danych z aplikacją Gemini Enterprise.
  7. Sprawdź: przejdź jednorazowy proces zgody użytkownika na OAuth 2.0, wywołaj narzędzia MCP za pomocą asystenta Gemini Enterprise (potwierdzając zarówno egress_source_ip, jak i authenticated_user) i sprawdź egzekwowanie zasad oraz statyczne tłumaczenie NAT IP w Cloud Logging.

Architektura centralnego dostawcy tożsamości + serwera zasobów MCP chronionego przez OAuth

W przypadku wdrożeń w przedsiębiorstwach zarządzanie tożsamością i wykonywanie narzędzi odbywa się zgodnie ze standardowym podziałem ról OAuth 2.0 między scentralizowanego dostawcę tożsamości (serwer autoryzacji) a chroniony serwer zasobów MCP:

Rola OAuth 2.0

Komponent w tym ćwiczeniu

Odpowiedzialność

Właściciel zasobu

Użytkownik (${USER_IDENTITY})

Loguje się w aplikacji internetowej Gemini Enterprise i wyraża zgodę podczas jednorazowego 3-etapowego procesu autoryzacji OAuth 2.0.

Klient OAuth 2.0

Łącznik danych custom_mcpGemini Enterprise

Zawiera OAUTH_CLIENT_ID i OAUTH_CLIENT_SECRET, wymienia kod autoryzacji w oauth2.googleapis.com/token, przechowuje tokeny OAuth 2.0 użytkownika i przekazuje Authorization: Bearer [access_token] przy każdym wychodzącym wywołaniu narzędzia MCP.

Serwer autoryzacji

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

Uwierzytelnia użytkownika podczas przekierowania zgody w przeglądarce i wydaje tokeny dostępu i odświeżania OAuth 2.0 dla Gemini Enterprise.

Serwer zasobów

Zewnętrznymcp-sprockets serwer (https://mcp.[MCP_EXT_IP].sslip.io/mcp)

Wymusza tożsamość sieci w warstwie 3 za pomocą zapory sieciowej VPC (${NAT_EXT_IP}/32) i tożsamość użytkownika w warstwie 7, weryfikując nagłówek Authorization: Bearer [access_token] na podstawie https://oauth2.googleapis.com/tokeninfo.

Ponieważ przekierowanie zgody w przeglądarce (accounts.google.com) i wymiana tokenów w kanale zwrotnym (oauth2.googleapis.com/token) odbywają się w punktach końcowych OAuth 2.0 zarządzanych przez Google, zapora serwera MCP zewnętrznego otrzymuje tylko żądania JSON-RPC MCP w czasie działania (POST /mcp) z bramy agentów za pośrednictwem Cloud NAT, co pozwala na ścisłe ograniczenie zapory ruchu przychodzącego do ${NAT_EXT_IP}/32.

Model zasobów Discovery Engine

Aplikacja Gemini Enterprise (reprezentowana jako zasób Engine w interfejsie Discovery Engine API) to centralna warstwa orkiestracji i interfejs konwersacyjny dla użytkowników. Zarządza sesjami czatu użytkowników, opiera modele generatywne na danych przedsiębiorstwa i koordynuje dynamiczne wykonywanie narzędzi.

Aplikacje Gemini Enterprise wchodzą w interakcje z danymi i systemami za pomocą magazynów danych:

  • Magazyny danych o wiedzy: pozyskiwanie i indeksowanie treści statycznych (np. Cloud Storage, Dysk Google, BigQuery) na potrzeby generowania wspomaganego wyszukiwaniem (RAG).
  • Łączniki danych (dostawcy działań): łączą się z dynamicznymi interfejsami API innych firm lub interfejsami niestandardowymi. Niestandardowy magazyn danych serwera MCP udostępnia narzędzia zdefiniowane przez protokół Model Context Protocol (MCP), co umożliwia modelowi dynamiczne wywoływanie funkcji zewnętrznych podczas rozmowy.

Ruch wychodzący Gemini Enterprise

Gemini Enterprise kieruje żądania narzędzi niestandardowego serwera MCP do bramy agenta, gdy skonfigurowane są zarówno agentGatewaySetting w Engine, jak i use_agent_gateway_egress: true w DataConnector.

figure2

Rys. 2. Architektura ruchu wychodzącego Gemini Enterprise

Aplikacja Gemini Enterprise porządkuje routing narzędzi w 4 głównych obszarach:

    • Widżet (default_search_widget_config):�
    • Obsługuje interfejs klienta internetowego. Widżet otrzymuje od użytkownika prompty, wywołuje jednorazowe przekierowanie zgody użytkownika OAuth 2.0, gdy narzędzie wymaga autoryzacji, i inicjuje sesje czatu z silnikiem bazowym.
  1. Podstawowy asystent (assistants/default_assistant/agents/default/core_assistant):
    • Główny konwersacyjny agent rozumowania w silniku. Podczas oceny zapytania użytkownika Asystent podstawowy sprawdza dostępne narzędzia i przekazuje wykonanie zadania do wygenerowanego podagenta bramy agenta.
  2. Magazyn danych i łącznik danych:
    • DataStore: udostępniany w ramach dedykowanego Collection podczas działania :setUpDataConnector. Łączy (dataStoreIds) zaimportowane schematy narzędzi Agent Registry (get_sprockets, get_sprocket_by_id), typy argumentów i instrukcje agenta z Engine Gemini Enterprise.
    • DataConnector: zarządza połączeniem działania REGISTRY_MCP (createBapConnection: true) ze zdalnym serwerem MCP (instance_uri), rozwiązuje zasób serwera MCP z Agent Registry (registry_mcp_server_name), dołącza token okaziciela OAuth 2.0 przechowywany w magazynie użytkownika (Authorization: Bearer [access_token]) i włącza ruch wychodzący Bramy agentów (use_agent_gateway_egress: true).
  3. Agent Identity, Agent Registry i Brama agentów:
    • Gdy łącznik danych wysyła wywołanie narzędzia wychodzącego, kieruje ruch do bramy określonej w agentGatewaySetting. Core Assistant generuje token tożsamości SPIFFE potwierdzający tożsamość zadania: principal://agents.global.org-.../agents/default/core_assistant.
    • Brama agentów integruje się z Agent Registry za pomocą pola registries, aby dynamicznie rozpoznawać docelowe punkty końcowe i zarejestrowane schematy narzędzi, oceniać zasady autoryzacji za pomocą IAP i przekazywać dozwolone żądania (z zachowaniem nagłówka użytkownika Authorization: Bearer) do sieci VPC za pomocą AgentConnectivityTemplate.

Połączenie z siecią VPC bramy i statyczny NAT IP

Brama agentów obsługuje łączność z siecią VPC za pomocą zasobu AgentConnectivityTemplate, do którego odwołuje się agentConnectivityTemplate na bramie. Szablon egressNetworkConfig określa, jak ruch wchodzi do sieci VPC przez przyłącze sieci PSC:

  • PRIVATE_RANGES_ONLY (domyślnie): kieruje przez przyłączenie sieci PSC tylko prywatne zakresy adresów IP RFC 1918, RFC 6598 i klasy E. Ruch wychodzący do internetu omija sieć VPC i wychodzi bezpośrednio przez domyślne wyjście internetowe Google.
  • ALL_TRAFFIC (używane w tym ćwiczeniu): kieruje cały ruch wychodzący z bramy agentów – w tym ruch do publicznego internetu i zewnętrznych punktów końcowych MCP partnera – do podsieci VPC przez przyłączenie sieci PSC (10.10.10.2).

W trybie ALL_TRAFFIC podsieć połączenia PSC wymaga 2 konfiguracji:

  • Prywatny dostęp do Google--enable-private-ip-google-access: zapewnia, że wewnętrzne wywołania interfejsów Google Cloud API (*.googleapis.com) są nadal kierowane prywatnie w sieci Google.
  • Cloud Router i Cloud NAT (MANUAL_ONLY): ruch wychodzący do internetu, który wchodzi do podsieci przyłączenia PSC, jest kierowany domyślną ścieżką (0.0.0.0/0) przez Cloud NAT, który wykonuje translację źródłowych adresów sieciowych (SNAT) na zarezerwowany statyczny zewnętrzny adres IPv4 (${NAT_EXT_IP}). Zewnętrzne zapory sieciowe mogą więc ograniczać dostęp przychodzący tylko do ${NAT_EXT_IP}/32.

Ograniczenia i wymagania

Lokalizacja aplikacji Gemini Enterprise

Lokalizacja bramy agentów i NAT

Lokalizacja rejestru agentów

global

us-central1

us-central1, us lub global

us

us-central1

us-central1 lub us

eu

europe-west1

europe-west1 lub eu

To koniec części poświęconej koncepcjom. Przejdźmy teraz do sekcji Konfiguracja.

3. Konfiguracja

Wymagane role uprawnień

Aby ukończyć to ćwiczenie, potrzebujesz tych ról:

Domena

Wymagane role uprawnień

Projekt i IAM

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

Sieć i brama

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

Gemini Enterprise i rejestr

roles/discoveryengine.admin
roles/agentregistry.admin

Zadania

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

Dostrzegalność

roles/logging.viewer

Możesz też użyć szerokiego poziomu podstawowego, np. roles/owner, w połączeniu z roles/orgpolicy.policyAdmin (ponieważ sam poziom podstawowy roles/owner nie może modyfikować zasad organizacji).

Dostęp do projektu

W tym ćwiczeniu używany jest jeden projekt Google Cloud. Etapy konfiguracji wykorzystują interfejs wiersza poleceń gcloud i polecenia powłoki Linux.

Zacznij od uzyskania dostępu do wiersza poleceń projektu w chmurze Google Cloud:

Ustawianie identyfikatora projektu

# set target project id
gcloud config set project SET_YOUR_PROJECT_ID_HERE

Uwierzytelnianie sesji

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

Ustawianie zmiennych środowiskowych powłoki

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

Ustawianie domen zaufania tożsamości agenta

Instrukcja if-then-else sprawdza, czy projekt należy do organizacji, aby ustawić prawidłową domenę zaufania dla tożsamości agenta głównego.

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

Ustawianie projektu rozliczeniowego i projektu limitu

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

Tworzenie lokalnego katalogu plików konfiguracyjnych

# create config folder
mkdir -p cfg

Jeśli korzystasz z samodzielnie zarządzanej instalacji pakietu Google Cloud SDK (czyli poza Cloud Shell), zaktualizuj komponenty do najnowszej wersji.

# update gcloud cli
gcloud components update

Włącz usługi API

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

Zasady organizacji

Domyślne ograniczenia zasad organizacji zarządzanych w Google Cloud i zasady piaskownicy mogą ograniczać funkcje używane w tym Codelabie:

  • compute.vmExternalIpAccess: ogranicza zewnętrzne adresy IPv4 na maszynach wirtualnych Compute Engine w organizacjach w trybie sandbox.
  • discoveryengine.managed.disableCustomMcpServerConnector: ogranicza tworzenie łączników danych, które używają niestandardowego serwera MCP (custom_mcp) jako źródła danych (domyślnie wymuszane).
  • discoveryengine.managed.allowedEgressFqdns: ogranicza domeny ruchu wychodzącego (instance_uri w pełni kwalifikowane nazwy domen) w przypadku łączników danych, gdy aktywne są ustawienia usługi VPC (VPC-SC) lub projekt jest wymieniony w enforcedProjects.
  • discoveryengine.managed.allowedDataSources: ogranicza dozwolone typy łączników danych (dataSource), gdy aktywne są ustawienia usługi VPC lub projekt jest wymieniony w enforcedProjects.

zastępować na poziomie projektu wszelkie odziedziczone ograniczenia zasad organizacji;

Wyłączanie niestandardowego ograniczenia MCP

# 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

Wyłączanie ograniczeń warunkowego oprogramowania sprzęgającego dane

# 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

Wyłączanie ograniczenia zasady dostępu

# 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

Zezwalanie na zewnętrzne adresy IP

# 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

Weryfikowanie zasad organizacji

Sprawdź, czy compute.vmExternalIpAccess jest ustawiona na allowAll: True, a pozostałe zasady mają wartość enforce: False:

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

Weryfikowanie powiązań agenta usługi (środki ostrożności)

W nowym projekcie Google Cloud automatycznie udostępnia agenta usługi Brama agentów i przyznaje mu uprawnienia roles/agentgateway.serviceAgent, gdy po raz pierwszy włączona jest usługa networkservices.googleapis.com. Jeśli ponownie używasz istniejącego projektu, w którym wcześniejsze czyszczenie mogło usunąć domyślne powiązania agenta usługi, uruchom te polecenia, aby upewnić się, że tożsamość i powiązanie ról są nienaruszone:

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

To kończy część konfiguracji. Przejdź do sekcji Sieć.

4. Sieć

W tej sekcji zarezerwujesz statyczne zewnętrzne adresy IPv4, utworzysz wewnętrzną sieć VPC ruchu wychodzącego i odizolowaną zewnętrzną sieć VPC, udostępnisz przyłącze sieci PSC, skonfigurujesz Cloud NAT i utworzysz reguły zapory sieciowej.

Rezerwowanie statycznych zewnętrznych adresów IP

Zarezerwuj 2 regionalne statyczne zewnętrzne adresy IPv4 dla Cloud NAT i zewnętrznej maszyny wirtualnej serwera MCP:

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

Weryfikowanie statycznych zewnętrznych adresów IP

Gemini Enterprise wymaga, aby zdalne punkty końcowe MCP używały protokołu HTTPS z publicznie zaufanym certyfikatem TLS. Zamiast rejestrować niestandardową domenę na potrzeby tego laboratorium, użyjesz sslip.io, bezpłatnej usługi DNS z wieloznacznym symbolem, która rozpoznaje dowolną nazwę hosta zawierającą adres IP (np. mcp.[IP].sslip.io) i kieruje ją bezpośrednio z powrotem do tego adresu IP. Ponieważ urzędy certyfikacji, takie jak Let's Encrypt, nie wydają certyfikatów dla samych adresów IP, ta nazwa hosta sslip.io zapewnia odwrotnemu serwerowi proxy Caddy prawidłową nazwę domeny, aby automatycznie udostępnić zaufany certyfikat TLS dla serwera MCP.

Wyeksportuj oba adresy IPv4 i utwórz nazwę domeny sslip.io oraz adres URL zewnętrznego serwera MCP:

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

Przykładowe dane wyjściowe:

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

Tworzenie sieci wewnętrznej

Jeśli szablon łączności bramy agenta jest skonfigurowany do używania egressNetworkConfig z networkAttachment, podsieć hostująca przyłączenie sieci PSC musi mieć co najmniej blok CIDR /28 i musi mieć włączony prywatny dostęp do Google (--enable-private-ip-google-access).

Utwórz globalną sieć VPC na potrzeby wychodzącego ruchu wewnętrznego z bramy agenta:

# 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

Tworzenie reguł zapory sieciowej ruchu wewnętrznego

Utwórz zasadę zapory sieciowej, która zezwala na cały ruch wychodzący z włączonym logowaniem. Będzie on używany do monitorowania ruchu wychodzącego z bramy agentów do wewnętrznej sieci VPC. Cloud NGFW obsługuje poziomy Essentials i Standard w zakresie zabezpieczeń sieci i monitorowania ruchu.

# 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

Tworzenie przyłącza sieci PSC

Utwórz przyłącze sieci Private Service Connect (PSC) skonfigurowane tak, aby automatycznie akceptować połączenia z Bramy agentów. Przyłącze sieciowe tworzy po stronie sieci VPC konsumenta połączenie, które bezpiecznie łączy się ze stroną producenta bramy agenta w przypadku wychodzącego ruchu wychodzącego. Więcej informacji o wymaganiach dotyczących podsieci i specyfikacjach zakresu adresów IP znajdziesz w artykule Konfigurowanie łączności VPC.

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

Weryfikowanie przyłącza sieci PSC

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

Pobierz identyfikator URI zasobu przyłącza sieci PSC i zapisz go w zmiennej środowiskowej PSC_NA_URI. Ten URI będzie używany w konfiguracji bramy agenta (networkConfig.egress.networkAttachment) do udostępniania interfejsu PSC na potrzeby ruchu wychodzącego z sieci do sieci VPC:

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

Tworzenie Cloud NAT

Cloud NAT służy do tłumaczenia źródłowego adresu IP ruchu wychodzącego z bramy agenta na zarezerwowany publiczny adres IP w celu kierowania ruchu przez publiczny internet.

Tylko źródła z podsieci przyłącza sieci ruchu wychodzącego bramy agentów są uznawane za kwalifikujące się do korzystania z Cloud NAT.

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

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

Weryfikowanie Cloud NAT

Sprawdź stan Cloud NAT i upewnij się, że skonfigurowano oczekiwane źródło natIP:

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

Przykładowe dane wyjściowe:

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

Tworzenie sieci zewnętrznej

Utwórz osobną, odizolowaną sieć VPC, w której będzie hostowana zewnętrzna maszyna wirtualna serwera MCP.

# 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

Tworzenie zewnętrznych reguł zapory sieciowej

Utwórz 2 reguły zapory sieciowej zezwalające na ruch przychodzący w zewnętrznej sieci VPC:

  • 2001: zezwala na przychodzący port TCP 80, aby Let's Encrypt mogło ukończyć wyzwanie związane z weryfikacją domeny ACME HTTP-01 dla ${MCP_DOMAIN}.
  • 2002: początkowo zezwala na ruch przychodzący na porcie TCP 443 z 0.0.0.0/0, aby zweryfikować gotowość TLS i wymuszanie OAuth 2.0 tokeninfo z lokalnej powłoki przed ścisłym ograniczeniem go do ${NAT_EXT_IP}/32.
# create fw policy
gcloud compute network-firewall-policies create fw-policy-${SLUG}-external --global
# create fw policy rules
gcloud compute network-firewall-policies rules create 2001 \
  --description="allow in any http" \
  --firewall-policy=fw-policy-${SLUG}-external \
  --global-firewall-policy \
  --action=allow \
  --direction=INGRESS \
  --layer4-configs=tcp:80 \
  --src-ip-ranges=0.0.0.0/0 \
  --dest-ip-ranges=240.240.240.0/24 \
  --enable-logging

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

To wszystko, jeśli chodzi o sieć. Przejdźmy teraz do sekcji Brama agenta.

5. Brama agentów

W tej sekcji wdrożysz szablon łączności agenta z vpcEgress: ALL_TRAFFIC, wdrożysz regionalną bramę agentów, przekażesz autoryzację do Identity-Aware Proxy (IAP) i określisz reguły ujednoliconych zasad dostępu IAM, aby zarządzać wychodzącymi żądaniami sieciowymi.

Tworzenie szablonu połączenia

Specyfikacja szablonu połączenia określa:

  • egressNetworkConfig.networkAttachment: wskazuje przyłącze sieci PSC, które łączy bramę agentów z siecią VPC.
  • egressNetworkConfig.vpcEgress: ustaw na ALL_TRAFFIC, aby wszystkie połączenia wychodzące agenta (w tym publiczne punkty końcowe MCP w internecie) były kierowane do sieci VPC i wychodziły z niej przy użyciu translacji źródłowego adresu IP Cloud NAT.

Utwórz i zaimportuj plik konfiguracji szablonu połączenia:

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

Tworzenie bramy agenta

Specyfikacja bramy agenta określa:

  • agentConnectivityTemplate: wskazuje szablon łączności, dzięki czemu brama może używać przyłącza sieci PSC do połączenia z siecią VPC.
  • registries: łączy bramę z regionalnym Agent Registry, aby rozwiązywać skatalogowane punkty końcowe MCP i schematy narzędzi.

Utwórz i zaimportuj plik konfiguracji bramy agentów:

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

Sprawdzanie wdrożenia bramy agentów

Potwierdź konfigurację Agent Registry i szablonu połączenia:

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

Przykładowe dane wyjściowe:

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

Sprawdź przyłącze sieci PSC, aby potwierdzić połączenie z bramą:

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

Przykładowe dane wyjściowe:

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

Przekazywanie autoryzacji

Brama agentów zabezpiecza i kontroluje ruch wychodzący narzędzi za pomocą zasad autoryzacji (networksecurity.authzPolicies) zintegrowanych z ujednoliconymi zasadami dostępu (UAP) Identity-Aware Proxy (IAP).

Chociaż brama agentów obsługuje podstawowe reguły wbudowane ALLOW i DENY, środowiska firmowe wymagają scentralizowanego zarządzania opartego na tożsamości. Za pomocą ujednoliconych zasad dostępu (UAP) (lub zasad dostępu) możesz zarządzać regułami ruchu wychodzącego za pomocą standardowych zasad dostępu uprawnień w wersji 3.

figure3

Rys. 3. Architektura autoryzacji

Proces autoryzacji łączy 3 komponenty:

  1. Zasady autoryzacji bramy (authzPolicy):
    • Zasób regionalny kierowany na bramę agenta.
    • Skonfigurowane za pomocą policyProfile: REQUEST_AUTHZ i action: CUSTOM, aby kierować wszystkie wychodzące kontrole autoryzacji do rozszerzenia autoryzacji IAP.
  2. Rozszerzenie usługi IAP (authzExtension):
    • Zasób regionalny, który deleguje autoryzację żądań do Identity-Aware Proxy (iap.googleapis.com).
    • Ocenia zasady w trybie ENFORCE, korzystając z wersji zasad V2.
  3. Ujednolicone zasady dostępu i powiązania IAM (accessPolicy i policyBinding):
    • Zasoby globalnych uprawnień w wersji 3 zawierające szczegółowe reguły dostępu.
    • Uwierzytelnia tożsamość podmiotu SPIFFE wywołującego agenta, weryfikuje uniwersalne uprawnienie iap.googleapis.com/resources.egressViaIAP i ocenia warunki języka Common Expression Language (CEL) na podstawie atrybutów miejsca docelowego.

Wdrażanie rozszerzenia autoryzacji

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

Weryfikacja rozszerzenia autoryzacji

Sprawdź, czy rozszerzenie autoryzacji jest aktywne:

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

Wdrażanie zasady autoryzacji

Utwórz konfigurację zasady autoryzacji network-security, która jest kierowana na bramę agentów i deleguje weryfikację żądań na rozszerzenie autoryzacji dla IAP:

# create authz policy config file
cat > cfg/${AGW_NAME}-authz-policy-iap.yaml << EOF
name: ${AGW_NAME}-authz-policy-iap
target:
  resources:
    - "projects/${PROJ_ID}/locations/${REGION}/agentGateways/${AGW_NAME}"
policyProfile: REQUEST_AUTHZ
action: CUSTOM
customProvider:
  authzExtension:
    resources:
      - "projects/${PROJ_ID}/locations/${REGION}/authzExtensions/${AGW_NAME}-svc-ext-authz-iap"
EOF
# import authz policy config file (create authz policy)
gcloud network-security authz-policies import ${AGW_NAME}-authz-policy-iap \
  --source=cfg/${AGW_NAME}-authz-policy-iap.yaml \
  --location=${REGION}

Sprawdzanie zasad autoryzacji

Sprawdź, czy zasady autoryzacji są aktywne:

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

Tworzenie zasad dostępu uprawnień

Brama agentów deleguje teraz sprawdzanie autoryzacji do IAP i rozwiązuje metadane miejsca docelowego z Agent Registry. Następnie zdefiniuj regułę ujednoliconych zasad dostępu uprawnień, która będzie regulować wykonywanie narzędzi wychodzących.

IAP ocenia wyrażenia atrybutów CEL na podstawie tych atrybutów miejsca docelowego w Agent Registry:

  • Stan rejestracji (destination.is_registered):
    • Wartość logiczna (true/false) wskazująca, czy miejsce docelowe jest skatalogowane w Agent Registry.
  • Nazwa serwera MCP (destination.agent_registry.mcp_server.name):
    • Kanoniczna nazwa zasobu serwera MCP zarejestrowana w Agent Registry.
  • Metoda MCP (destination.agent_registry.mcp_server.method):
    • Wywoływana metoda MCP (np. tools/call, tools/list, initialize).
  • Nazwa narzędziadestination.agent_registry.mcp_server.tool.name:
    • Nazwa wywołanego narzędzia (np. get_sprocket_by_id lub get_sprockets), która umożliwia precyzyjną autoryzację na poziomie narzędzia na zarejestrowanych serwerach MCP.

Definiowanie reguły zasady dostępu uprawnień

Manifest reguły zasady uprawnień określa:

  • Podmioty: tożsamość podmiotu SPIFFE reprezentująca agenta podstawowego asystenta Gemini Enterprise.
  • Uprawnienia: uniwersalne uprawnienie iap.googleapis.com/resources.egressViaIAP wymagane w przypadku całego ruchu wychodzącego objętego IAP.
  • Warunki: wyrażenie CEL (destination.is_registered == true), które zapewnia, że agent może wywoływać tylko punkty końcowe katalogowane w Agent Registry.

Utwórz plik manifestu reguły zasady:

# 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

Wdrażanie zasad dostępu uprawnień

Utwórz globalną zasadę dostępu uprawnień, korzystając z reguł zdefiniowanych w pliku manifestu:

# 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

Sprawdzanie zasady dostępu uprawnień

Sprawdź, czy zasada dostępu uprawnień została utworzona, i zbadaj szczegóły reguły:

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

Przykładowe dane wyjściowe:

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

Powiązywanie zasad dostępu uprawnień z projektem

Aby aktywować egzekwowanie we wszystkich bramach agentów w projekcie, utwórz powiązanie zasad, które dołącza zasady dostępu IAM do zasobu projektu:

# 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

Sprawdzanie powiązania zasady dostępu uprawnień

Sprawdź, czy aktywne punkty wiązania zasad są powiązane z odpowiednimi zasadami i odpowiednim celem:

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

To wszystko, jeśli chodzi o bramę agenta. Przejdźmy teraz do sekcji poświęconej serwerowi MCP.

6. Serwer MCP

W tej sekcji wdrażasz zewnętrzny serwer zasobów OAuth 2.0 FastMCP (mcp-sprockets) udostępniający narzędzia get_sprockets i get_sprocket_by_id oraz sprawdzasz, czy kryptograficznie weryfikuje tokeny dostępu Google OAuth 2.0 względem https://oauth2.googleapis.com/tokeninfo. Następnie ograniczysz zewnętrzną regułę zapory sieciowej tylko do statycznego adresu IP usługi Cloud NAT.

Wdrażanie zewnętrznego serwera MCP

Skrypt startowy instaluje Caddy i FastMCP, uruchamia serwer mcp-sprockets na porcie 127.0.0.1:8080 i konfiguruje Caddy do obsługi protokołu HTTPS na porcie ${MCP_DOMAIN}.

Za każdym razem, gdy Gemini Enterprise wywołuje narzędzie MCP (np. get_sprockets i get_sprocket_by_id), serwer:

  1. Odczytuje źródłowy adres IP wywołującego z nagłówka X-Forwarded-For (egress_source_ip).
  2. Wyodrębnij nagłówek Authorization: Bearer [access_token] i zweryfikuj token w punkcie końcowym weryfikacji Google OAuth 2.0 (https://oauth2.googleapis.com/tokeninfo?access_token=[token]).
  3. Zwróć "authenticated_user" ([user_email]) wraz z "egress_source_ip", co potwierdza, że zewnętrzny serwer MCP zweryfikował zarówno statyczny adres IP Cloud NAT, jak i tożsamość użytkownika Google OAuth 2.0.
# 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"

Sprawdzanie gotowości serwera MCP i weryfikacja OAuth 2.0 tokeninfo

Poczekaj kilka minut, aż skrypt startowy zainstaluje FastMCP i Caddy oraz udostępni certyfikat protokołu TLS Let's Encrypt.

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

Sprawdź rozpoznawanie nazw DNS sslip.io, certyfikat TLS Let's Encrypt obsługiwany przez Caddy i odpowiedź FastMCPtools/list:

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

Przykładowe dane wyjściowe:

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

Zanim zablokujesz zewnętrzną zaporę, przeprowadź test tools/call, przekazując token dostępu Google OAuth 2.0 (gcloud auth print-access-token), aby sprawdzić, czy mcp-sprockets weryfikuje token na podstawie https://oauth2.googleapis.com/tokeninfo i zwraca Twój adres e-mail "authenticated_user" wraz z adresem IP źródła wywołania:

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

Przykładowe dane wyjściowe (zawierające bezpośredni adres IP Cloud Shell przed zablokowaniem zapory sieciowej i zweryfikowany adres e-mail Google OAuth):

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

Zablokuj zaporę sieciową na statyczny adres IP Cloud NAT

Zaktualizuj zasadę zapory sieciowej zewnętrznej sieci VPC, aby port TCP 443 akceptował ruch tylko ze statycznego zewnętrznego adresu IP Cloud NAT (${NAT_EXT_IP}/32):

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

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

Sprawdź, czy reguły zewnętrznych zasad zapory sieciowej są na miejscu:

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

Sprawdź, czy bezpośrednie połączenia poza statycznym adresem IP Cloud NAT są teraz blokowane:

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

Przykładowe dane wyjściowe:

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

To wszystko, jeśli chodzi o serwer MCP. Przejdźmy teraz do sekcji Agent Registry.

7. Rejestr agentów

Rejestr agentów to scentralizowany spis wszystkich agentów, serwerów MCP i punktów końcowych (interfejsów API) w ekosystemie AI. Jest to też katalog, w którym można wyświetlać, wyszukiwać i odkrywać inne zarejestrowane narzędzia i usługi do wykorzystania w aplikacjach AI. Brama agentów używa modelu danych rejestru jako platformy zarządzania do egzekwowania kontroli dostępu wychodzącego. Uprawnienia roli IAM dla podmiotów zabezpieczeń wywołujących agentów są sprawdzane pod kątem zasad powiązanych z zasobem rejestru.

W tej sekcji zarejestrujesz Serwer MCP i jego schemat narzędzia (toolspec.json) w Agent Registry. Aby umożliwić Gemini Enterprise interakcję z interfejsami API i usługami Google za pomocą Bramy agentów, utworzysz też pojedynczą usługę punktu końcowego rejestru (oauth2-googleapis), która określa interfejsy API Google używane przez Gemini Enterprise do wymiany kodu autoryzacji na tokeny.

Rejestrowanie serwera MCP

Aby umożliwić Gemini Enterprise wykrywanie narzędzi dostępnych na Serwerze MCP, podczas rejestrowania usługi w Agent Registry podaj plik specyfikacji narzędzi (cfg/toolspec.json).

Tworzenie specyfikacji narzędzia MCP

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

Tworzenie usługi serwera MCP

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

Weryfikowanie serwera MCP w rejestrze agentów

Sprawdź, czy usługa jest wymieniona jako zarejestrowany serwer MCP w regionie wraz z adresem URL punktu końcowego i dostępnymi narzędziami:

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

Przykładowe dane wyjściowe:

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

Wyświetl specyfikację konfiguracji usługi, aby sprawdzić, czy rejestruje ona dokładne definicje narzędzi, schematy danych wejściowych i adnotacje dotyczące działania każdego narzędzia:

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

Rejestrowanie punktu końcowego OAuth

Aby backend Gemini Enterprise DataConnector (pełniący rolę klienta OAuth w procesie autoryzacji) mógł wysyłać żądania POST do serwera autoryzacji Google OAuth 2.0 (https://oauth2.googleapis.com/token) za pomocą Bramy agentów, punkt końcowy tokena musi być zarejestrowany w Agent Registry, aby IAP mógł ocenić destination.is_registered == true.

Tworzenie usługi punktu końcowego

# 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

Weryfikowanie rejestracji punktu końcowego

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

Oczekiwane dane wyjściowe:

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

Zasady dostępu uprawnień

Zasady dostępu IAM definiują zasadę zezwalającą na każdą zarejestrowaną usługę, o którą prosi tożsamość agenta aplikacji Gemini Enterprise core_assistant, więc do wymiany tokenów OAuth nie są wymagane żadne dodatkowe powiązania zasad uprawnień.

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

To koniec części poświęconej rejestrowi agentów. Przejdźmy teraz do sekcji Gemini Enterprise.

8. Gemini Enterprise

W tej sekcji skonfigurujesz dostawcę tożsamości, licencję próbną i dane logowania klienta OAuth 2.0 Google Identity, utworzysz aplikację Gemini Enterprise (${GE_APP_ID}), powiążesz wychodzący ruch wychodzący z bramą agenta (${AGW_URI}) i połączysz zarejestrowany serwer MCP sprockets jako niestandardowy magazyn danych MCP OAuth 2.0.

Tworzenie aplikacji Gemini Enterprise

Poniższa metoda korzysta z interfejsu discoveryengine.googleapis.com API do tworzenia zasobów i konfiguracji aplikacji Gemini Enterprise. Instrukcje dotyczące konfigurowania za pomocą interfejsu konsoli Google Cloud znajdziesz w sekcji Tworzenie aplikacji.

# 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

Weryfikowanie utworzenia aplikacji

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

Wyświetl szczegóły silnika, aby zobaczyć utworzoną konfigurację:

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

Włączanie dostawcy tożsamości

Włącz tożsamość Google jako dostawcę tożsamości do uwierzytelniania użytkowników w aplikacji Gemini Enterprise.

Poniższa metoda korzysta z interfejsu discoveryengine.googleapis.com API do skonfigurowania dostawcy tożsamości aplikacji Gemini Enterprise. Instrukcje dotyczące konfiguracji za pomocą interfejsu konsoli Google Cloud znajdziesz w sekcji Konfigurowanie dostawcy tożsamości.

# 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

Weryfikacja dostawcy tożsamości

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

Dane wyjściowe "idpType": "GSUITE" odpowiadają dostawcy tożsamości Google.

Włączanie licencji próbnej Gemini Enterprise (opcjonalnie)

Jeśli używasz projektu, do którego przypisane są licencje Gemini Enterprise, możesz pominąć ten krok. Jeśli używasz nowego projektu bez licencji, przejdź dalej i wykonaj te czynności.

Utwórz zasób konfiguracji licencji, aby przyznać użytkownikom Gemini Enterprise licencje na 30 dni. Spowoduje to ustawienie nowej wersji próbnej jako domyślnej licencji, dzięki czemu każdy użytkownik logujący się w usłudze automatycznie otrzyma miejsce:

# 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

Sprawdzanie, czy licencja została zastosowana

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

Sprawdź, czy są dostępne "subscriptionTerm": "SUBSCRIPTION_TERM_ONE_MONTH" i "freeTrial": true.

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

Sprawdź, czy są dostępne ../free_trial_gemini" i "enableLicenseAutoRegister": true.

Aby umożliwić Gemini Enterprise (klientowi OAuth 2.0) uzyskanie delegowanego przez użytkownika tokena dostępu Google OAuth 2.0 i przekazanie go w Twoim imieniu do mcp-sprocketsserwera zasobów, skonfiguruj ekran zgody OAuth na platformie uwierzytelniania Google i utwórz w projekcie identyfikator klienta OAuth 2.0 aplikacji internetowej.

Wydrukuj bezpośredni adres URL konsoli Google Cloud dla przeglądu platformy uwierzytelniania Google w projekcie:

# print google auth platform consent screen url
echo "https://console.cloud.google.com/auth/overview?project=${PROJ_ID}"
  1. Otwórz adres URL w przeglądarce i kliknij Rozpocznij (jeśli nie został jeszcze skonfigurowany dla Twojego projektu).
  2. W sekcji Informacje o aplikacji ustaw Nazwę aplikacji na mcp-sprockets-oauth i wybierz swój adres e-mail (${USER_IDENTITY}) jako Adres e-mail dla użytkowników potrzebujących pomocy, a następnie kliknij Dalej.
  3. W sekcji Odbiorcy wybierz Wewnętrzny (zalecane, jeśli Twoje konto należy do organizacji Google Workspace) lub Zewnętrzny (jeśli używasz konta osobistego; jeśli wybierzesz Zewnętrzny, dodaj ${USER_IDENTITY} w sekcji **Odbiorcy – użytkownicy testowi**), a potem kliknij Dalej.
  4. Wpisz adres e-mail w sekcji Informacje kontaktowe, zaakceptuj umowę dotyczącą zasad i kliknij Utwórz.

2. Tworzenie identyfikatora klienta OAuth 2.0 aplikacji internetowej

Wydrukuj bezpośredni adres URL konsoli Google Cloud do strony Klienci:

# print google auth platform clients url
echo "https://console.cloud.google.com/auth/clients?project=${PROJ_ID}"
  1. Otwórz adres URL i kliknij + Utwórz klienta.
  2. Jako Typ aplikacji wybierz Aplikacja internetowa, a w przypadku Nazwy ustaw wartość ge-mcp-sprockets-client.
  3. Zaznacz pole wyboru Tego klienta będzie używać agent oparty na AI, aby wyznaczyć klienta OAuth dla przepływów pracy agenta AI działającego w imieniu użytkowników.
  4. W sekcji Autoryzowane identyfikatory URI przekierowania kliknij + Dodaj identyfikator URI i dodaj identyfikator URI wywołania zwrotnego OAuth Gemini Enterprise:
    • https://vertexaisearch.cloud.google.com/oauth-redirect
  5. Kliknij Utwórz, skopiuj wygenerowane wartości Client ID (Identyfikator klienta) i Client secret (Tajny klucz klienta) i wyeksportuj je w sesji powłoki:

Ustaw identyfikator klienta OAuth 2.0 i tajny klucz klienta wygenerowane w poprzednim kroku:

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

Sprawdź, czy identyfikator klienta jest ustawiony:

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

Tworzenie powiązania z bramą agentów

Kierowanie ruchu wychodzącego z Gemini Enterprise przez bramę agentów tworzy scentralizowaną granicę egzekwowania i kierowania statycznego adresu IP dla wszystkich wywołań narzędzi agentów AI:

  • Centralne egzekwowanie zasad: Brama agentów działa jako wbudowany serwer proxy, który ocenia wychodzące żądania narzędzi pod kątem zasad autoryzacji, zanim ruch opuści środowisko agenta.
  • Deterministyczny ruch wychodzący z sieci VPC i Cloud NAT: powiązanie Gemini Enterprise z bramą agentów skonfigurowaną za pomocą vpcEgress: ALL_TRAFFIC zapewnia, że wywołania narzędzi są kierowane przez przyłącze sieci PSC i wychodzą przy użyciu zarezerwowanego statycznego adresu IP Cloud NAT.
  • Ujednolicona kontrola: zapewnia scentralizowane rejestrowanie żądań i rejestry kontrolne na wszystkich połączonych serwerach MCP.

Zastosuj poprawkę do silnika agentGatewaySetting, aby włączyć:

# 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

Sprawdzanie powiązania bramy agenta

Pobierz konfigurację aplikacji, aby potwierdzić powiązanie agentGatewaySetting:

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

Przykładowe dane wyjściowe:

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

Tworzenie magazynu danych niestandardowego serwera MCP

W tej sekcji połączysz serwer mcp-sprockets z Gemini Enterprise, tworząc niestandardowy magazyn danych MCP OAuth 2.0 skonfigurowany za pomocą Google Identity (https://accounts.google.com/o/oauth2/v2/auth i https://oauth2.googleapis.com/token).

W przypadku interfejsu Discovery Engine API jest to proces dwuetapowy:

  1. Utwórz (:setUpDataConnector): tworzy dedykowany zasób Collection (${MCP_NAME}-collection-%timestamp), dołącza DataConnector (custom_mcp) z auth_type: "OAUTH" i inicjuje jego zasób zapasowy DataStore (..._mcp_data).
  2. Aktywuj (PATCH .../dataConnector?updateMask=actionConfig): aktywuje środowisko wykonawcze działania łącznika (actionState: "ACTIVE") przy użyciu specyfikacji narzędzia Agent Registry, parametrów OAuth 2.0 Google Identity i wiąże DataStore (dataStoreIds) z Twoją usługą Gemini Enterprise Engine.
# 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}"

Tworzenie łącznika danych

# 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

Weryfikowanie utworzenia łącznika danych

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

Sprawdź, czy pole "registry_mcp_server_name" jest wypełnione identyfikatorem UUID Agent Registry dla serwera MCP, a pole "auth_type" ma wartość OAUTH:

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

Wyświetl wpis rejestru serwera MCP w interfejsie konsoli Google Cloud:

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

Aktywowanie łącznika danych

# 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

Weryfikowanie połączeń z niestandardowym serwerem MCP

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

Sprawdź, czy połączony magazyn danych "dataStoreIds": ["mcp-sprockets-collection-[EPOCH]_mcp_data"] jest widoczny.

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

Sprawdź, czy są dostępne "state": "ACTIVE" i "auth_type": "OAUTH".

Operacje na narzędziu

Gdy sprawdzisz mcp-sprockets-collection magazyn danych na panelu Gemini Enterprise, zauważysz, że karta Działania nie jest używana, a przycisk ↻ Ponownie załaduj działania niestandardowe jest wyłączony. Jest to prawidłowe działanie.

Wyświetl stronę szczegółów magazynu danych w interfejsie konsoli Google Cloud:

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

W zależności od tego, jak połączysz niestandardowy serwer MCP z Gemini Enterprise, wykrywanie narzędzi i zarządzanie nimi odbywa się na jeden z tych 2 sposobów:

  • Bezpośredni niestandardowy MCP (BYO_MCP przepływ pracy): gdy skonfigurujesz niestandardowy serwer MCP bezpośrednio w Gemini Enterprise bez Agent Registry, katalog narzędzi (connectorModes: ["FEDERATED", "ACTIONS"]) będzie zarządzany przez sam magazyn danych. Musisz otworzyć kartę Działania i kliknąć ↻ Ponownie załaduj działania niestandardowe, aby pobrać schemat tools/list, a następnie ręcznie włączyć lub wyłączyć poszczególne narzędzia (add i subtract) w interfejsie.
  • Importowanie z Agent Registry (REGISTRY_MCP przepływ pracy używany w tym laboratorium): gdy importujesz serwer MCP z Agent Registry, Agent Registry służy jako autorytatywne źródło informacji o punkcie końcowym MCP, metadanych interfejsu i katalogu narzędzi (connectorModes: ["FEDERATED"]). Gemini Enterprise automatycznie włącza zarejestrowane narzędzia MCP w czasie działania za pomocą ustawienia silnika Bramy agentów bez konieczności ręcznego ponownego wczytywania lub przełączania działań w interfejsie magazynu danych.

To wszystko, jeśli chodzi o Gemini Enterprise. Przejdźmy teraz do sekcji Sprawdzanie.

9. Weryfikuj

W tej sekcji wykonasz jednorazowy proces uzyskiwania zgody użytkownika na Google OAuth 2.0, wywołasz narzędzia MCP na zewnętrznym serwerze mcp-sprockets z Gemini Enterprise i sprawdzisz, czy zewnętrzny serwer MCP zweryfikował zarówno zarezerwowany statyczny adres IP Cloud NAT (egress_source_ip), jak i tożsamość Google OAuth 2.0 (authenticated_user).

Dostęp użytkownika

Skonstruuj adres URL aplikacji internetowej Gemini Enterprise:

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

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

echo "app user url: ${GE_APP_USER_URL}"

Zanim wyślesz zapytanie do agenta, musisz przejść jednorazowy proces zgody OAuth 2.0, który przyznaje Gemini Enterprise uprawnienia do uzyskania tokena dostępu do Twojej tożsamości Google (${USER_IDENTITY}). Dzięki temu Gemini Enterprise może uwierzytelniać wychodzące wywołania narzędzi za pomocą Bramy agentów, aby zewnętrzny serwer mcp-sprockets mógł weryfikować Twoją tożsamość przy każdym żądaniu.

  1. Otwórz ${GE_APP_USER_URL} w przeglądarce i kliknij Rozpocznij.
  2. W oknie czatu kliknij ikonę Łączniki (ikonę puzzla) i obok ikony mcp-sprockets-collection kliknij Autoryzuj.
  3. Pojawi się nowe okno z prośbą o wybranie konta, aby kontynuowaćmcp-sprockets-oauth (nazwa aplikacji na ekranie zgody OAuth, którą skonfigurowano). Następnie wybierz swoje konto użytkownika (${USER_IDENTITY}).
  4. Na ekranie zgody OAuth Google sprawdź uprawnienia, które umożliwiają Google (dostawcy tożsamości) udostępnianie Twojej tożsamości użytkownika (openid, email, profile) usłudze mcp-sprockets-oauth, a następnie kliknij Dalej.
  5. Ponownie kliknij ikonę Łączniki i sprawdź, czy przełącznik mcp-sprockets-collection jest włączony. Potwierdza to, że autoryzacja się powiodła.

Testowanie zapytań agenta

Testy interfejsu czatu z asystentem

Wyślij na czacie to zapytanie testowe:

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

Wypróbuj drugie zapytanie na czacie:

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

Sprawdź, czy asystent zwraca prawidłowe odpowiedzi i wyświetla interaktywną plakietkę z cytatem z działania.

Na przykład „Sprocket Lookup SPK-105 (5s)Ikona narzędzia MCPAgent Gatewayikona znacznika wyboru w kółku,” pod każdą odpowiedzią potwierdza, że narzędzie zostało uruchomione.

Sprawdź, czy Asystent zwraca specyfikacje koła zębatego wraz z "authenticated_user" pasującym ${USER_IDENTITY} i "egress_source_ip" pasującym do zarezerwowanego ${NAT_EXT_IP}.

Testy interfejsu API AsystentastreamAssist

Gdy konto użytkownika autoryzuje łącznik OAuth 2.0, możesz też wywołać interfejs API default_assistant:streamAssist bezpośrednio z CLI i sprawdzić, czy zewnętrzny serwer mcp-sprockets zwraca oba adresy IP statyczne Cloud NAT (${NAT_EXT_IP}) i zweryfikowaną tożsamość Google OAuth 2.0 (${USER_IDENTITY}):

Prześlij to zapytanie testowe:

# 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

Przykładowe dane wyjściowe:

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

Spróbuj wpisać inne zapytanie:

# 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

Sprawdzanie logów w Cloud Logging

Sprawdź, czy Gemini Enterprise przekierował wywołania narzędzi przez Bramę agentów, przyłącze sieci PSC i Cloud NAT, przeglądając dzienniki w Cloud Logging.

Sprawdzanie dzienników bramy agentów

Sprawdź, czy Brama agentów przechwyciła żądanie, rozpoznała miejsce docelowe w Agent Registry, oceniła zasady autoryzacji i przekazała wywołanie narzędzia:

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

Przykładowe dane wyjściowe:

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

Sprawdź, czy dane wyjściowe zawierają:

  • STATUS: 200 (udane wykonanie) i 202 (uzgadnianie połączenia notifications/initialized).
  • SERVER_IP: zewnętrzny adres IP i port serwera MCP (${MCP_EXT_IP}:443).
  • MCP_METHOD i TOOL: sekwencja protokołu MCP (initialize, notifications/initialized, tools/list i tools/call z get_sprocket_by_id).
  • AUTHZ: ALLOWED (autoryzacja IAP zezwala na ruch wychodzący).
  • REGISTRY_MCP: identyfikator zasobu Resolved Agent Registry (agentregistry-...).

Sprawdzanie logów Cloud NAT

Sprawdź, czy Cloud NAT przetłumaczył połączenie wychodzące z adresu IP przyłącza sieciowego PSC bramy agentów (10.10.10.2) na zarezerwowany statyczny zewnętrzny adres IPv4 (${NAT_EXT_IP}) podczas łączenia się z ${MCP_EXT_IP}:443:

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

Przykładowe dane wyjściowe:

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

Sprawdzanie logów zapory sieciowej

Sprawdź, czy wewnętrzna zasada zapory sieciowej (fw-policy-${SLUG}-internal) zezwala na ruch wychodzący z bramy agenta do miejsca docelowego w internecie:

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

Sprawdź, czy zewnętrzna zasada zapory sieciowej (fw-policy-${SLUG}-external) zezwala na ruch przychodzący do serwera MCP z publicznego adresu IP NAT sieci wewnętrznej:

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

To wszystko, jeśli chodzi o weryfikację. Przejdźmy teraz do sekcji Czyszczenie.

10. Czyszczenie

Aby usunąć zasoby i konfiguracje utworzone w tym laboratorium, wykonaj te czynności.

Usuwanie komponentów Gemini Enterprise

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

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

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

Aby usunąć dane logowania klienta OAuth 2.0 (ge-mcp-sprockets-client), otwórz stronę Klienci platformy uwierzytelniania Google i kliknij ikonę Usuń (kosz) obok ge-mcp-sprockets-client:

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

Usuwanie serwera MCP i komponentów Agent Registry

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

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

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

Usuwanie komponentów bramy agenta

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

Usuwanie komponentów zapory sieciowej

# 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

Usuwanie komponentów sieci

# 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

Usuwanie zastąpień zasad organizacji i plików lokalnych

# 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

To koniec porządkowania. Przejdźmy teraz do podsumowania.

11. Podsumowanie

Gratulacje! Utworzono architekturę kompleksową, która umożliwia aplikacji Gemini Enterprise bezpieczne wykrywanie i wywoływanie narzędzi na zewnętrznym serwerze MCP z białą listą adresów IP i ochroną OAuth 2.0:

  • Wychodzący ruch z sieci VPC z użyciem statycznego adresu IP (ALL_TRAFFIC i Cloud NAT): cały ruch wychodzący z bramy agenta był kierowany przez przyłącze sieci PSC (10.10.10.2), a żądania kierowane do internetu były tłumaczone na zarezerwowany statyczny zewnętrzny adres IPv4 (${NAT_EXT_IP}) za pomocą Cloud NAT.
  • Serwer zasobów MCP OAuth 2.0 i Agent Registry: wdrożono zewnętrzny serwer HTTP FastMCP z możliwością przesyłania strumieniowego (mcp-sprockets) chroniony przez ścisłą listę dozwolonych adresów IP źródła (${NAT_EXT_IP}/32) i weryfikację Google OAuth 2.0 tokeninfo, a także zarejestrowano jego punkt końcowy i schemat narzędzia (get_sprockets i get_sprocket_by_id) w Agent Registry.
  • Integracja i zarządzanie Gemini Enterprise OAuth 2.0: udostępniono aplikację Gemini Enterprise, powiązano ruch wychodzący narzędzia z bramą agentów, dołączono zarejestrowany serwer MCP jako REGISTRY_MCP łącznik danych OAuth 2.0 i zweryfikowano zarówno egress_source_ip, jak i authenticated_user wraz z telemetrią Cloud Logging.

cosmopup

Cosmopup uważa, że ćwiczenia są super!

Co dalej?

Jeśli masz uwagi, pytania lub poprawki, możesz je przesłać za pomocą tego formularza opinii.

Dziękujemy!