‫Gemini Enterprise مع بوابة الوكيل، وخروج جميع الزيارات من شبكة VPC، وعنوان IP ثابت من Cloud NAT إلى خادم MCP خارجي

1. مقدمة

يستكشف هذا الدرس التطبيقي حول الترميز إمكانية الاتصال الثابت بعنوان IP الصادر في Gemini Enterprise باستخدام Agent Gateway في وضع agent-to-anywhere (صادر). ستضبط تطبيق Gemini Enterprise لاستدعاء خادم بروتوكول سياق النموذج (MCP) مخصّص، محمي بقائمة سماح صارمة لعناوين IP المصدر ومصادقة OAuth 2.0، من خلال توجيه جميع حركة البيانات الصادرة عبر Agent Gateway باستخدام إعداد نموذج الاتصال. يربط مرفق شبكة Private Service Connect (PSC) خدمة Agent Gateway بشبكة VPC، وتوفّر خدمة Cloud NAT عنوان IP خارجيًا ثابتًا لحركة البيانات الصادرة على الإنترنت.

بشكلٍ تلقائي، تنشأ الاتصالات الصادرة من Gemini Enterprise إلى نقاط نهاية الإنترنت العامة من مجموعات عناوين IP الديناميكية والمشترَكة من Google التي لا يمكن ربطها بقاعدة واحدة من قواعد القائمة المسموح بها لعناوين IP التي يملكها العميل. يؤدي ربط Agent Gateway بـ AgentConnectivityTemplate في وضع ALL_TRAFFIC إلى توجيه جميع الزيارات الصادرة من الوكيل إلى شبكة VPC، حيث تترجم خدمة Cloud NAT الاتصالات المتجهة إلى الإنترنت إلى عنوان IPv4 خارجي ثابت محجوز يمكنك التحكّم فيه مع الحفاظ على إدارة أداة MCP المركزية من خلال قاعدة بيانات الوكلاء وIdentity-Aware Proxy (IAP).

ما يمكنك إنشاؤه

  • نموذج ربط الوكيل (vpcEgress: ALL_TRAFFIC) وAgent Gateway الذي يعمل في وضع الخروج (agent-to-anywhere) مع التحقّق من نقطة نهاية Agent Registry
  • شبكة السحابة الافتراضية الخاصة (VPC) ومرفق شبكة PSC وبوابة Cloud Router وCloud NAT المرتبطة بعنوان IPv4 خارجي ثابت محجوز
  • خادم موارد HTTP MCP خارجي قابل للبث (mcp-sprockets) يتم توجيهه من خلال Caddy TLS، ويتم تقييده بواسطة قواعد جدار الحماية بشكل صارم إلى عنوان IP الثابت في Cloud NAT، ويتم التحقّق من رموز Google OAuth 2.0 المميزة الخاصة بحامل الأذونات التي يمنحها المستخدم مقابل https://oauth2.googleapis.com/tokeninfo
  • شاشة طلب موافقة OAuth 2.0 لمنصة Google Auth وبيانات اعتماد عميل OAuth 2.0 لتطبيق الويب (accounts.google.com وoauth2.googleapis.com/token)
  • إدخال كتالوج خادم MCP في Agent Registry ومواصفات الأداة (toolspec.json)
  • إضافة تفويض Identity-Aware Proxy (IAP) وسياسة تفويض البوابة لـ Agent Gateway
  • تطبيق Gemini Enterprise مرتبط بـ Agent Gateway ومتصل بمخزن بيانات خادم MCP مخصّص تم استيراده من Agent Registry

figure1

الشكل 1. بنية الدرس التطبيقي حول الترميز

ما ستتعلمه

  • كيفية ضبط 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 ومخطط أدواته في Agent Registry
  • كيفية ربط خادم MCP مسجَّل لبروتوكول OAuth 2.0 بـ Gemini Enterprise وتوجيه طلبات استدعاء الأدوات التي يفوّضها المستخدم من خلال Agent Gateway
  • كيفية التحقّق من صحة ترجمة عنوان IP الثابت، وإثبات هوية المستخدم النهائي باستخدام OAuth 2.0 (authenticated_user)، وتنفيذ سياسة البوابة باستخدام أوامر واجهة سطر الأوامر وCloud Logging

ما تحتاج إليه

  • مشروع Google Cloud تم تفعيل الفوترة فيه
  • ترخيص Gemini Enterprise نشط أو فترة تجريبية لمدة 30 يومًا
  • أذونات إدارة الهوية وإمكانية الوصول لتوفير خدمات الشبكات وسياسات المؤسسة وGemini Enterprise وموارد Agent Platform
  • برنامج shell متوافق مع POSIX (bash أو zsh) مثبَّت عليه Google Cloud CLI (gcloud) وcurl وjq

بهذا نكون قد انتهينا من الجزء التمهيدي... لننتقل الآن إلى قسم المفاهيم.

2. المفاهيم

تسلسل النشر

ينشر هذا الدرس التطبيقي حول الترميز بنية الشبكات والحوكمة الأساسية أولاً حتى تكون مسارات الخروج الثابتة لعنوان IP وعناصر التحكّم في البوابة جاهزة للتشغيل قبل تسجيل أدوات بروتوكول سياق النموذج (MCP) وربطها بـ Gemini Enterprise:

  1. بنية الشبكة التحتية: احجز عناوين IPv4 خارجية ثابتة وقدِّم شبكة VPC للخروج والشبكة الفرعية لمرفق PSC ومرفق شبكة PSC وCloud Router وبوابة Cloud NAT وقواعد جدار الحماية الخارجية لشبكة MCP.
  2. نموذج ربط الوكيل وAgent Gateway: يمكنك نشر AgentConnectivityTemplate (vpcEgress: ALL_TRAFFIC) وAgentGateway الإقليمي في وضع الخروج (AGENT_TO_ANYWHERE) مع دمج Agent Registry (registries).
  3. سياسات التفويض: يمكنك ضبط إضافة تفويض IAP (AuthzExtension) وسياسة تفويض Gateway (AuthzPolicy) وسياسة الوصول الموحَّد الإصدار 3 في "إدارة الهوية وإمكانية الوصول" (AccessPolicy وPolicyBinding).
  4. نشر خادم MCP وتسجيله: يمكنك نشر mcp-sprockets خادم موارد OAuth 2.0 خارجي خلف Caddy TLS، والتحقّق من تنفيذ tokeninfo Google OAuth 2.0، وحظر جدار الحماية الوارد بشكل صارم على عنوان IP الثابت في Cloud NAT ‏ (${NAT_EXT_IP}/32)، وتسجيل مواصفات الخدمة والأداة (get_sprockets وget_sprocket_by_id) في Agent Registry.
  5. تطبيق Gemini Enterprise وعميل OAuth 2.0: اضبط Google Identity وترخيص الفترة التجريبية وشاشة طلب الموافقة على OAuth 2.0 وبيانات اعتماد عميل تطبيق الويب (OAUTH_CLIENT_ID وOAUTH_CLIENT_SECRET)، وأنشئ تطبيق Gemini Enterprise (Engine)، واربط عملية الخروج الصادر ببوابة Agent Gateway (agentGatewaySetting).
  6. استيراد أداة ربط بيانات MCP مخصّصة: أنشئ وفعِّل أداة ربط البيانات REGISTRY_MCP (:setUpDataConnector) التي تم ضبطها باستخدام auth_type: "OAUTH" لربط مخزن البيانات الاحتياطي لخادم MCP المسجّل بتطبيق Gemini Enterprise.
  7. التحقّق من الصحة: أكمل تدفّق الموافقة على OAuth 2.0 للمستخدم لمرة واحدة، واستخدِم أدوات بروتوكول سياق النموذج (MCP) من خلال مساعد Gemini Enterprise (مع تأكيد كل من egress_source_ip وauthenticated_user)، وتحقّق من إجراء التنفيذ للسياسة وترجمة NAT لعنوان IP الثابت في تسجيل Cloud.

بنية خادم موارد MCP المحمي باستخدام OAuth بالإضافة إلى موفّر الهوية المركزي

في عمليات النشر على مستوى المؤسسة، تتبع إدارة الهوية وتنفيذ الأدوات الفصل العادي للأدوار في بروتوكول OAuth 2.0 بين موفّر هوية مركزي (خادم تفويض) وخادم موارد MCP محمي:

دور OAuth 2.0

المكوّن في هذا الدرس التطبيقي حول الترميز

المسؤولية

مالك المورد

المستخدِم النهائي (${USER_IDENTITY})

تسجيل الدخول إلى تطبيق Gemini Enterprise على الويب ومنح الموافقة أثناء عملية التفويض لمرة واحدة باستخدام OAuth 2.0 المكوّن من 3 أجزاء

عميل OAuth 2.0

Gemini Enterprise custom_mcp Data Connector

يحتوي على OAUTH_CLIENT_ID وOAUTH_CLIENT_SECRET، ويتبادل رمز التفويض في oauth2.googleapis.com/token، ويخزّن رموز OAuth 2.0 المميزة للمستخدم، ويعرض Authorization: Bearer [access_token] في كل طلب صادر من أداة MCP.

خادم التفويض

بروتوكول Google Identity OAuth 2.0 (accounts.google.com وoauth2.googleapis.com/token)

تتم مصادقة المستخدم أثناء إعادة التوجيه إلى صفحة الموافقة في المتصفّح، ويتم إصدار رموز الدخول وإعادة التحميل لبروتوكول OAuth 2.0 إلى Gemini Enterprise.

خادم الموارد

خادم mcp-sprockets خارجي (https://mcp.[MCP_EXT_IP].sslip.io/mcp)

تفرض هوية شبكة الطبقة 3 باستخدام جدار الحماية الخاص بشبكة VPC (${NAT_EXT_IP}/32) وهوية مستخدم الطبقة 7 من خلال التحقّق من عنوان Authorization: Bearer [access_token] مقابل https://oauth2.googleapis.com/tokeninfo.

بما أنّ عملية إعادة التوجيه إلى صفحة الموافقة في المتصفّح (accounts.google.com) وعملية تبادل الرموز المميزة عبر القناة الخلفية (oauth2.googleapis.com/token) تتمّان مقابل نقاط نهاية OAuth 2.0 التي تديرها Google، لن يتلقّى جدار الحماية الخارجي لخادم MCP سوى طلبات JSON-RPC لوقت التشغيل (POST /mcp) من Agent Gateway من خلال Cloud NAT، ما يسمح بإغلاق جدار الحماية الوارد بإحكام على ${NAT_EXT_IP}/32.

نموذج موارد Discovery Engine

تطبيق Gemini Enterprise (يتم تمثيله كمورد Engine في Discovery Engine API) هو طبقة التنسيق المركزية وواجهة المحادثة للمستخدمين النهائيين. تدير هذه الخدمة جلسات المحادثات مع المستخدمين، وتستند إلى نماذج توليدية تستخدم بيانات المؤسسة، وتنسّق تنفيذ الأدوات الديناميكية.

تتفاعل تطبيقات Gemini Enterprise مع البيانات والأنظمة من خلال مخازن البيانات:

  • مخازن بيانات المعرفة: يمكنك استيعاب المحتوى الثابت وفهرسته (مثل Cloud Storage وGoogle Drive وBigQuery) من أجل إنشاء المحتوى باستخدام أسلوب الاسترجاع المعزّز (RAG).
  • أدوات ربط البيانات (مقدّمو الإجراءات): يمكنك الربط بواجهات برمجة تطبيقات ديناميكية تابعة لجهات خارجية أو مخصّصة. يعرض مخزن بيانات خادم MCP مخصّص الأدوات المحدّدة بموجب "بروتوكول سياق النموذج" (MCP)، ما يتيح للنموذج استدعاء وظائف خارجية بشكل ديناميكي أثناء المحادثة.

نقل البيانات من Gemini Enterprise

يوجّه Gemini Enterprise طلبات أدوات خادم MCP المخصّصة إلى Agent Gateway عندما يتم ضبط كل من agentGatewaySetting على Engine وuse_agent_gateway_egress: true على DataConnector.

figure2

الشكل 2. بنية خروج البيانات في Gemini Enterprise

ينظّم تطبيق Gemini Enterprise عملية توجيه الأدوات في أربعة مجالات رئيسية:

  1. التطبيق المصغّر (default_search_widget_config):
    • تعرض واجهة عميل الويب. يتلقّى التطبيق المصغّر طلبات من المستخدم، ويؤدي إلى إعادة توجيه طلب موافقة المستخدم لمرة واحدة على بروتوكول OAuth 2.0 عندما تتطلّب إحدى الأدوات الحصول على إذن، ويبدأ جلسات المحادثة مع المحرّك الأساسي.
  2. مساعد Google الأساسي (assistants/default_assistant/agents/default/core_assistant):
    • الوكيل الحواري الأساسي للاستدلال ضمن المحرّك عند تقييم طلب بحث من مستخدم، يفحص "المساعد الأساسي" الأدوات المتاحة ويفوّض تنفيذها إلى الوكيل الفرعي "بوابة الوكيل" الذي تم إنشاؤه.
  3. مخزن البيانات وأداة ربط البيانات:
    • DataStore: يتم توفيرها داخل Collection مخصّص عند تشغيل :setUpDataConnector، وتربط (dataStoreIds) مخططات أداة "سجلّ الوكلاء" المستوردة (get_sprockets وget_sprocket_by_id) وأنواع الوسيطات وتعليمات الوكيل بـ Engine في Gemini Enterprise.
    • DataConnector: يدير عملية ربط إجراء REGISTRY_MCP (createBapConnection: true) بخادم MCP البعيد (instance_uri)، ويحلّ مورد خادم MCP في Agent Registry (registry_mcp_server_name)، ويربط رمز OAuth 2.0 المميز المخزّن في خزينة المستخدم (Authorization: Bearer [access_token])، ويتيح خروج Agent Gateway (use_agent_gateway_egress: true).
  4. هوية الوكيل وسجلّ الوكلاء وAgent Gateway:
    • عندما ترسل "أداة ربط البيانات" طلبًا إلى الأداة الخارجية، فإنّها توجّه الزيارات إلى البوابة المحدّدة في agentGatewaySetting. يُصدر Core Assistant رمزًا مميزًا للمعلومات التعريفية SPIFFE يؤكّد معلومات تعريف عبء العمل: principal://agents.global.org-.../agents/default/core_assistant.
    • تتكامل Agent Gateway مع Agent Registry باستخدام الحقل registries لتحديد نقاط النهاية الوجهة ومخططات الأدوات المسجّلة بشكل ديناميكي، وتقييم سياسات التفويض باستخدام IAP، وإعادة توجيه الطلبات المسموح بها (مع الحفاظ على عنوان Authorization: Bearer الخاص بالمستخدم) إلى شبكة السحابة الافتراضية الخاصة (VPC) باستخدام AgentConnectivityTemplate.

الاتصال بشبكة VPC للبوابة وترجمة عناوين الشبكة (NAT) باستخدام عنوان IP ثابت

يتيح Agent Gateway الاتصال بشبكة السحابة الإلكترونية الخاصة الافتراضية باستخدام مورد AgentConnectivityTemplate تشير إليه agentConnectivityTemplate على البوابة. يحدّد النموذج egressNetworkConfig كيفية دخول الزيارات إلى شبكة VPC عبر ربط شبكة PSC:

  • PRIVATE_RANGES_ONLY (الإعداد التلقائي): لا يتم توجيه سوى نطاقات عناوين IP الخاصة بمعايير RFC 1918 وRFC 6598 والفئة E من خلال ربط شبكة PSC. تتجاوز الزيارات المتّجهة إلى الإنترنت شبكة VPC وتخرج مباشرةً من خلال عملية الخروج التلقائية من الإنترنت في Google.
  • ALL_TRAFFIC (المستخدَم في هذا الدرس التطبيقي حول الترميز): يوجّه كل حركة البيانات الصادرة من Agent Gateway، بما في ذلك الإنترنت العام ونقاط نهاية MCP الخاصة بالشركاء الخارجيين، إلى الشبكة الفرعية لسحابة VPC من خلال مرفق شبكة PSC (10.10.10.2).

عند التشغيل في وضع ALL_TRAFFIC، تتطلّب الشبكة الفرعية المرفقة بـ PSC إعدادَين:

  • الوصول الخاص إلى Google (--enable-private-ip-google-access): يضمن استمرار توجيه المكالمات الداخلية إلى واجهات برمجة تطبيقات Google Cloud (*.googleapis.com) بشكل خاص ضمن شبكة Google.
  • Cloud Router و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 التوافق الإقليمي بين الموقع الجغرافي للتطبيق وAgent Gateway وAgent Registry:

موقع تطبيق Gemini Enterprise

Agent Gateway وموقع NAT

موقع "سجلّ الوكلاء"

global

us-central1

us-central1 أو us أو global

us

us-central1

us-central1 أو us

eu

europe-west1

europe-west1 أو eu

بهذا نكون قد انتهينا من جزء المفاهيم... لننتقل الآن إلى قسم الإعداد.

3- الإعداد

أدوار "إدارة الهوية وإمكانية الوصول" المطلوبة

يجب أن تتوفّر الأدوار التالية لإكمال هذا الدرس التطبيقي حول الترميز:

النطاق

أدوار "إدارة الهوية وإمكانية الوصول" المطلوبة

المشروع وإدارة الهوية وإمكانية الوصول

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

الشبكات والبوابة

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

‫Gemini Enterprise و"قاعدة بيانات المسجّلين"

roles/discoveryengine.admin
roles/agentregistry.admin

أحمال العمل

‫roles/compute.instanceAdmin.v1 (أو roles/compute.admin)

إمكانية تتبُّع البيانات

roles/logging.viewer

أو استخدِم دورًا أساسيًا واسع النطاق، مثل roles/owner، مع roles/orgpolicy.policyAdmin (لأنّ roles/owner وحده لا يمكنه تعديل سياسات المؤسسة).

الوصول إلى مشروعك

يستخدم هذا الدرس التطبيقي حول الترميز مشروعًا واحدًا على Google Cloud. تستخدم خطوات الضبط واجهة سطر الأوامر gcloud وأوامر shell في Linux.

ابدأ بالوصول إلى سطر الأوامر في مشروعك على Google Cloud:

  • ‫Cloud Shell على shell.cloud.google.com أو
  • جهاز طرفي محلي gcloud مثبَّت عليه CLI

ضبط رقم تعريف المشروع

# 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

ضبط متغيّرات بيئة shell

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

echo ${SLUG}
echo ${REGION}
echo ${ZONE}
# create project vars (automatic)
export PROJ_ID=$(gcloud config list --format="value(core.project)")
export PROJ_NO=$(gcloud projects describe ${PROJ_ID} --format="value(projectNumber)")
export ORG_ID=$(gcloud projects get-ancestors ${PROJ_ID} --format="value(id)" | tail -n 1)
export USER_IDENTITY=$(gcloud config get-value account)

echo ${PROJ_ID}
echo ${PROJ_NO}
echo ${ORG_ID}
echo ${USER_IDENTITY}
# create resource vars for agent platform (automatic)
export AGW_NAME="agw-${SLUG}-${REGION}-ata"
export AGW_URI="projects/${PROJ_ID}/locations/${REGION}/agentGateways/${AGW_NAME}"
export MCP_NAME="mcp-sprockets"

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

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

ضبط نطاقات موثوق بها لهوية الوكيل

يتحقّق بيان 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

إذا كنت تستخدم عملية تثبيت مُدارة ذاتيًا لحزمة تطوير البرامج (SDK) من Google Cloud (أي خارج Cloud Shell)، عليك تعديل المكوّنات إلى أحدث إصدار.

# update gcloud cli
gcloud components update

تفعيل خدمات واجهة برمجة التطبيقات

# 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 نشطة أو عندما يكون المشروع مدرَجًا في 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 تلقائيًا وكيل خدمة Agent Gateway ويمنحه الإذن 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 (--enable-private-ip-google-access) مفعّلة.

أنشئ شبكة VPC عالمية لخروج Agent Gateway الداخلي:

# 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

إنشاء قواعد جدار حماية داخلية

أنشئ سياسة جدار حماية للسماح بجميع حركة بيانات الخروج مع تفعيل التسجيل. سيتم استخدام هذا المقياس لتتبُّع حركة البيانات الخارجة من Agent Gateway إلى شبكة 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) تم ضبطه على قبول الاتصالات تلقائيًا من Agent Gateway. يُنشئ مرفق الشبكة جانب شبكة VPC المستهلك من الاتصال للربط بشكل آمن بجانب المنتج في Agent Gateway من أجل حركة بيانات الخروج الصادرة. للحصول على معلومات إضافية حول متطلبات الشبكة الفرعية ومواصفات نطاق عناوين 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 المصدر لحركة بيانات الخروج من Agent Gateway إلى عنوان IP العام المحجوز للتوجيه عبر الإنترنت المتاح للجميع.

يتم تحديد المصادر من الشبكة الفرعية المرفقة بشبكة الخروج في Agent Gateway على أنّها مؤهَّلة لاستخدام 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: يسمح بمنفذ TCP الوارد 80 حتى تتمكّن Let's Encrypt من إكمال عملية التحقّق من صحة النطاق ACME HTTP-01 لـ ${MCP_DOMAIN}.
  • 2002: يسمح في البداية بمنفذ TCP الوارد 443 من 0.0.0.0/0 للتحقّق من إمكانية استخدام بروتوكول TLS وفرض tokeninfo بروتوكول OAuth 2.0 من shell محلي قبل حظره بشكل صارم على ${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- Agent Gateway

في هذا القسم، يمكنك نشر نموذج ربط الوكيل باستخدام vpcEgress: ALL_TRAFFIC، ونشر بوابة الوكيل الإقليمية، وتفويض إذن الوصول إلى خدمة Identity-Aware Proxy (IAP)، وتحديد قواعد سياسة الوصول الموحَّدة في "إدارة الهوية وإمكانية الوصول" للتحكّم في طلبات الشبكة الصادرة.

إنشاء نموذج اتصال

تحدّد مواصفات نموذج الاتصال ما يلي:

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

إنشاء Agent Gateway

تحدّد مواصفات Agent Gateway ما يلي:

  • agentConnectivityTemplate: يشير إلى نموذج الاتصال، ما يتيح للبوابة استخدام ملحق شبكة PSC للاتصال بشبكة VPC.
  • registries: يربط البوابة بـ Agent Registry الإقليمي لحلّ نقاط نهاية MCP المحدّدة في الفهرس ومخططات الأدوات.

أنشئ ملف إعداد Agent Gateway واستورِده:

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

تأكيد نشر "بوابة الوكيل"

أكِّد إعدادات "سجلّ الوكلاء" ونموذج الاتصال:

# 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) في خدمة Identity-Aware Proxy (IAP).

على الرغم من أنّ Agent Gateway يتيح استخدام قواعد ALLOW وDENY الأساسية المضمّنة، تتطلّب بيئات المؤسسات حوكمة مركزية ترتكز على الهوية. باستخدام "سياسات الوصول الموحَّدة" في "إدارة الهوية وإمكانية الوصول" (أو سياسات الوصول)، يمكنك إدارة قواعد الوصول إلى الخارج باستخدام سياسات الوصول العادية في الإصدار 3 من "إدارة الهوية وإمكانية الوصول".

figure3

الشكل 3. بنية التفويض

تربط عملية التفويض ثلاثة مكوّنات:

  1. سياسة تفويض البوابة (authzPolicy):
    • مورد إقليمي يستهدف Agent Gateway.
    • تم ضبطها باستخدام policyProfile: REQUEST_AUTHZ وaction: CUSTOM لتوجيه جميع عمليات التحقّق من التفويض الصادرة إلى إضافة التفويض في IAP.
  2. إضافة خدمة داخل التطبيق (authzExtension):
    • مورد إقليمي يفوّض عملية منح الإذن بالطلبات إلى خدمة Identity-Aware Proxy (iap.googleapis.com).
    • تقيّم السياسات في وضع ENFORCE باستخدام إصدار السياسة V2.
  3. سياسة الوصول الموحّد والربط في إدارة الهوية وإمكانية الوصول (accessPolicy وpolicyBinding):
    • موارد الإصدار 3 من "إدارة الهوية وإمكانية الوصول" (IAM) على مستوى العالم التي تحتوي على قواعد وصول دقيقة
    • تتم مصادقة هوية 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 تستهدف Agent Gateway وتفوّض عملية التحقّق من الطلبات إلى إضافة التفويض في 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
  )"

إنشاء سياسات الوصول في "إدارة الهوية وإمكانية الوصول"

يُفوض Agent Gateway الآن عمليات التحقّق من التفويض إلى IAP ويحلّل البيانات الوصفية للوجهة من Agent Registry. بعد ذلك، حدِّد قاعدة سياسة موحّدة لإدارة الهوية وإمكانية الوصول لتنظيم تنفيذ الأداة الصادرة.

تقيّم خدمة IAP تعبيرات سمات CEL استنادًا إلى سمات الوجهة التالية في "سجلّ الوكلاء":

  • حالة التسجيل (destination.is_registered):
    • قيمة منطقية (true/false) تشير إلى ما إذا كان قد تم إدراج الوجهة في "سجلّ الوكلاء".
  • اسم خادم MCP (destination.agent_registry.mcp_server.name):
    • اسم مورد خادم MCP الأساسي المسجَّل في Agent Registry
  • طريقة MCP (destination.agent_registry.mcp_server.method):
    • طريقة MCP التي يتم استدعاؤها (مثل tools/call أو tools/list أو initialize)
  • اسم الأداة (destination.agent_registry.mcp_server.tool.name):
    • اسم الأداة المحدّد الذي تم استدعاؤه (مثل get_sprocket_by_id أو get_sprockets)، ما يتيح الحصول على إذن دقيق على مستوى الأداة على خوادم MCP المسجَّلة.

تحديد قاعدة سياسة الوصول إلى "إدارة الهوية وإمكانية الوصول"

يحدّد بيان قاعدة سياسة "إدارة الهوية وإمكانية الوصول" ما يلي:

  • الجهات الرئيسية: هوية الجهة الرئيسية في SPIFFE التي تمثّل وكيل المساعد الأساسي في Gemini Enterprise.
  • الأذونات: إذن iap.googleapis.com/resources.egressViaIAP الشامل المطلوب لجميع زيارات الخروج التي تحكمها عمليات الشراء داخل التطبيق.
  • الشروط: تعبير 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) باستخدام القواعد المحدّدة في ملف البيان:

# 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) بنجاح، وافحص تفاصيل القاعدة:

# 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) بالمشروع

لتفعيل التنفيذ في جميع "بوابات الوكيل" في مشروعك، أنشئ ربط سياسة يربط سياسة الوصول إلى "إدارة الهوية وإمكانية الوصول" بمورد المشروع:

# 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

التحقّق من ربط سياسة الوصول إلى "إدارة الهوية وإمكانية الوصول"

تحقَّق من نقاط ربط السياسة النشطة بالسياسة والهدف الصحيحَين:

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

بهذا نكون قد انتهينا من جزء Agent Gateway... ننتقل الآن إلى قسم خادم MCP.

6. خادم MCP

في هذا القسم، ستنشئ خادم موارد خارجيًا FastMCP OAuth 2.0 (mcp-sprockets) يعرض الأداتَين get_sprockets وget_sprocket_by_id، وتتأكّد من أنّه يتحقّق من صحة رموز Google OAuth 2.0 المميزة بشكل مشفّر مقابل 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)، سيفعل الخادم ما يلي:

  1. قراءة عنوان IP الخاص بمصدر المتصل من العنوان X-Forwarded-For (egress_source_ip)
  2. استخرِج العنوان Authorization: Bearer [access_token] وتحقّق من الرمز المميز باستخدام نقطة نهاية التحقّق من Google OAuth 2.0 (https://oauth2.googleapis.com/tokeninfo?access_token=[token]).
  3. يجب عرض "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 وصحة tokeninfo في بروتوكول OAuth 2.0

انتظِر بضع دقائق حتى يتم تثبيت 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

تحقَّق من صحة عملية تحليل نظام أسماء النطاقات (DNS) في sslip.io، وشهادة بروتوكول أمان طبقة النقل (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 من 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. Agent Registry

‫Agent Registry هي مستودع مركزي لجميع الوكلاء وخوادم MCP ونقاط النهاية (واجهات برمجة التطبيقات) في منظومة الذكاء الاصطناعي المتكاملة. وهو أيضًا فهرس يمكن استخدامه لإدراج الأدوات والخدمات الأخرى المسجّلة والبحث عنها واكتشافها لاستخدامها في تطبيقات الذكاء الاصطناعي. تستخدم Agent Gateway نموذج بيانات السجلّ كإطار عمل للحوكمة من أجل فرض عناصر التحكّم في الوصول إلى البيانات الصادرة. يتم التحقّق من أذونات دور "إدارة الهوية وإمكانية الوصول" الممنوحة للمستخدم الأساسي الذي يستدعي الوكلاء مقارنةً بالسياسة المرتبطة بمورد السجلّ.

في هذا القسم، ستسجّل خادم MCP ومخطط أدواته (toolspec.json) في Agent Registry. لإتاحة تفاعل Gemini Enterprise مع واجهات برمجة التطبيقات والخدمات من Google من خلال Agent Gateway، عليك أيضًا إنشاء خدمة نقطة نهاية تسجيل واحدة (oauth2-googleapis) تحدّد واجهات Google API التي يستخدمها Gemini Enterprise لتبادل رمز المصادقة مقابل الرموز المميزة.

تسجيل خادم MCP

للسماح لـ Gemini Enterprise باكتشاف الأدوات المتاحة على خادم MCP، قدِّم ملف مواصفات الأداة (cfg/toolspec.json) عند تسجيل الخدمة في Agent Registry.

إنشاء مواصفات أداة 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 في Agent Registry

تأكَّد من أنّ الخدمة مُدرَجة كخادم 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) من خلال Agent Gateway، يجب تسجيل نقطة نهاية الرمز المميز في Agent Registry لكي يقيّم 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

سياسة الوصول في "إدارة الهوية وإمكانية الوصول"

بما أنّ سياسة الوصول إلى "إدارة الهوية وإمكانية الوصول" تحدّد سياسة السماح لأي خدمة مسجّلة يطلبها تطبيق Gemini Enterprise core_assistant، لا يلزم ربط أي سياسات إضافية لإدارة الهوية وإمكانية الوصول بعملية تبادل رموز OAuth المميزة.

  - 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})، وربط حركة الخروج الصادرة ببوابة Agent Gateway (${AGW_URI})، وربط خادم MCP المسجّل في sprockets باعتباره مخزن بيانات MCP مخصّصًا في OAuth 2.0.

إنشاء تطبيق Gemini Enterprise

تستخدم الطريقة التالية واجهة برمجة التطبيقات discoveryengine.googleapis.com لإنشاء موارد تطبيق Gemini Enterprise وإعداداته. لضبط الإعدادات باستخدام واجهة مستخدم Google Cloud Console، يُرجى الاطّلاع على إنشاء تطبيق للحصول على التعليمات.

# 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" كموفِّر الهوية لمصادقة المستخدمين النهائيين على تطبيق Gemini Enterprise.

تستخدِم الطريقة التالية واجهة برمجة التطبيقات discoveryengine.googleapis.com لضبط موفِّر هوية تطبيق Gemini Enterprise. لضبط الإعدادات باستخدام واجهة مستخدم Google Cloud Console، اطّلِع على ضبط موفّر الهوية للحصول على التعليمات.

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

(اختياري) تفعيل ترخيص تجريبي لـ 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.

للسماح لـ Gemini Enterprise (عميل OAuth 2.0) بالحصول على رمز مميّز لحامل الإذن من Google OAuth 2.0 مفوَّض من المستخدم وتقديمه إلى mcp-sprocketsخادم الموارد نيابةً عنك، عليك ضبط شاشة طلب الموافقة على OAuth في "منصة مصادقة Google" وإنشاء معرّف عميل لتطبيق ويب OAuth 2.0 في مشروعك.

اطبع عنوان URL المباشر الخاص بـ Google Cloud Console نظرة عامة على منصة Google Auth في مشروعك:

# print google auth platform consent screen url
echo "https://console.cloud.google.com/auth/overview?project=${PROJ_ID}"
  1. افتح عنوان URL في المتصفّح وانقر على البدء (إذا لم يتم إعداده لمشروعك بعد).
  2. ضمن معلومات التطبيق، اضبط اسم التطبيق على mcp-sprockets-oauth واختَر عنوان بريدك الإلكتروني (${USER_IDENTITY}) كـ البريد الإلكتروني لدعم المستخدمين، ثم انقر على التالي.
  3. ضمن الجمهور، اختَر داخلي (يُنصح بهذا الخيار إذا كان حسابك تابعًا لمؤسسة Google Workspace) أو خارجي (إذا كنت تستخدم حسابًا شخصيًا؛ إذا اخترت خارجي، أضِف ${USER_IDENTITY} ضمن **مستخدمو اختبار الجمهور**)، ثم انقر على التالي.
  4. أدخِل عنوان بريدك الإلكتروني ضمن معلومات الاتصال، واقبل اتفاقية السياسة، ثم انقر على إنشاء.

2. إنشاء معرّف عميل OAuth 2.0 لتطبيق الويب

اطبع عنوان URL المباشر لصفحة العملاء في Google Cloud Console:

# print google auth platform clients url
echo "https://console.cloud.google.com/auth/clients?project=${PROJ_ID}"
  1. افتح عنوان URL وانقر على + إنشاء عميل.
  2. اختَر تطبيق الويب كـ نوع التطبيق واضبط الاسم على ge-mcp-sprockets-client.
  3. ضَع علامة في مربّع الاختيار سيستخدم هذا العميل وكيل يستند إلى الذكاء الاصطناعي لتحديد عميل OAuth لسير عمل وكيل الذكاء الاصطناعي الذي يعمل نيابةً عن المستخدمين.
  4. ضمن معرّفات الموارد المنتظمة (URI) المعتمَدة لإعادة التوجيه، انقر على + إضافة معرّف الموارد المنتظمة (URI) وأضِف معرّف الموارد المنتظمة (URI) الخاص بعملية ردّ الاتصال في OAuth في Gemini Enterprise:
    • https://vertexaisearch.cloud.google.com/oauth-redirect
  5. انقر على إنشاء، وانسخ معرّف العميل وسر العميل اللذين تم إنشاؤهما، ثمّ صدِّرهما في جلسة shell:

اضبط معرّف عميل 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}"

الربط بـ Agent Gateway

يؤدي توجيه الزيارات الصادرة من Gemini Enterprise من خلال Agent Gateway إلى إنشاء حدود مركزية لفرض السياسات وتوجيه عناوين IP الثابتة لجميع عمليات استدعاء أدوات وكلاء الذكاء الاصطناعي، وذلك على النحو التالي:

  • فرض السياسات بشكل مركزي: تعمل Agent Gateway كخادم وكيل مضمّن يقيّم طلبات الأدوات الصادرة وفقًا لسياسات التفويض قبل أن تغادر الزيارات بيئة الوكيل.
  • الخروج من سحابة VPC وCloud NAT بشكلٍ حتمي: يضمن ربط Gemini Enterprise ببوابة Agent Gateway تم ضبطها باستخدام 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

التحقّق من ربط Agent Gateway

استرداد إعدادات التطبيق لتأكيد ربط 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، تتألف العملية من خطوتَين:

  1. إنشاء (:setUpDataConnector): ينشئ هذا الإجراء مورد Collection مخصّصًا (${MCP_NAME}-collection-%timestamp)، ويربط DataConnector (custom_mcp) بـ auth_type: "OAUTH"، ويوفر DataStore الأساسي (..._mcp_data).
  2. التفعيل (PATCH .../dataConnector?updateMask=actionConfig): يفعّل هذا الخيار وقت تشغيل إجراء الموصل (actionState: "ACTIVE") باستخدام مواصفات أداة Agent Registry ومعلَمات Google Identity OAuth 2.0، ويربط DataStore (dataStoreIds) بـ Engine في Gemini Enterprise.
# 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 في Agent Registry وأنّ "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 Console:

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 بدون Agent Registry، يدير مخزن البيانات نفسه قائمة الأدوات (connectorModes: ["FEDERATED", "ACTIONS"]). عليك فتح علامة التبويب الإجراءات والنقر على ↻ إعادة تحميل الإجراءات المخصّصة لجلب مخطط tools/list، ثم تفعيل الأدوات الفردية (add وsubtract) أو إيقافها يدويًا في واجهة المستخدم.
  • استيراد Agent Registry (REGISTRY_MCP سير العمل المستخدَم في هذا الدرس التطبيقي حول الترميز): عند استيراد خادم بروتوكول سياق النموذج (MCP) من Agent Registry، يعمل Agent Registry كمصدر موثوق للمعلومات عن نقطة نهاية بروتوكول سياق النموذج (MCP) وبياناتها الوصفية الخاصة بالواجهة وقائمة الأدوات (connectorModes: ["FEDERATED"]). يفعّل Gemini Enterprise تلقائيًا أدوات بروتوكول سياق النموذج (MCP) المسجّلة في وقت التشغيل من خلال إعداد Agent Gateway في المحرّك بدون الحاجة إلى إعادة تحميل الإجراءات أو تبديلها يدويًا في واجهة مستخدم مخزن البيانات.

بهذا نكون قد انتهينا من جزء 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 2.0 تمنح Gemini Enterprise الإذن بالحصول على رمز مميّز للوصول إلى هويتك على Google (${USER_IDENTITY}). يتيح ذلك لـ Gemini Enterprise المصادقة على طلبات الأدوات الصادرة من خلال Agent Gateway حتى يتمكّن خادم mcp-sprockets الخارجي من إثبات هويتك في كل طلب.

  1. افتح ${GE_APP_USER_URL} في المتصفّح وانقر على البدء.
  2. في مربّع المحادثة، انقر على رمز الموصلات (رمز قطعة الألغاز) ثم انقر على تفويض بجانب mcp-sprockets-collection.
  3. ستظهر نافذة جديدة تطلب منك اختيار حساب لمواصلة استخدام mcp-sprockets-oauth (اسم تطبيق شاشة طلب الموافقة لبروتوكول OAuth الذي ضبطته). اختَر حساب المستخدم (${USER_IDENTITY}).
  4. في شاشة طلب موافقة Google OAuth، راجِع الأذونات المطلوبة التي تسمح لشركة Google (موفّر الهوية) بمشاركة هوية المستخدم (openid وemail وprofile) مع mcp-sprockets-oauth، ثم انقر على متابعة.
  5. انقر على رمز الموصلات مرة أخرى وتأكَّد من تفعيل زر التبديل الخاص بـ mcp-sprockets-collection، ما يؤكّد نجاح عملية التفويض.

اختبار طلبات الوكيل

اختبارات واجهة مستخدم المحادثة في "مساعد Google"

أرسِل طلب البحث التجريبي التالي في المحادثة:

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)رمز أداة MCPAgent Gatewayرمز دائرة علامة الصح" الظاهر تحت كل ردّ إلى أنّه تم تنفيذ الأداة.

تأكَّد من أنّ "مساعد Google" يعرض مواصفات العجلة المسنّنة مع "authenticated_user" مطابق ${USER_IDENTITY} و"egress_source_ip" مطابق ${NAT_EXT_IP} المحجوز.

اختبارات واجهة برمجة التطبيقات streamAssist في "مساعد Google"

بعد أن يمنح حساب المستخدم الإذن لموصّل OAuth 2.0، يمكنك أيضًا استدعاء واجهة برمجة التطبيقات 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.

التحقّق من سجلّات Agent Gateway

تأكَّد من أنّ Agent Gateway اعترض الطلب، وحلّ الهدف في Agent Registry، وقَيّم سياسة التفويض، وأعاد توجيه طلب الأداة:

# 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 المرفق بالشبكة في Private Service Connect (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) سمحت بحركة البيانات الصادرة من Agent Gateway إلى وجهة الإنترنت:

# 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 Auth" وانقر على رمز حذف (سلة المهملات) بجانب ge-mcp-sprockets-client:

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

إزالة مكوّنات خادم MCP وAgent Registry

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

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

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

إزالة مكوّنات "بوابة الوكيل"

# 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): تم توجيه جميع الزيارات الصادرة من Agent Gateway من خلال ربط شبكة 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.0 tokeninfo، وتم تسجيل نقطة النهاية ومخطط الأداة (get_sprockets وget_sprocket_by_id) في قاعدة بيانات الوكلاء.
  • دمج بروتوكول OAuth 2.0 في Gemini Enterprise وإدارته: تم توفير تطبيق Gemini Enterprise، وربط حركة بيانات الأدوات الصادرة بـ Agent Gateway، وإرفاق خادم MCP المسجّل كأداة ربط بيانات REGISTRY_MCP لبروتوكول OAuth 2.0، والتحقّق من كل من egress_source_ip وauthenticated_user إلى جانب بيانات القياس عن بُعد في Cloud Logging.

cosmopup

ترى Cosmopup أنّ دروس Codelabs التطبيقية رائعة!

ما هي الخطوة التالية؟

يمكنك تقديم تعليقات أو طرح أسئلة أو اقتراح تصحيحات باستخدام نموذج الملاحظات هذا.

شكرًا