1. Введение
В этой практической работе рассматривается исходящее подключение со статическим IP-адресом для Gemini Enterprise с использованием Agent Gateway в режиме agent-to-anywhere (исходящий трафик). Вы настроите приложение Gemini Enterprise так, чтобы оно вызывало пользовательский сервер протокола Model Context Protocol (MCP), защищенный строгим белым списком IP-адресов источника и аутентификацией OAuth 2.0, путем маршрутизации всего исходящего трафика через шлюз агента с помощью конфигурации шаблона подключения. Сетевое подключение Private Service Connect (PSC) соединяет Agent Gateway с сетью VPC, а Cloud NAT предоставляет стабильный внешний IP-адрес для исходящего интернет-трафика.
По умолчанию исходящие подключения из Gemini Enterprise к общедоступным конечным точкам интернета исходят из динамических общих пулов IP-адресов Google, которые нельзя привязать к одному правилу белого списка IP-адресов, принадлежащему клиенту. При подключении шлюза агента к AgentConnectivityTemplate в режиме ALL_TRAFFIC весь исходящий трафик агента направляется в сеть VPC, где Cloud NAT преобразует подключения к интернету в зарезервированный статический внешний IPv4-адрес, который вы контролируете, сохраняя при этом централизованное управление инструментом MCP через реестр агентов и прокси-сервер с поддержкой идентификации.
Что вы создаете
- Шаблон подключения агента (
vpcEgress: ALL_TRAFFIC) и шлюз агента, работающий в режиме исходящего трафика (agent-to-anywhere) с проверкой конечной точки реестра агентов - Сеть VPC, подключение к сети PSC, маршрутизатор Cloud Router и шлюз Cloud NAT, привязанный к зарезервированному статическому внешнему адресу IPv4
- Внешний HTTP-сервер ресурсов MCP (
mcp-sprockets), который можно использовать для потоковой передачи данных, с TLS-сертификатом Caddy, ограниченный правилами брандмауэра только статическим IP-адресом Cloud NAT и проверяющий токены OAuth 2.0 Bearer, делегированные пользователем, с помощьюhttps://oauth2.googleapis.com/tokeninfo - Окно запроса доступа OAuth 2.0 платформы аутентификации Google и учетные данные клиента OAuth 2.0 веб-приложения (
accounts.google.comиoauth2.googleapis.com/token) - Запись каталога MCP-серверов из реестра агентов и спецификация инструмента (
toolspec.json) - Расширение авторизации прокси-сервера с идентификацией (IAP) и правила авторизации шлюза для шлюза агента
- Приложение Gemini Enterprise, связанное с Agent Gateway и подключенное к пользовательскому хранилищу данных MCP-сервера, импортированному из реестра агентов.
Рис. 1. Архитектура Codelab
Что вы узнаете
- Как настроить
AgentConnectivityTemplateсvpcEgress: ALL_TRAFFIC, чтобы направить весь исходящий трафик Agent Gateway в сеть VPC - Как зарезервировать статический внешний адрес IPv4 и привязать его к Cloud NAT в подсети подключения к сети PSC
- Как развернуть внешний потоковый HTTP-сервер ресурсов MCP, который проверяет токены носителя Google OAuth 2.0 (
oauth2.googleapis.com/tokeninfo) и ограничивает входящий трафик межсетевого экрана статическим IP-адресом Cloud NAT (${NAT_EXT_IP}/32) - Как настроить учетные данные клиента OAuth 2.0 Google Identity и зарегистрировать MCP-сервер и его схему инструментов в реестре агентов
- Как подключить зарегистрированный MCP-сервер OAuth 2.0 к Gemini Enterprise и перенаправлять вызовы инструментов, делегированные пользователем, через шлюз агентов
- Как проверить преобразование статического IP-адреса, подтверждение личности конечного пользователя OAuth 2.0 (
authenticated_user) и применение правил шлюза с помощью команд CLI и Cloud Logging
Что вам потребуется
- Проект Google Cloud с включенными платежными функциями.
- Активная лицензия Gemini Enterprise или 30-дневная пробная версия.
- Разрешения IAM для инициализации сетевых сервисов, правил организации, Gemini Enterprise и ресурсов платформы агентов
- Оболочка, совместимая с POSIX (
bashилиzsh), с установленными Google Cloud CLI (gcloud),curlиjq
На этом вводная часть заканчивается. Перейдем к разделу Основные понятия.
2. Основные понятия
Порядок развертывания
В этой практической работе сначала развертывается сетевая инфраструктура и инфраструктура управления, чтобы статические IP-адреса исходящих путей и элементы управления шлюзом были готовы до регистрации и подключения инструментов MCP к Gemini Enterprise.
- Сетевая инфраструктура. Зарезервируйте статические внешние адреса IPv4 и подготовьте исходящую VPC, подсеть подключения PSC, сетевое подключение PSC, Cloud Router, шлюз Cloud NAT и внешние правила брандмауэра сети MCP.
- Шаблон подключения агента и Agent Gateway. Разверните
AgentConnectivityTemplate(vpcEgress: ALL_TRAFFIC) и региональныйAgentGatewayв режиме исходящего трафика (AGENT_TO_ANYWHERE) с интеграцией реестра агентов (registries). - Правила авторизации. Настройте расширение авторизации IAP (
AuthzExtension), правило авторизации шлюза (AuthzPolicy) и единое правило доступа IAM версии 3 (AccessPolicyиPolicyBinding). - Разверните и зарегистрируйте MCP-сервер. Разверните внешний ресурсный сервер OAuth 2.0
mcp-sprocketsза Caddy TLS, проверьте его принудительное применение Google OAuth 2.0tokeninfo, заблокируйте его входящий межсетевой экран строго для статического IP-адреса Cloud NAT (${NAT_EXT_IP}/32) и зарегистрируйте спецификации сервиса и инструмента (get_sprocketsиget_sprocket_by_id) в реестре агентов. - Приложение Gemini Enterprise и клиент OAuth 2.0. Настройте Google Identity, пробную лицензию, окно запроса доступа OAuth 2.0 и учетные данные клиента веб-приложения (
OAUTH_CLIENT_IDиOAUTH_CLIENT_SECRET), создайте приложение Gemini Enterprise (Engine) и привяжите исходящий трафик к шлюзу агента (agentGatewaySetting). - Импортируйте собственный коннектор данных MCP. Создайте и активируйте коннектор данных
REGISTRY_MCP(:setUpDataConnector), настроенный с помощьюauth_type: "OAUTH", чтобы связать зарегистрированный MCP-сервер, поддерживающий хранилище данных, с приложением Gemini Enterprise. - Проверка. Выполните однократный процесс предоставления согласия OAuth 2.0, вызовите инструменты MCP через помощника Gemini Enterprise (подтвердив
egress_source_ipиauthenticated_user) и проверьте применение правил и трансляцию NAT статического IP-адреса в Cloud Logging.
Архитектура центрального поставщика идентификационной информации и защищенного OAuth MCP-сервера ресурсов
В корпоративных развертываниях управление идентификацией и выполнение инструментов следуют стандартному разделению ролей OAuth 2.0 между централизованным поставщиком идентификационной информации (сервером авторизации) и защищенным сервером ресурсов MCP:
Роль OAuth 2.0 | Компонент в этой практической работе | Ответственность |
Владелец ресурса | Конечный пользователь ( | Выполняет вход в веб-приложение Gemini Enterprise и предоставляет согласие во время однократного трехэтапного процесса авторизации OAuth 2.0. |
Клиент OAuth 2.0 | Gemini Enterprise | Содержит |
Сервер авторизации | Google Identity OAuth 2.0 ( | Аутентифицирует пользователя во время перенаправления для получения согласия в браузере и выдает Gemini Enterprise токены доступа и обновления OAuth 2.0. |
Сервер ресурсов | Внешний | Обеспечивает соблюдение сетевой идентификации уровня 3 с помощью межсетевого экрана VPC ( |
Поскольку перенаправление согласия браузера (accounts.google.com) и обмен токенами по обратному каналу (oauth2.googleapis.com/token) выполняются с помощью управляемых Google конечных точек OAuth 2.0, межсетевой экран внешнего сервера MCP получает только запросы JSON-RPC MCP во время выполнения (POST /mcp) от шлюза агента через Cloud NAT, что позволяет строго ограничить входящий трафик межсетевого экрана до ${NAT_EXT_IP}/32.
Модель ресурсов Discovery Engine
Приложение Gemini Enterprise (представленное как ресурс Engine в Discovery Engine API) – это центральный уровень оркестрации и разговорный интерфейс для конечных пользователей. Он управляет сеансами чата пользователей, предоставляет генеративным моделям доступ к корпоративным данным и координирует динамическое выполнение инструментов.
Приложения Gemini Enterprise взаимодействуют с данными и системами через хранилища данных:
- Хранилища данных о знаниях. Загружайте и индексируйте статический контент (например, из Cloud Storage, Google Диска или BigQuery) для генерации ответов с использованием поиска (RAG).
- Коннекторы данных (поставщики действий). Подключайтесь к динамическим сторонним или пользовательским API. Хранилище данных пользовательского MCP-сервера предоставляет инструменты, определенные протоколом Model Context Protocol (MCP), позволяя модели динамически вызывать внешние функции во время разговора.
Исходящий трафик Gemini Enterprise
Gemini Enterprise направляет запросы к инструменту пользовательского сервера MCP в Agent Gateway, если на Engine настроен параметр agentGatewaySetting, а на DataConnector – параметр use_agent_gateway_egress: true.
Рис. 2. Архитектура исходящего трафика Gemini Enterprise
Приложение Gemini Enterprise организует маршрутизацию инструментов по четырем ключевым областям:
- Виджет (
default_search_widget_config):- Обслуживает интерфейс веб-клиента. Виджет получает запросы от пользователя, запускает однократную переадресацию для получения согласия пользователя на OAuth 2.0, когда инструменту требуется авторизация, и инициирует сеансы чата с базовым движком.
- Основной помощник (
assistants/default_assistant/agents/default/core_assistant):- Корневой разговорный агент в системе. При обработке запроса пользователя основной помощник проверяет доступные инструменты и делегирует выполнение синтезированному суб-агенту Agent Gateway.
- Хранилище данных и коннектор данных:
DataStore. При запуске:setUpDataConnectorв выделенномCollectionвыполняется инициализация, а затем импортированные схемы инструмента "Реестр агентов" (get_sprockets,get_sprocket_by_id), типы аргументов и инструкции агента связываются (dataStoreIds) сEngineGemini Enterprise.DataConnector: управляет подключением действияREGISTRY_MCP(createBapConnection: true) к удаленному MCP-серверу (instance_uri), разрешает ресурс MCP-сервера из реестра агентов (registry_mcp_server_name), прикрепляет токен OAuth 2.0 Bearer из хранилища пользователя (Authorization: Bearer [access_token]) и включает исходящий трафик шлюза агента (use_agent_gateway_egress: true).
- Идентификация агента, реестр агентов и шлюз агента
- Когда коннектор данных отправляет вызов исходящего инструмента, он направляет трафик на шлюз, указанный в
agentGatewaySetting. Основной помощник создает токен идентификации SPIFFE, подтверждающий идентификатор рабочей нагрузки:principal://agents.global.org-.../agents/default/core_assistant. - Шлюз агента интегрируется с реестром агентов с помощью поля
registries, чтобы динамически разрешать конечные точки назначения и зарегистрированные схемы инструментов, оценивает правила авторизации с помощью IAP и пересылает разрешенные запросы (сохраняя заголовок пользователяAuthorization: Bearer) в сеть VPC с помощьюAgentConnectivityTemplate.
- Когда коннектор данных отправляет вызов исходящего инструмента, он направляет трафик на шлюз, указанный в
Подключение к VPC шлюза и статический IP-адрес NAT
Шлюз агента поддерживает подключение к сети VPC с помощью ресурса AgentConnectivityTemplate, на который ссылается agentConnectivityTemplate на шлюзе. Шаблон egressNetworkConfig определяет, как трафик поступает в VPC через сетевое подключение PSC:
PRIVATE_RANGES_ONLY(по умолчанию). Маршрутизирует через подключение к сети PSC только частные диапазоны IP-адресов RFC 1918, RFC 6598 и класса E. Трафик, предназначенный для интернета, минует VPC и выходит напрямую через интернет-шлюз Google по умолчанию.ALL_TRAFFIC(используется в этой практической работе). Направляет весь исходящий трафик из шлюза агента, включая общедоступный интернет и внешние конечные точки MCP партнеров, в подсеть VPC через сетевое подключение PSC (10.10.10.2).
При работе в режиме ALL_TRAFFIC подсеть для подключения PSC требует двух конфигураций:
- Частный доступ Google (
--enable-private-ip-google-access). Обеспечивает маршрутизацию внутренних вызовов к Google Cloud API (*.googleapis.com) в частном порядке в сети Google. - Облачный маршрутизатор и Cloud NAT (
MANUAL_ONLY). Трафик, предназначенный для интернета и поступающий в подсеть подключения PSC, следует маршруту по умолчанию (0.0.0.0/0) через Cloud NAT, который выполняет преобразование сетевых адресов источника (SNAT) в зарезервированный статический внешний адрес IPv4 (${NAT_EXT_IP}). Таким образом, внешние брандмауэры могут ограничить входящий доступ только до${NAT_EXT_IP}/32.
Ограничения и требования
- Только для StreamableHTTP. Транспорт Server-Sent Events (SSE) устарел и не поддерживается. MCP-серверы должны использовать StreamableHTTP.
- Переопределение правил организации. Перед регистрацией коннектора данных необходимо явно переопределить правила организации для хранилищ данных Custom MCP.
- Соответствие региональным требованиям. Gemini Enterprise обеспечивает соответствие региональным требованиям между местоположением приложения, шлюзом агента и реестром агента:
Где найти приложение Gemini Enterprise | Местоположение шлюза агента и NAT | Местоположение реестра агентов |
|
|
|
|
|
|
|
|
|
На этом раздел с основными понятиями завершается. Перейдем к разделу Настройка.
3. Настройка
Необходимые роли IAM
Для выполнения этой практической работы требуются следующие роли:
Поместье | Необходимые роли IAM |
Проект и IAM |
|
Сеть и шлюз |
|
Gemini Enterprise и реестр |
|
Рабочие нагрузки |
|
Наблюдаемость |
|
Или используйте широкую базовую роль, например roles/owner, в сочетании с roles/orgpolicy.policyAdmin (поскольку roles/owner не позволяет изменять политики организации).
Как получить доступ к проекту
В этой практической работе используется один проект Google Cloud. В инструкциях по настройке используются команды интерфейса командной строки gcloud и оболочки Linux.
Для начала откройте командную строку проекта Google Cloud:
- Cloud Shell на сайте
shell.cloud.google.com; - Локальный терминал с
gcloudCLI установленным.
Как задать идентификатор проекта
# set target project id
gcloud config set project SET_YOUR_PROJECT_ID_HERE
Аутентификация сеанса
# login to gcloud cli
gcloud auth login
# login for gcloud api
gcloud auth application-default login
Как задать переменные среды оболочки
# 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}
Как настроить доверенные домены для идентификации агента
Оператор if-then-else проверяет, принадлежит ли проект организации, чтобы задать правильный доверенный домен для идентификаторов основного агента.
# set var for trust domain
if [[ -n "${ORG_ID}" ]]; then
export TRUST_DOMAIN="agents.global.org-${ORG_ID}.system.id.goog"
else
export TRUST_DOMAIN="agents.global.proj-${PROJ_NO}.system.id.goog"
fi
echo "trust domain: ${TRUST_DOMAIN}"
Как задать проект для оплаты и квот
# set cli quota project
gcloud config set billing/quota_project ${PROJ_ID}
# set api quota project
gcloud auth application-default set-quota-project ${PROJ_ID}
Создайте локальный каталог для файлов конфигурации
# create config folder
mkdir -p cfg
Обновите gcloud cli (рекомендуется)
Если вы используете установленную самостоятельно версию Google Cloud SDK (не в Cloud Shell), обновите компоненты до последней версии.
# update gcloud cli
gcloud components update
Как включить сервисы 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
Политики организации
Ограничения, накладываемые правилами управляемой организации Google Cloud по умолчанию и правилами изолированной среды, могут препятствовать использованию функций, описанных в этой практической работе.
compute.vmExternalIpAccess: ограничивает внешние адреса IPv4 на виртуальных машинах Compute Engine в организациях с заблокированной песочницей.discoveryengine.managed.disableCustomMcpServerConnector– запрещает создание коннекторов данных, которые используют в качестве источника данных собственный MCP-сервер (custom_mcp) (применяется по умолчанию).discoveryengine.managed.allowedEgressFqdns: ограничивает исходящие домены (instance_uriполных доменных имен) для коннекторов данных, когда активно Управление зонами безопасности VPC (VPC-SC) или проект указан вenforcedProjects.discoveryengine.managed.allowedDataSources: ограничивает разрешенные типы коннекторов данных (dataSource), когда активна функция VPC-SC или проект указан вenforcedProjects.
Переопределять любые ограничения, заданные правилами организации, на уровне проекта.
Как отключить пользовательское ограничение 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
Как отключить ограничения для коннектора условных данных
# 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
Как отключить ограничение правила доступа
# 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
Разрешить внешние 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
Как проверить политики организации
Убедитесь, что для правила compute.vmExternalIpAccess задано значение allowAll: True, а для остальных правил – 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
Проверьте привязки агента сервиса (меры предосторожности)
В новом проекте Google Cloud автоматически инициализирует агента сервиса шлюза агента и предоставляет ему роль roles/agentgateway.serviceAgent при первом включении networkservices.googleapis.com. Если вы используете существующий проект, в котором ранее могла быть выполнена очистка, в результате которой были удалены привязки агента сервиса по умолчанию, выполните следующие команды, чтобы убедиться, что идентификатор и привязка роли сохранены:
# 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"
На этом настройка завершена. Перейдите к разделу Сеть.
4. Сеть
В этом разделе вы зарезервируете статические внешние адреса IPv4, создадите внутреннюю исходящую сеть VPC и изолированную внешнюю сеть VPC, настроите подключение к сети PSC, настроите Cloud NAT и создадите правила брандмауэра.
Как зарезервировать статические внешние IP-адреса
Зарезервируйте два региональных статических внешних адреса IPv4 для Cloud NAT и внешней виртуальной машины сервера 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}
Как проверить статические внешние IP-адреса
Для Gemini Enterprise требуется, чтобы удаленные конечные точки MCP использовали HTTPS с общедоступным доверенным сертификатом TLS. Вместо того чтобы регистрировать для этой лабораторной работы собственный домен, вы будете использовать sslip.io – бесплатный сервис DNS с подстановочными знаками, который преобразует любое имя хоста, содержащее IP-адрес (например, mcp.[IP].sslip.io), обратно в этот IP-адрес. Поскольку центры сертификации, такие как Let's Encrypt, не выдают сертификаты для IP-адресов, имя хоста sslip.io предоставляет обратному прокси-серверу Caddy действительное доменное имя, чтобы автоматически предоставить доверенный сертификат TLS для сервера MCP.
Экспортируйте оба адреса IPv4 и создайте доменное имя sslip.io и URL для внешнего 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}"
Примеры результатов:
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
Как создать внутреннюю сеть
Если шаблон подключения шлюза агента настроен на использование egressNetworkConfig с networkAttachment, подсеть, в которой размещено сетевое подключение PSC, должна быть не меньше блока CIDR /28 и иметь включенный доступ к сервисам Google с частным IP-адресом (--enable-private-ip-google-access).
Создайте глобальную сеть VPC для исходящего трафика внутреннего шлюза агента:
# 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
Как создать правила внутреннего брандмауэра
Создайте правило брандмауэра, чтобы разрешить весь исходящий трафик с включенным ведением журнала. Он будет использоваться для мониторинга трафика, исходящего из шлюза агента во внутреннюю сеть VPC. Cloud NGFW поддерживает уровни Essentials и Standard для обеспечения безопасности сети и мониторинга трафика.
# create fw policy
gcloud compute network-firewall-policies create fw-policy-${SLUG}-internal --global
# create fw policy rule
gcloud compute network-firewall-policies rules create 1001 \
--description="allow all out and log" \
--firewall-policy=fw-policy-${SLUG}-internal \
--global-firewall-policy \
--action=allow \
--direction=EGRESS \
--layer4-configs=all \
--dest-ip-ranges=0.0.0.0/0 \
--enable-logging
# bind fw policy to network
gcloud compute network-firewall-policies associations create \
--name=fw-policy-bind-${SLUG}-internal \
--firewall-policy=fw-policy-${SLUG}-internal \
--network=vnet-${SLUG}-internal \
--global-firewall-policy
Как создать подключение к сети PSC
Создайте сетевое подключение Private Service Connect (PSC), настроенное на автоматическое принятие подключений от шлюза агента. Сетевое подключение устанавливает сторону подключения к сети VPC потребителя, чтобы безопасно связать ее со стороной поставщика шлюза агента для исходящего трафика. Дополнительную информацию о требованиях к подсети и спецификациях диапазона IP-адресов можно найти в статье Настройка подключения VPC.
# create psc network attachment
gcloud compute network-attachments create psc-na-${REGION}-agw \
--region=${REGION} \
--subnets=subnet-${REGION}-agw \
--connection-preference=ACCEPT_AUTOMATIC
Как проверить подключение к сети PSC
# show psc network attachment details
gcloud compute network-attachments describe psc-na-${REGION}-agw --region=${REGION}
Получите URI ресурса для сетевого подключения PSC и сохраните его в переменной среды PSC_NA_URI. Этот URI будет указан в конфигурации шлюза агента (networkConfig.egress.networkAttachment), чтобы инициализировать интерфейс PSC для исходящего трафика в сеть 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}
Как создать Cloud NAT
Cloud NAT используется для преобразования исходного IP-адреса исходящего трафика шлюза агента в зарезервированный общедоступный IP-адрес для маршрутизации через общедоступный интернет.
Только источники из подсети исходящего сетевого подключения шлюза агента могут использовать 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
Как проверить Cloud NAT
Проверьте статус Cloud NAT и убедитесь, что настроен ожидаемый источник 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)"
Примеры результатов:
name: nat-foo-us-central1
natIps:
- https://www.googleapis.com/compute/v1/projects/[PROJ_ID]/regions/us-central1/addresses/ip-foo-nat
Как создать внешнюю сеть
Создайте отдельную изолированную сеть VPC для размещения ВМ внешнего 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
Как создать внешние правила брандмауэра
Создайте два правила брандмауэра для входящего трафика во внешней сети VPC:
2001: разрешает входящий порт TCP80, чтобы Let's Encrypt мог выполнить проверку домена ACME HTTP-01 для${MCP_DOMAIN}.2002: изначально разрешает входящий порт TCP443от0.0.0.0/0, чтобы проверить готовность TLS и принудительное применение OAuth 2.0tokeninfoиз локальной оболочки, прежде чем строго ограничить его до${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
На этом мы завершаем раздел о сети и переходим к разделу Шлюз агента.
5. Шлюз агента
В этом разделе вы развернете шаблон подключения агента с vpcEgress: ALL_TRAFFIC, развернете региональный шлюз агента, делегируете авторизацию прокси-серверу с идентификацией (IAP) и определите правила единой политики доступа IAM для управления исходящими сетевыми запросами.
Как создать шаблон подключения
Спецификация шаблона подключения определяет:
egressNetworkConfig.networkAttachment: указывает на подключение к сети PSC, соединяющее Agent Gateway с вашей сетью VPC.egressNetworkConfig.vpcEgress: установите значениеALL_TRAFFIC, чтобы все исходящие подключения агента (включая общедоступные конечные точки MCP в интернете) направлялись в сеть VPC и выходили с использованием преобразования исходного IP-адреса Cloud NAT.
Создайте и импортируйте файл конфигурации шаблона подключения:
# 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}
Как создать шлюз агента
Спецификация шлюза агента определяет:
agentConnectivityTemplate: указывает на шаблон подключения, чтобы шлюз мог использовать подключение к сети PSC для подключения к VPC.registries: связывает шлюз с региональным реестром агентов, чтобы разрешать каталогизированные конечные точки MCP и схемы инструментов.
Создайте и импортируйте файл конфигурации шлюза агента:
# 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}
Как проверить развертывание шлюза агента
Проверьте конфигурацию реестра агентов и шаблона подключения:
# verify agent gateway deployment details
gcloud network-services agent-gateways describe ${AGW_NAME} \
--location=${REGION} \
--format="yaml(name,agentConnectivityTemplate,registries)"
Примеры результатов:
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
Проверьте подключение к сети PSC, чтобы подтвердить подключение к шлюзу:
# show psc network attachment details
gcloud compute network-attachments describe psc-na-${REGION}-agw \
--region=${REGION} \
--format="yaml(connectionEndpoints)"
Примеры результатов:
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
Делегирование авторизации
Agent Gateway защищает исходящий трафик инструментов и управляет им с помощью правил авторизации (networksecurity.authzPolicies), интегрированных с едиными правилами доступа (UAP) прокси-сервера с идентификацией (IAP).
Хотя Agent Gateway поддерживает базовые встроенные правила ALLOW и DENY, корпоративным средам требуется централизованное управление на основе идентификации. С помощью единых правил доступа IAM (или правил доступа) вы можете управлять правилами доступа к исходящему трафику, используя стандартные правила доступа IAM версии 3.
Рис. 3. Архитектура авторизации
Процесс авторизации состоит из трех компонентов:
- Правила авторизации шлюза (
authzPolicy):- Региональный ресурс, предназначенный для шлюза агента.
- Настроено с помощью
policyProfile: REQUEST_AUTHZиaction: CUSTOMдля маршрутизации всех исходящих проверок авторизации в расширение авторизации IAP.
- Расширение сервиса встроенных покупок (
authzExtension):- Региональный ресурс, который делегирует авторизацию запросов прокси-серверу с идентификацией (
iap.googleapis.com). - Оценивает правила в режиме
ENFORCE, используя версию правилV2.
- Региональный ресурс, который делегирует авторизацию запросов прокси-серверу с идентификацией (
- Единая политика доступа и привязка IAM (
accessPolicyиpolicyBinding):- Глобальные ресурсы IAM версии 3, содержащие детализированные правила доступа.
- Аутентифицирует основную идентификационную информацию SPIFFE вызывающего агента, проверяет универсальное разрешение
iap.googleapis.com/resources.egressViaIAPи оценивает условия Common Expression Language (CEL) по атрибутам назначения.
Как развернуть расширение для авторизации
# 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}
Как проверить расширение для авторизации
Проверьте, активно ли расширение для авторизации:
# 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
)"
Как развернуть правила авторизации
Создайте конфигурацию правил авторизации network-security, которая будет предназначена для шлюза агента и делегирует проверку запросов расширению авторизации для 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}
Как проверить правила авторизации
Проверьте, активно ли правило авторизации:
# list authz policies
gcloud network-security authz-policies list \
--location=${REGION} \
--format="table(
name.basename():label=NAME,
action:label=ACTION,
policyProfile:label=POLICY_PROFILE,
customProvider.authzExtension.resources[0].basename():label=CUSTOM_PROVIDER_RESOURCE
)"
Как создать правила доступа IAM
Теперь Agent Gateway делегирует проверки авторизации сервису IAP и получает метаданные целевого ресурса из реестра агентов. Затем определите правило единого правила доступа IAM, чтобы управлять выполнением исходящих инструментов.
IAP оценивает выражения атрибутов CEL по следующим целевым атрибутам реестра агентов:
- Статус регистрации (
destination.is_registered):- Логическое значение (
trueилиfalse), указывающее, зарегистрирован ли целевой сайт в реестре агентов.
- Логическое значение (
- Название MCP-сервера (
destination.agent_registry.mcp_server.name):- Каноническое название ресурса MCP-сервера, зарегистрированное в реестре агентов.
- Метод MCP (
destination.agent_registry.mcp_server.method):- Вызываемый метод MCP (например,
tools/call,tools/list,initialize).
- Вызываемый метод MCP (например,
- Название инструмента (
destination.agent_registry.mcp_server.tool.name):- Название вызванного инструмента (например,
get_sprocket_by_idилиget_sprockets), позволяющее выполнять точную авторизацию на уровне инструмента на зарегистрированных MCP-серверах.
- Название вызванного инструмента (например,
Как задать правило доступа IAM
Манифест правила политики IAM содержит следующие сведения:
- Субъекты. Идентификатор субъекта SPIFFE, представляющий агента основного помощника Gemini Enterprise.
- Разрешения. Универсальное разрешение
iap.googleapis.com/resources.egressViaIAP, необходимое для всего исходящего трафика, управляемого IAP. - Условия: выражение CEL (
destination.is_registered == true), гарантирующее, что агент может вызывать только конечные точки, зарегистрированные в реестре агентов.
Создайте файл манифеста для правила:
# create access policy rule file
cat > cfg/uap-policy-${SLUG}-rules.json << EOF
[
{
"description": "allow ge assistant to any registered service",
"effect": "ALLOW",
"principals": [
"principal://${TRUST_DOMAIN}/resources/discoveryengine/projects/${PROJ_NO}/locations/global/engines/${GE_APP_INIT}/assistants/default_assistant/agents/default/core_assistant"
],
"operation": {
"permissions": [
"iap.googleapis.com/resources.egressViaIAP"
]
},
"conditions": {
"iap.googleapis.com": {
"expression": \
"destination.is_registered == true"
}
}
}
]
EOF
Как развернуть правила доступа IAM
Создайте глобальное правило доступа IAM, используя правила, определенные в файле манифеста:
# create iam access policy
gcloud iam access-policies create uap-policy-${SLUG} \
--details-rules=cfg/uap-policy-${SLUG}-rules.json \
--project=${PROJ_ID} \
--location=global
Как проверить правила доступа IAM
Убедитесь, что политика доступа IAM создана, и проверьте сведения о правиле:
# show iam access policy details
gcloud iam access-policies describe uap-policy-${SLUG} \
--project=${PROJ_ID} \
--location=global
Примеры результатов:
details:
rules:
- conditions:
iap.googleapis.com:
expression: destination.is_registered == true
description: allow ge assistant to any registered service
effect: ALLOW
operation:
permissions:
- iap.googleapis.com/resources.egressViaIAP
principals:
- principal://agents.global.org-[ORG_ID].system.id.goog/resources/discoveryengine/projects/[PROJ_NO]/locations/global/engines/app-foo-global_[EPOCH]/assistants/default_assistant/agents/default/core_assistant
name: projects/[PROJ_ID]/locations/global/accessPolicies/uap-policy-foo
Как привязать правило доступа IAM к проекту
Чтобы активировать принудительное применение для всех шлюзов агентов в проекте, создайте привязку правила, которая прикрепляет правило доступа IAM к ресурсу проекта:
# bind iam access policy to project resource
gcloud iam policy-bindings create uap-bind-${SLUG} \
--policy="projects/${PROJ_ID}/locations/global/accessPolicies/uap-policy-${SLUG}" \
--target-resource="//cloudresourcemanager.googleapis.com/projects/${PROJ_ID}" \
--project=${PROJ_ID} \
--location=global
Как проверить привязку правила доступа IAM
Проверьте, что активные точки привязки правил указывают на правильные правила и цели:
# show policy binding details
gcloud iam policy-bindings describe uap-bind-${SLUG} \
--project=${PROJ_ID} \
--location=global
На этом раздел об Agent Gateway завершается. Перейдем к разделу о MCP-сервере.
6. MCP-сервер
В этом разделе вы развернете внешний сервер ресурсов OAuth 2.0 FastMCP (mcp-sprockets), предоставляющий доступ к инструментам get_sprockets и get_sprocket_by_id, и убедитесь, что он криптографически проверяет токены OAuth 2.0 Bearer от Google на соответствие https://oauth2.googleapis.com/tokeninfo. Затем вы ограничите внешнее правило брандмауэра статическим IP-адресом Cloud NAT.
Как развернуть внешний MCP-сервер
Сценарий запуска устанавливает Caddy и FastMCP, запускает сервер mcp-sprockets на порту 127.0.0.1:8080 и настраивает Caddy для обслуживания HTTPS на порту ${MCP_DOMAIN}.
Каждый раз, когда Gemini Enterprise вызывает инструмент MCP (например, get_sprockets и get_sprocket_by_id), сервер будет:
- Считывает IP-адрес источника звонка из заголовка
X-Forwarded-For(egress_source_ip). - Извлеките заголовок
Authorization: Bearer [access_token]и проверьте токен с помощью конечной точки проверки Google OAuth 2.0 (https://oauth2.googleapis.com/tokeninfo?access_token=[token]). - Верните
"authenticated_user"([user_email]) вместе с"egress_source_ip", чтобы подтвердить, что внешний сервер MCP проверил как статический IP-адрес Cloud NAT, так и идентификатор конечного пользователя 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"
Проверка готовности MCP-сервера и валидации OAuth 2.0 tokeninfo
Подождите несколько минут, пока сценарий запуска установит FastMCP и Caddy и предоставит сертификат 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
Проверьте sslip.io DNS-преобразование, сертификат TLS Let's Encrypt, предоставленный Caddy, и ответ 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:"
Примеры результатов:
* 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}}]}}
Прежде чем блокировать внешний межсетевой экран, выполните проверку tools/call, передав токен OAuth 2.0 Bearer от Google (gcloud auth print-access-token), чтобы убедиться, что mcp-sprockets проверяет токен на соответствие https://oauth2.googleapis.com/tokeninfo и возвращает ваш адрес электронной почты "authenticated_user" вместе с исходным IP-адресом вызывающего абонента:
# 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'
Пример выходных данных (с указанием прямого IP-адреса Cloud Shell до блокировки брандмауэра и подтвержденного адреса электронной почты 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
}
}
Блокировка брандмауэра для статического IP-адреса Cloud NAT
Обновите правила брандмауэра внешней сети VPC, чтобы порт TCP 443 принимал трафик только от статического внешнего 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
Проверьте, действуют ли правила внешнего брандмауэра:
# 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
)"
Убедитесь, что прямые подключения за пределами статического IP-адреса Cloud NAT теперь заблокированы:
# query mcp server
curl -i --connect-timeout 5 "${MCP_URL}" \
|| echo "Expected: Direct access blocked (not originating from ${NAT_EXT_IP})"
Примеры результатов:
curl: (28) Connection timed out after 5001 milliseconds
Expected: Direct access blocked (not originating from 203.0.113.10)
На этом мы завершаем раздел о MCP-сервере и переходим к разделу Реестр агентов.
7. Реестр агентов
Реестр агентов – это централизованный каталог всех агентов, MCP-серверов и конечных точек (API) в экосистеме ИИ. Кроме того, это каталог, в котором можно искать и находить другие зарегистрированные инструменты и сервисы для использования в ИИ-приложениях. В качестве основы для контроля исходящего доступа Agent Gateway использует модель данных реестра. Предоставление ролей IAM для вызывающих агентов проверяется на соответствие правилам, связанным с ресурсом реестра.
В этом разделе вы зарегистрируете MCP-сервер и его схему инструментов (toolspec.json) в реестре агентов. Чтобы Gemini Enterprise мог взаимодействовать с API и сервисами Google через Agent Gateway, вам также нужно создать сервис конечной точки реестра (oauth2-googleapis), в котором будут указаны интерфейсы API Google, используемые Gemini Enterprise для обмена кода авторизации на токены.
Как зарегистрировать MCP-сервер
Чтобы Gemini Enterprise мог обнаруживать инструменты, доступные на MCP-сервере, при регистрации сервиса в реестре агентов укажите файл спецификаций инструментов (cfg/toolspec.json).
Как создать спецификацию инструмента 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
Как создать сервис 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}"
Как проверить MCP-сервер в реестре агентов
Убедитесь, что сервис указан в качестве зарегистрированного MCP-сервера в регионе вместе с URL конечной точки и доступными инструментами:
# 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
)"
Примеры результатов:
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
Посмотрите спецификацию конфигурации сервиса, чтобы убедиться, что для каждого инструмента зарегистрированы точные определения, схемы входных данных и аннотации поведения:
# describe mcp server tool specs
gcloud agent-registry services describe ${MCP_NAME} \
--location=${REGION} \
--project=${PROJ_ID} \
--format="yaml(mcpServerSpec.content.tools)"
Как зарегистрировать конечную точку OAuth
Чтобы серверная часть Gemini Enterprise DataConnector (действующая как клиент OAuth в потоке авторизации) могла отправлять запросы POST на сервер авторизации Google OAuth 2.0 (https://oauth2.googleapis.com/token) через шлюз агента, конечная точка токена должна быть зарегистрирована в реестре агентов, чтобы IAP мог оценивать destination.is_registered == true.
Как создать сервис конечной точки
# 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
Как проверить регистрацию конечной точки
# 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
)"
Ожидаемый результат:
DISPLAY_NAME ENDPOINT_ID URL
oauth2.googleapis.com agentregistry-00000000-0000-0000-0012-3456789abcde https://oauth2.googleapis.com
Правила доступа IAM
Поскольку политика доступа IAM определяет разрешающую политику для любого зарегистрированного сервиса, запрошенного приложением Gemini Enterprise с идентификатором агента core_assistant, для обмена токенами OAuth не требуются дополнительные привязки политики IAM.
- conditions:
iap.googleapis.com:
expression: destination.is_registered == true
description: allow ge assistant to any registered service
effect: ALLOW
На этом раздел о реестре агентов завершается. Перейдем к разделу Gemini Enterprise.
8. Gemini Enterprise
В этом разделе вы настроите поставщика идентификационной информации, пробную лицензию и учетные данные клиента OAuth 2.0 Google Identity, создадите приложение Gemini Enterprise (${GE_APP_ID}), привяжете исходящий трафик к шлюзу агента (${AGW_URI}) и подключите зарегистрированный MCP-сервер sprockets в качестве пользовательского хранилища данных MCP OAuth 2.0.
Как создать приложение Gemini Enterprise
Чтобы создать ресурсы и конфигурацию приложения Gemini Enterprise, используйте API discoveryengine.googleapis.com. Инструкции по настройке с помощью интерфейса консоли Google Cloud приведены в разделе Как создать приложение.
# 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
Как проверить, создано ли приложение
# 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}"
Чтобы посмотреть созданную конфигурацию, откройте сведения о системе:
# 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}"
Как включить поставщика идентификационной информации
Включите Google Identity в качестве поставщика идентификационной информации для аутентификации конечных пользователей в приложении Gemini Enterprise.
Ниже описано, как настроить поставщика идентификационной информации для приложения Gemini Enterprise с помощью API discoveryengine.googleapis.com. Чтобы настроить поставщика идентификационной информации с помощью интерфейса консоли Google Cloud, следуйте инструкциям в разделе Настройка поставщика идентификационной информации.
# 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
Как проверить поставщика идентификационной информации
# 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}"
Выходные данные "idpType": "GSUITE" соответствуют поставщику Google Identity.
Включите пробную лицензию Gemini Enterprise (необязательно)
Если вы используете проект, которому назначены лицензии Gemini Enterprise, этот шаг можно пропустить. Если вы используете новый проект без лицензии, продолжите и выполните следующие действия.
Создайте ресурс конфигурации лицензии, чтобы предоставить пользователям Gemini Enterprise лицензии на 30 дней. Это позволит задать новую пробную версию в качестве лицензии по умолчанию, чтобы каждый пользователь, который входит в аккаунт, автоматически получал место:
# 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
Как проверить, применена ли лицензия
# show license config
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/licenseConfigs/free_trial_gemini" \
-H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
-H "X-Goog-User-Project: ${PROJ_ID}"
Проверьте, есть ли в нем "subscriptionTerm": "SUBSCRIPTION_TERM_ONE_MONTH" и "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}"
Проверьте, есть ли в нем ../free_trial_gemini" и "enableLicenseAutoRegister": true.
Как настроить согласие и учетные данные OAuth 2.0
Чтобы разрешить Gemini Enterprise (клиенту OAuth 2.0) получать делегированный пользователем токен на предъявителя Google OAuth 2.0 и передавать его mcp-sprocketsсерверу ресурсов от вашего имени, настройте окно запроса доступа OAuth платформы аутентификации Google и создайте идентификатор клиента OAuth 2.0 веб-приложения в своем проекте.
1. Как настроить окно запроса доступа OAuth
Выведите прямой URL консоли Google Cloud для обзора платформы аутентификации Google в вашем проекте:
# print google auth platform consent screen url
echo "https://console.cloud.google.com/auth/overview?project=${PROJ_ID}"
- Откройте URL в браузере и нажмите Начать (если для вашего проекта ещё не настроено).
- В разделе Информация о приложении в поле Название приложения введите
mcp-sprockets-oauthи выберите свой адрес электронной почты (${USER_IDENTITY}) в качестве адреса электронной почты для поддержки пользователей. Нажмите Далее. - В разделе Аудитория выберите Внутренняя (рекомендуется, если ваш аккаунт принадлежит организации Google Workspace) или Внешняя (если вы используете личный аккаунт; если вы выберете Внешняя, добавьте
${USER_IDENTITY}в разделе **Тестировщики аудитории**), а затем нажмите Далее. - В разделе Контактная информация введите адрес электронной почты, примите условия использования и нажмите Создать.
2. Как создать идентификатор клиента OAuth 2.0 для веб-приложения
Выведите прямой URL консоли Google Cloud для страницы Клиенты:
# print google auth platform clients url
echo "https://console.cloud.google.com/auth/clients?project=${PROJ_ID}"
- Откройте URL и нажмите + Создать клиента.
- В качестве типа приложения выберите Веб-приложение и задайте для параметра Название значение
ge-mcp-sprockets-client. - Установите флажок Этот клиент будет использоваться ИИ-агентом, чтобы назначить клиента OAuth для рабочих процессов ИИ-агента, действующего от имени пользователей.
- В разделе Разрешенные URI перенаправления нажмите + Добавить URI и добавьте URI обратного вызова OAuth Gemini Enterprise:
https://vertexaisearch.cloud.google.com/oauth-redirect
- Нажмите Создать, скопируйте сгенерированные идентификатор клиента и секретный код клиента и экспортируйте их в сеанс оболочки:
Укажите идентификатор и секретный код клиента OAuth 2.0, созданные на предыдущем шаге:
# 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"
Проверьте, задан ли идентификатор клиента:
# print oauth 2.0 client id
echo "oauth client id: ${OAUTH_CLIENT_ID}"
Как подключиться к шлюзу агента
Маршрутизация исходящего трафика из Gemini Enterprise через шлюз агента позволяет централизованно применять правила и задавать статические IP-адреса для всех вызовов инструментов ИИ-агента.
- Централизованное применение правил. Agent Gateway действует как встроенный прокси-сервер, который оценивает исходящие запросы инструментов на соответствие правилам авторизации до того, как трафик покинет среду агента.
- Детерминированный исходящий трафик VPC и Cloud NAT. Привязка Gemini Enterprise к шлюзу агента, настроенному с помощью
vpcEgress: ALL_TRAFFIC, гарантирует, что вызовы инструментов будут направляться через сетевое подключение PSC и выходить с использованием зарезервированного статического IP-адреса Cloud NAT. - Единый аудит. Централизованное ведение журналов запросов и аудита на всех подключенных MCP-серверах.
Исправьте движок agentGatewaySetting, чтобы включить:
# 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
Как проверить привязку шлюза агента
Чтобы проверить привязку 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}'
Примеры результатов:
{
"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"
}
}
}
Как создать собственное хранилище данных MCP-сервера
В этом разделе вы подключите сервер mcp-sprockets к Gemini Enterprise, создав специальное хранилище данных MCP OAuth 2.0, настроенное с помощью Google Identity (https://accounts.google.com/o/oauth2/v2/auth и https://oauth2.googleapis.com/token).
С помощью Discovery Engine API это можно сделать в два этапа:
- Создать (
:setUpDataConnector): создает выделенный ресурсCollection(${MCP_NAME}-collection-%timestamp), прикрепляетDataConnector(custom_mcp) сauth_type: "OAUTH"и инициализирует его резервный ресурсDataStore(..._mcp_data). - Активировать (
PATCH .../dataConnector?updateMask=actionConfig): активирует среду выполнения действий коннектора (actionState: "ACTIVE") с помощью спецификации инструмента реестра агентов, параметров OAuth 2.0 Google Identity и привязываетDataStore(dataStoreIds) к Gemini EnterpriseEngine.
# 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}"
Как создать коннектор данных
# 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
Как проверить создание коннектора данных
# fetch collection id
export GE_COLLECTION_ID=$(curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections" \
-H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
-H "X-Goog-User-Project: ${PROJ_ID}" \
| jq -r --arg dname "${MCP_NAME}-collection" '.collections[] | select(.displayName == $dname) | .name | split("/") | last' | head -n 1)
echo "ge collection id: ${GE_COLLECTION_ID}"
Убедитесь, что в поле "registry_mcp_server_name" указан UUID MCP-сервера из реестра агентов, а в поле "auth_type" – значение 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}'
Посмотреть запись реестра сервера MCP в интерфейсе консоли 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}"
Как активировать коннектор данных
# 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
Как проверить связи с собственным 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}'
Проверьте, есть ли связанное хранилище данных "dataStoreIds": ["mcp-sprockets-collection-[EPOCH]_mcp_data"].
# show collection details
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections" \
-H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
-H "X-Goog-User-Project: ${PROJ_ID}" \
| jq --arg app "${GE_APP_ID}" '.collections[] | select(.dataConnector.actionConfig.actionParams.agent_gateway_engine // "" | endswith($app)) | .dataConnector | {name: .name, state: .state, actionState: .actionState, connectorModes: .connectorModes, auth_type: .actionConfig.actionParams.auth_type}'
Проверьте, есть ли в нем "state": "ACTIVE" и "auth_type": "OAUTH".
Действия с инструментами
При проверке хранилища данных mcp-sprockets-collection на панели управления Gemini Enterprise вы заметите, что вкладка Действия не используется, а кнопка ↻ Перезагрузить специальные действия отключена. Это ожидаемое поведение.
Чтобы посмотреть страницу сведений о хранилище данных в интерфейсе Google Cloud Console:
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}"
В зависимости от того, как вы подключите собственный MCP-сервер к Gemini Enterprise, обнаружение инструментов и управление ими будет выполняться одним из двух способов:
- Прямой доступ к специальному MCP-серверу (
BYO_MCP): если вы настраиваете специальный MCP-сервер непосредственно в Gemini Enterprise без реестра агентов, каталог инструментов (connectorModes: ["FEDERATED", "ACTIONS"]) управляется хранилищем данных. Вам нужно открыть вкладку Действия, нажать ↻ Перезагрузить специальные действия, чтобы получить схемуtools/list, и вручную включить или отключить отдельные инструменты (addиsubtract) в интерфейсе. - Импорт из реестра агентов (
REGISTRY_MCPрабочий процесс, используемый в этой практической работе): при импорте MCP-сервера из реестра агентов этот реестр выступает в качестве авторитетного источника информации о конечной точке MCP, метаданных интерфейса и каталоге инструментов (connectorModes: ["FEDERATED"]). Gemini Enterprise автоматически включает зарегистрированные инструменты MCP во время выполнения через настройку шлюза агента без необходимости вручную перезагружать или переключать действия в интерфейсе хранилища данных.
На этом раздел о Gemini Enterprise завершается. Перейдем к разделу Проверка.
9. Проверить
В этом разделе вы выполните однократный процесс получения согласия пользователя Google OAuth 2.0, вызовете инструменты MCP на внешнем сервере mcp-sprockets из Gemini Enterprise и убедитесь, что внешний сервер MCP проверил как зарезервированный статический IP-адрес Cloud NAT (egress_source_ip), так и вашу учетную запись Google OAuth 2.0 (authenticated_user).
Доступ пользователей
Создайте URL для веб-приложения 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}"
Как предоставить согласие OAuth
Прежде чем отправлять запросы агенту, необходимо пройти процедуру согласия OAuth 2.0, чтобы предоставить Gemini Enterprise разрешение на получение токена доступа для вашего аккаунта Google (${USER_IDENTITY}). Это позволит Gemini Enterprise аутентифицировать исходящие вызовы инструментов через Agent Gateway, чтобы внешний сервер mcp-sprockets мог проверять вашу личность при каждом запросе.
- Откройте в браузере страницу
${GE_APP_USER_URL}и нажмите Начать. - В окне чата нажмите на значок Коннекторы (пазл) и выберите Авторизовать рядом с
mcp-sprockets-collection. - Откроется новое окно с предложением выбрать аккаунт для перехода к
mcp-sprockets-oauth(название приложения в окне запроса доступа OAuth, которое вы настроили). Выберите аккаунт пользователя (${USER_IDENTITY}). - На окне запроса доступа OAuth от Google проверьте запрошенные разрешения, которые позволяют Google (поставщику идентификационной информации) передавать вашу идентификационную информацию (
openid,email,profile) приложениюmcp-sprockets-oauth, а затем нажмите Продолжить. - Нажмите на значок Коннекторы ещё раз и убедитесь, что переключатель
mcp-sprockets-collectionвключен. Это означает, что авторизация прошла успешно.
Тестирование запросов к агенту
Тестирование интерфейса чата с Помощником
Отправьте в чат следующий тестовый запрос:
look up sprocket SPK-105 and confirm the model, material, unit_price, authenticated_user, and egress_source_ip
Попробуйте задать второй запрос в чате:
list all sprockets in the inventory catalog and report the authenticated_user and egress_source_ip
Убедитесь, что помощник дает правильные ответы и показывает интерактивный значок цитирования действия.
Например, значки Sprocket Lookup SPK-105 (5s)Agent Gateway под каждым ответом подтверждают, что инструмент был запущен.
Убедитесь, что Ассистент возвращает спецификации звездочки вместе с "authenticated_user", соответствующим ${USER_IDENTITY}, и "egress_source_ip", соответствующим зарезервированному ${NAT_EXT_IP}.
Тесты API Ассистента streamAssist
После того как ваш аккаунт пользователя авторизует коннектор OAuth 2.0, вы также можете вызвать API default_assistant:streamAssist непосредственно из интерфейса командной строки и убедиться, что внешний сервер mcp-sprockets возвращает и статический IP-адрес Cloud NAT (${NAT_EXT_IP}), и подтвержденный идентификатор Google OAuth 2.0 (${USER_IDENTITY}):
Отправьте следующий тестовый запрос:
# 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
Примеры результатов:
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
Попробуйте другой запрос:
# query engine (ge app) streamAssist
curl -s -X POST "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}/assistants/default_assistant:streamAssist" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "X-Goog-User-Project: ${PROJ_ID}" \
-H "Content-Type: application/json" \
-d @- <<EOF | jq -r '.[].answer.replies[]?.groundedContent?.content?.text // empty'
{
"query": {
"text": "find a sprocket model i can get for under \$20 and report the details, authenticated_user, and egress_source_ip"
},
"toolsSpec": {
"vertexAiSearchSpec": {
"dataStoreSpecs": [
{
"dataStore": "projects/${PROJ_NO}/locations/${GE_LOCATION}/collections/default_collection/dataStores/${GE_COLLECTION_ID}_mcp_data"
}
]
}
}
}
EOF
Как проверять журналы в Cloud Logging
Убедитесь, что Gemini Enterprise перенаправил вызовы инструментов через Agent Gateway, сетевое подключение PSC и Cloud NAT, проверив журналы в Cloud Logging.
Как проверить журналы шлюза агента
Убедитесь, что шлюз агента перехватил запрос, определил цель в реестре агентов, оценил правила авторизации и переслал вызов инструмента:
# 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
)"
Примеры результатов:
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
Убедитесь, что в выходных данных есть:
STATUS:200(успешное выполнение) и202(рукопожатиеnotifications/initialized).SERVER_IP: IP-адрес и порт внешнего MCP-сервера (${MCP_EXT_IP}:443).MCP_METHODиTOOL– последовательность протокола MCP (initialize,notifications/initialized,tools/listиtools/callсget_sprocket_by_id).AUTHZ:ALLOWED(разрешен исходящий трафик для авторизации покупок в приложении).REGISTRY_MCP: идентификатор ресурса реестра агентов (agentregistry-...).
Как проверить журналы Cloud NAT
Убедитесь, что Cloud NAT преобразовал исходящее подключение от IP-адреса сетевого подключения PSC Agent Gateway (10.10.10.2) к зарезервированному статическому внешнему адресу IPv4 (${NAT_EXT_IP}) при подключении к ${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
)"
Примеры результатов:
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
Проверьте журналы брандмауэра
Убедитесь, что внутренние правила брандмауэра (fw-policy-${SLUG}-internal) разрешают исходящий трафик от шлюза агента к целевому ресурсу в интернете:
# 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
)"
Убедитесь, что внешнее правило брандмауэра (fw-policy-${SLUG}-external) разрешает входящий трафик на MCP-сервер с общедоступного IP-адреса NAT внутренней сети:
# 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
)"
На этом этапе проверка завершена. Перейдите к разделу Очистка.
10. Очистка
Чтобы удалить ресурсы и конфигурации, созданные в этой лаборатории, выполните следующие действия:
Как удалить компоненты 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"}}'
Чтобы удалить учетные данные клиента OAuth 2.0 (ge-mcp-sprockets-client), откройте страницу клиентов платформы аутентификации Google и нажмите на значок Удалить (корзина) рядом с ge-mcp-sprockets-client:
# print google auth platform clients url
echo "https://console.cloud.google.com/auth/clients?project=${PROJ_ID}"
Как удалить компоненты MCP-сервера и реестра агентов
# 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}
Как удалить компоненты шлюза агента
# 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}
Как удалить компоненты брандмауэра
# 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
Как удалить сетевые компоненты
# 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
Как удалить переопределения правил организации и локальные файлы
# 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
На этом очистка завершена. Перейдем к заключению.
11. Заключение
Поздравляем! Вы создали комплексную архитектуру, позволяющую приложению Gemini Enterprise безопасно обнаруживать и вызывать инструменты на внешнем пользовательском MCP-сервере, защищенном с помощью OAuth 2.0 и белого списка IP-адресов:
- Исходящий трафик VPC со статическим IP-адресом (
ALL_TRAFFICи Cloud NAT). Весь исходящий трафик шлюза агента направлялся через сетевое подключение PSC (10.10.10.2), а запросы, предназначенные для интернета, преобразовывались в зарезервированный статический внешний адрес IPv4 (${NAT_EXT_IP}) с помощью Cloud NAT. - Сервер ресурсов MCP OAuth 2.0 и реестр агентов. Развернут внешний потоковый HTTP-сервер FastMCP (
mcp-sprockets), защищенный строгим белым списком IP-адресов источника (${NAT_EXT_IP}/32) и проверкой Google OAuth 2.0tokeninfo. Конечная точка и схема инструмента (get_sprocketsиget_sprocket_by_id) зарегистрированы в реестре агентов. - Интеграция и управление Gemini Enterprise с OAuth 2.0. Подготовлено приложение Gemini Enterprise, исходящий трафик инструментов привязан к шлюзу агента, зарегистрированный сервер MCP прикреплен как коннектор данных OAuth 2.0
REGISTRY_MCP, а также провереныegress_source_ipиauthenticated_userвместе с телеметрией Cloud Logging.

Космопес считает, что Codelabs – это круто!
Что дальше?
- Ознакомьтесь с документацией по Gemini Enterprise Agent Platform, чтобы узнать больше о продвинутых функциях и посмотреть учебные материалы.
- Настройте ограничения Model Armor в шлюзе агента для дополнительной безопасности ИИ.
- Изучите правила семантического управления, чтобы применять бизнес-правила и обеспечивать соответствие требованиям для запросов на естественном языке.
Если у вас есть комментарии, вопросы или исправления, заполните форму обратной связи.
Спасибо!