1. מבוא
בשיעור Codelab הזה נסביר איך ליצור קישוריות פרטית ומבוקרת ליציאה מ-Gemini Enterprise באמצעות Agent Gateway במצב agent-to-anywhere (יציאה). תגדירו אפליקציית Gemini Enterprise כדי להפעיל בצורה מאובטחת שרת מותאם אישית של Model Context Protocol (MCP) שמתארח ב-Cloud Run. לשם כך, תנתבו את התעבורה דרך Agent Gateway באמצעות ממשקי Private Service Connect (PSC) כדי להתחבר לנקודת קצה (endpoint) של PSC לממשקי Google APIs ברשת VPC.
בסביבות ארגוניות, מתן גישה ישירה לרשת לסוכנים אוטונומיים עלול להוביל לזליגת נתונים ולהרצת כלים שלא נבדקו. Agent Gateway מספק נקודת אכיפה מרכזית ברמת הפלטפורמה של גישת אפס אמון, שבודקת באופן דינמי מטען ייעודי (payload) של כלי MCP מסוג HTTP שאפשר להזרים. בקשות יוצאות מאומתות באמצעות זהות סוכן שניתנת לאימות קריפטוגרפי, ומקבלות הרשאה דרך שרת proxy לאימות זהויות (IAP) באמצעות כללי מדיניות מאוחדים של ניהול זהויות והרשאות גישה (IAM) עם כללי Common Expression Language (CEL). כך אפשר לשלוט ברמת גישה מפורטת לכלי MCP ולשיטות ספציפיות בלי לחשוף את עומסי העבודה של ה-Backend לאינטרנט הציבורי.
מה תפַתחו
- Agent Gateway פועל במצב יציאה (agent-to-anywhere) עם אימות של נקודת הקצה של Agent Registry
- שירות Cloud Run שמארח שרת MCP פרטי עם HTTP שניתן להזרמה (
--ingress=internal) ורשום במפרטי הכלים שלו ב-Agent Registry - תוסף הרשאות ל-Agent Gateway לשרת proxy לאימות זהויות (IAP)
- כללי מדיניות מאוחדים לגישה (UAP) ב-IAM עם תנאי CEL להרשאה של כלי MCP
- אפליקציית Gemini Enterprise שמקושרת ל-Agent Gateway ומחוברת למאגר נתונים של שרת MCP מותאם אישית שיובא מ-Agent Registry
- משאבי רשת VPC, אזור Cloud DNS ונקודת קצה (endpoint) של PSC עבור Google APIs
- מחבר רשת של PSC לתעבורת נתונים יוצאת (egress) פרטית מ-VPC של Agent Gateway
- כללי מדיניות של Cloud Next Generation Firewall (NGFW) לאבטחת תעבורה ב-VPC
איור 1. ארכיטקטורת Codelab
מה לומדים
- איך פורסים שרת MCP פרטי שניתן להזרמה ב-HTTP ממקור ב-Cloud Run ורושמים את נקודת הקצה ואת סכימת הכלים שלו ב-Agent Registry
- איך מגדירים את Agent Gateway עם רשומות תואמות של Agent Registry ומנתבים דרך השער קריאות לכלים באפליקציית Gemini Enterprise
- איך מגדירים תעבורת נתונים יוצאת (egress) פרטית של VPC באמצעות ממשקים וקבצים מצורפים לרשת של PSC
- איך להקצות הרשאות ל-Agent Gateway לשרת proxy לאימות זהויות (IAP)
- איך ליצור ולקשר כללי מדיניות מאוחדים לגישה (UAP) ב-IAM באמצעות מאפייני CEL
destination.agent_registry.*ו-destination.is_registeredכדי להגביל את ההרצה של כלי MCP - איך מאמתים את אכיפת המדיניות ואת תעבורת הנתונים היוצאת (egress) ברשת באמצעות Cloud Logging
מה צריך
- פרויקט ב-Google Cloud שהחיוב בו מופעל
- רישיון פעיל ל-Gemini Enterprise או תקופת ניסיון של 30 יום
- הרשאות IAM להקצאת משאבים של שירותי רשת, Gemini Enterprise ו-Agent Platform
- מעטפת תואמת POSIX (
bashאוzsh) עם Google Cloud CLI (gcloud),curlו-jqמותקנים
סיימנו את חלק המבוא ועכשיו נעבור לקטע מושגים.
2. מושגים
רצף הפריסה
בשיעור Codelab הזה נפרס קודם את התשתית, כדי שנתיבי הרשת הפרטית ואמצעי הבקרה על ניהול הגישה יהיו פעילים לפני שנרשום את כלי ה-MCP ונחבר אותם ל-Gemini Enterprise:
- תשתית רשת: הקצאת תת-רשתות של VPC, נקודת קצה (endpoint) של PSC, מחבר רשת של PSC, כללי מדיניות של Cloud NGFW ואזורי Cloud DNS פרטיים.
- Agent Gateway: פריסת Agent Gateway במצב יציאה עם שילוב של Agent Registry (
registries) ויציאה פרטית של VPC (networkAttachment). - כללי מדיניות הרשאה: הגדרת תוסף ההרשאה של IAP, מדיניות ההרשאה של Gateway וכללי מדיניות מאוחדים של IAM (UAP) באמצעות תנאי CEL
destination.is_registeredו-destination.agent_registry.*. - פריסה ורישום של שרת MCP: פורסים את שרת ה-MCP של המתמטיקה ממקור ל-Cloud Run (
--ingress=internal) ורושמים את מפרטי השירות והכלי (addו-subtract) ב-Agent Registry. - אפליקציית Gemini Enterprise: יוצרים את אפליקציית Gemini Enterprise (
Engine), מגדירים את הגדרות הזהות והניטור ומקשרים את התעבורה היוצאת ל-Agent Gateway (agentGatewaySetting). - ייבוא מחבר נתונים מותאם אישית של MCP: יוצרים ומפעילים את
REGISTRY_MCPמחבר הנתונים (:setUpDataConnector) כדי לקשר את מאגר הנתונים של שרת ה-MCP הרשום לאפליקציית Gemini Enterprise. - אימות: בדיקת הרשאות הפעלה של כלים בצ'אט ואימות אכיפת המדיניות ביומנים של Agent Gateway, DNS, חומת אש ו-Cloud Run.
יציאת נתונים מ-Gemini Enterprise
Gemini Enterprise מעביר בקשות לכלים של שרת MCP בהתאמה אישית אל Agent Gateway אם גם agentGatewaySetting ב-Engine וגם use_agent_gateway_egress: true ב-DataConnector מוגדרים.
איור 2. ארכיטקטורת יציאה של Gemini Enterprise
אפליקציית Gemini Enterprise מארגנת את ניתוב הכלים בארבעה תחומים מרכזיים:
- ווידג'ט (
default_search_widget_config):- מציג את ממשק לקוח האינטרנט. הווידג'ט מקבל פרומפטים מהמשתמש ומתחיל סשנים של צ'אט עם המנוע הבסיסי.
- הגרסה הבסיסית של Assistant (
assistants/default_assistant/agents/default/core_assistant):- סוכן השורש של מנוע הנימוקים בשיחה. כשמעריכים שאילתת משתמש, עוזר הליבה קובע אם נדרש חישוב אריתמטי, בודק את הכלים הזמינים ומקצה את ההרצה לסוכן המשנה של Agent Gateway הסינתטי.
- מאגר נתונים ומחבר נתונים:
DataStore: מוקצה בתוךCollectionייעודי כשמפעילים את:setUpDataConnector, ומקשר (dataStoreIds) את הסכימות של כלי Agent Registry המיובא (add,subtract), את סוגי הארגומנטים ואת ההוראות לסוכן אל Gemini EnterpriseEngine.-
DataConnector: מנהל את חיבור הפעולהREGISTRY_MCP(createBapConnection: true) לשרת MCP מרוחק (instance_uri), פותר את משאב שרת ה-MCP של Agent Registry (registry_mcp_server_name) ומאפשר יציאה (egress) של Agent Gateway (use_agent_gateway_egress: true).
- Agent Identity, Agent Registry ו-Agent Gateway:
- כשמחבר הנתונים שולח את הקריאה היוצאת לכלי, הוא מנתב את התנועה לשער שצוין ב-
agentGatewaySetting. הכלי Core Assistant יוצר אסימון זהות SPIFFE שמאשר את הזהות שלו:principal://agents.global.org-.../agents/default/core_assistant. - התכונה Agent Gateway משתלבת עם Agent Registry באמצעות השדה
registriesכדי לפתור באופן דינמי נקודות קצה של יעד וסכימות של כלים רשומים. הוא מאכלס את המאפייניםdestination.is_registeredו-destination.agent_registry.*ומעביר אותם ל-IAP v2 לצורך הערכה מול כללי CEL של מדיניות מאוחדת לגישה (UAP) ב-IAM, לפני שמאשרים את המעבר לרשת ה-VPC.
- כשמחבר הנתונים שולח את הקריאה היוצאת לכלי, הוא מנתב את התנועה לשער שצוין ב-
קישוריות של שער ל-VPC
Agent Gateway מאפשר קישוריות פרטית לרשת VPC באמצעות שני שדות YAML:
-
networkConfig.egress.networkAttachment: מכוון את התעבורה של כתובות IP פרטיות לניתוב דרך הקובץ המצורף לרשת PSC אל רשת ה-VPC. -
dnsPeeringConfig.domains: פתרון DNS של עמיתים באמצעות אזור Cloud DNS של רשת ה-VPC, כך ששמות מארחים של יעד (*.run.app) נפתרים לכתובת ה-IP הפרטית של נקודת הקצה של ה-PSC שמוגדרת ברשת ה-VPC.
הגבלות ודרישות
- רק ב-StreamableHTTP: אין תמיכה בשידור נתונים מדור קודם של אירועים שנשלחים מהשרת (SSE). בשרתי MCP צריך להשתמש ב-StreamableHTTP.
- נדרש TLS של רשות אישורים ציבורית: נקודות הקצה של MCP חייבות להשתמש באישורי TLS שחתומים על ידי רשות אישורים ציבורית מהימנה, גם כשניגשים אליהן באופן פרטי דרך PSC.
- עקיפה של מדיניות הארגון: לפני שמבצעים רישום של מאגר נתונים, צריך לעקוף באופן מפורש את מדיניות הארגון עבור מאגרי נתונים מותאמים אישית של MCP.
סיימנו את החלק של ההסברים… עכשיו נעבור לקטע הגדרה.
3. הגדרה
התפקידים שצריך ב-IAM
כדי להשלים את ה-Codelab, צריך את התפקידים הבאים:
דומיין | התפקידים שצריך ב-IAM |
Project & IAM |
|
Networking & Gateway |
|
Gemini Enterprise והמרשם | |
עומסי עבודה ו-Build |
|
ניראות (observability) |
|
אפשר גם להשתמש בתפקיד בסיסי רחב כמו roles/owner בשילוב עם roles/orgpolicy.policyAdmin (כי roles/owner לבד לא יכול לשנות את מדיניות הארגון).
גישה לפרויקט
בשיעור Codelab הזה משתמשים בפרויקט אחד ב-Google Cloud. בשלבי ההגדרה נעשה שימוש בפקודות של gcloud CLI ושל מעטפת Linux.
כדי להתחיל, ניגשים לשורת הפקודה של הפרויקט בענן ב-Google Cloud:
- Cloud Shell בכתובת
shell.cloud.google.com, או - מסוף מקומי עם
gcloudCLI מותקן
הגדרת מזהה הפרויקט
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"
echo ${SLUG}
echo ${REGION}
# 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 UAP_POLICY_NAME="uap-policy-${SLUG}"
export UAP_BINDING_NAME="uap-binding-${SLUG}"
export MCP_NAME="math-wizard"
export MCP_URL="https://${MCP_NAME}-${PROJ_NO}.${REGION}.run.app/mcp"
echo ${AGW_NAME}
echo ${AGW_URI}
echo ${UAP_POLICY_NAME}
echo ${UAP_BINDING_NAME}
echo ${MCP_NAME}
echo ${MCP_URL}
# create resource vars for gemini enterprise (automatic)
export GE_APP_DISPLAY_NAME="Codelab app"
export GE_APP_ORG_NAME="${SLUG}, Inc."
export GE_LOCATION="global"
export GE_APP_NAME="app-${SLUG}-${GE_LOCATION}"
export GE_APP_INIT="${GE_APP_NAME}_$(date +%s)"
echo ${GE_APP_DISPLAY_NAME}
echo ${GE_APP_ORG_NAME}
echo ${GE_LOCATION}
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 apis (part 1)
gcloud services enable \
agentregistry.googleapis.com \
agentidentity.googleapis.com \
aiplatform.googleapis.com \
apphub.googleapis.com \
apptopology.googleapis.com \
cloudapiregistry.googleapis.com \
cloudtrace.googleapis.com \
compute.googleapis.com \
dataform.googleapis.com \
iam.googleapis.com \
iap.googleapis.com \
logging.googleapis.com \
modelarmor.googleapis.com \
monitoring.googleapis.com \
networksecurity.googleapis.com \
networkservices.googleapis.com \
notebooks.googleapis.com \
observability.googleapis.com
# enable google apis (part 2)
gcloud services enable \
artifactregistry.googleapis.com \
cloudbuild.googleapis.com \
discoveryengine.googleapis.com \
dns.googleapis.com \
orgpolicy.googleapis.com \
run.googleapis.com \
saasservicemgmt.googleapis.com \
securitycenter.googleapis.com \
storage.googleapis.com \
telemetry.googleapis.com \
texttospeech.googleapis.com
מדיניות הארגון
אילוצים מנוהלים על מדיניות הארגון ב-Google Cloud מגבילים את התכונות שבהן נעשה שימוש ב-Codelab הזה:
-
discoveryengine.managed.disableCustomMcpServerConnector:- ההגדרה מגבילה את היצירה של מחברי נתונים שמשתמשים בשרת MCP מותאם אישית (
custom_mcp) כמקור נתונים (ההגדרה נאכפת כברירת מחדל).
- ההגדרה מגבילה את היצירה של מחברי נתונים שמשתמשים בשרת MCP מותאם אישית (
-
iam.managed.disableAccessPolicyBinding:- מגביל את הגישה של IAM v3 למשאבים (מופעל כברירת מחדל).
-
discoveryengine.managed.allowedEgressFqdns:- מגביל דומיינים יוצאים (
instance_uriFQDN) של מחברי נתונים כשה-VPC Service Controls (VPC-SC) פעיל או כשהפרויקט מופיע בפרמטרenforcedProjectsשל הארגון.
- מגביל דומיינים יוצאים (
-
discoveryengine.managed.allowedDataSources:- מגביל את סוגי מחברי הנתונים המותרים (
dataSource) כש-VPC-SC פעיל או כשהפרויקט מופיע בפרמטרenforcedProjectsשל הארגון.
- מגביל את סוגי מחברי הנתונים המותרים (
אפשר לבטל את כל ההגבלות של מדיניות הארגון שעברו בירושה ברמת הפרויקט על ידי הגדרה מפורשת של enforce: false.
השבתת אילוץ MCP בהתאמה אישית
# disable data connector constraint (allow custom mcp servers)
gcloud org-policies set-policy /dev/stdin << EOF
name: projects/${PROJ_NO}/policies/discoveryengine.managed.disableCustomMcpServerConnector
spec:
rules:
- enforce: false
EOF
# verify org policy constraint on project
gcloud org-policies describe discoveryengine.managed.disableCustomMcpServerConnector \
--project=${PROJ_ID} --effective
השבתת אילוץ מדיניות הגישה
# 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
# verify org policy constraint on project
gcloud org-policies describe iam.managed.disableAccessPolicyBinding \
--project=${PROJ_ID} --effective
בדיקה והשבתה של אילוצים מותנים של מחבר נתונים
כברירת מחדל, discoveryengine.managed.allowedEgressFqdns ו-discoveryengine.managed.allowedDataSources חוסמים את יצירת המחבר רק אם הפרויקט שלכם נמצא בתוך היקף של VPC Service Controls (VPC SC) או אם אדמין ארגוני הוסיף את הפרויקט שלכם ל-enforcedProjects.
קודם כל, בודקים את המדיניות בפועל בפרויקט:
# check effective egress fqdn constraint on project
gcloud org-policies describe discoveryengine.managed.allowedEgressFqdns \
--project=${PROJ_ID} --effective
# check effective data source constraint on project
gcloud org-policies describe discoveryengine.managed.allowedDataSources \
--project=${PROJ_ID} --effective
~~IF~~ האילוצים האלה נאכפים, כדי לוודא שהם לא יחסמו את ההגדרה של מחבר custom_mcp בארגון עם מדיניות מוגבלת או ב-VPC SC, צריך להגדיר את enforce: false בשתי המדיניות עבור הפרויקט:
# disable egress fqdn constraint on project
gcloud org-policies set-policy /dev/stdin << EOF
name: projects/${PROJ_NO}/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_NO}/policies/discoveryengine.managed.allowedDataSources
spec:
rules:
- enforce: false
EOF
# verify both constraints are disabled on project
gcloud org-policies describe discoveryengine.managed.allowedEgressFqdns \
--project=${PROJ_ID} --effective
gcloud org-policies describe discoveryengine.managed.allowedDataSources \
--project=${PROJ_ID} --effective
הרשאות IAM
מעניקים לחשבון המשתמש ולחשבון השירות שמשמש כברירת המחדל של Compute Engine ב-Cloud Build את תפקידי ה-IAM הנדרשים:
- חשבון משתמש (
${USER_IDENTITY}):- נדרשות הרשאות לפריסה ולהפעלת שירותים של Cloud Run (
roles/run.admin,roles/run.invoker,roles/iam.serviceAccountUser), ליצירת תמונות של קונטיינרים (roles/cloudbuild.builds.editor), לניהול של Gemini Enterprise (roles/discoveryengine.admin) ולכתיבה של מדיניות מאוחדת לגישה (roles/iam.accessPolicyAdmin).
- נדרשות הרשאות לפריסה ולהפעלת שירותים של Cloud Run (
- חשבון השירות של Compute Engine שמוגדר כברירת מחדל(
${PROJ_NO}-compute@developer.gserviceaccount.com):- ההרשאה הזו משמשת את Cloud Build כדי להכין את קוד המקור ב-Cloud Storage (
roles/storage.admin), להעביר תמונות ל-Artifact Registry (roles/artifactregistry.writer) ולכתוב יומני בנייה (roles/logging.logWriter).
- ההרשאה הזו משמשת את Cloud Build כדי להכין את קוד המקור ב-Cloud Storage (
מריצים את הפקודות הבאות כדי להקצות את קישורי התפקידים:
# grant roles to user account
gcloud projects add-iam-policy-binding ${PROJ_ID} \
--member="user:${USER_IDENTITY}" \
--role="roles/run.admin"
gcloud projects add-iam-policy-binding ${PROJ_ID} \
--member="user:${USER_IDENTITY}" \
--role="roles/iam.serviceAccountUser"
gcloud projects add-iam-policy-binding ${PROJ_ID} \
--member="user:${USER_IDENTITY}" \
--role="roles/run.invoker"
gcloud projects add-iam-policy-binding ${PROJ_ID} \
--member="user:${USER_IDENTITY}" \
--role="roles/discoveryengine.admin"
gcloud projects add-iam-policy-binding ${PROJ_ID} \
--member="user:${USER_IDENTITY}" \
--role="roles/iam.accessPolicyAdmin"
gcloud projects add-iam-policy-binding ${PROJ_ID} \
--member="user:${USER_IDENTITY}" \
--role="roles/cloudbuild.builds.editor"
# grant roles to default compute (cloud build) service account
gcloud projects add-iam-policy-binding ${PROJ_ID} \
--member="serviceAccount:${PROJ_NO}-compute@developer.gserviceaccount.com" \
--role="roles/storage.admin"
gcloud projects add-iam-policy-binding ${PROJ_ID} \
--member="serviceAccount:${PROJ_NO}-compute@developer.gserviceaccount.com" \
--role="roles/artifactregistry.writer"
gcloud projects add-iam-policy-binding ${PROJ_ID} \
--member="serviceAccount:${PROJ_NO}-compute@developer.gserviceaccount.com" \
--role="roles/logging.logWriter"
אימות הרשאות IAM
בודקים אם יש שישה (6) קישורי תפקידים בחשבון המשתמש.
# show iam policy on project for user account
gcloud projects get-iam-policy ${PROJ_ID} \
--flatten="bindings[].members" \
--filter="bindings.members:${USER_IDENTITY}" \
--format="table(bindings.role:label=ROLE, bindings.members:label=PRINCIPAL_IDENTITY)"
בודקים אם יש שלושה (3) קישורי תפקידים בחשבון השירות שמוגדר כברירת מחדל ב-Compute Engine.
# show iam policy on project for default compute service account
gcloud projects get-iam-policy ${PROJ_ID} \
--flatten="bindings[].members" \
--filter="bindings.members:${PROJ_NO}-compute@developer.gserviceaccount.com" \
--format="table(bindings.role:label=ROLE, bindings.members:label=PRINCIPAL_IDENTITY)"
אימות של הקישורים של סוכני השירות (אמצעי זהירות)
בפרויקט חדש, מערכת 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. רשת
בקטע הזה תפרסו רשת VPC באמצעות מצב מותאם אישית עם תת-רשת ייעודית /28 (192.168.10.0/28) שתומכת בחיבור הרשת של PSC לתעבורת נתונים יוצאת (egress) של Agent Gateway לרשת VPC.
נקודת הקצה (endpoint) של PSC ל-Google APIs נפרסת באמצעות /32כתובת IPv4 פנימית גלובלית אחת (172.16.20.20) כדי לתמוך בגישה פנימית פרטית ל-Google APIs ולשירותים של Google. בשיעור Codelab הזה, Agent Gateway מכוון ל-Cloud Run באמצעות נקודת הקצה של PSC על ידי פענוח הדומיין run.app. באמצעות שיתוף פעולה (peering) של Cloud DNS.
יצירת רשתות
יוצרים רשת VPC גלובלית.
# create vpc network
gcloud compute networks create vnet-${SLUG} --subnet-mode=custom
יוצרים רשתות משנה לחיבור לרשת PSC של Agent Gateway:
# create subnet for agent gateway psc na
gcloud compute networks subnets create subnet-${REGION}-agw \
--network=vnet-${SLUG} \
--range=192.168.10.0/28 \
--region=${REGION} \
--enable-private-ip-google-access
יצירת כללים לחומת האש
יוצרים מדיניות חומת אש שמאפשרת את כל תעבורת הנתונים היוצאת (egress) עם הפעלת הרישום ביומן. השירות ישמש למעקב אחרי תנועת הגולשים שיוצאת מ-Agent Gateway לרשת VPC. Cloud NGFW תומך ברמות Essentials ו-Standard לאבטחת רשת ולניטור תעבורה.
# create fw policy
gcloud compute network-firewall-policies create fw-policy-${SLUG} --global
# create fw policy rule
gcloud compute network-firewall-policies rules create 1001 \
--description="allow all out and log" \
--firewall-policy=fw-policy-${SLUG} \
--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} \
--firewall-policy=fw-policy-${SLUG} \
--network=vnet-${SLUG} \
--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 הזו תופיע בהגדרות של Agent Gateway (networkConfig.egress.networkAttachment) כדי להקצות את ממשק ה-PSC לתעבורת נתונים יוצאת (egress) לרשת ה-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}
יצירת נקודת קצה של PSC
נקודת קצה (endpoint) של Private Service Connect (PSC) לממשקי Google APIs משמשת את Agent Gateway כדי ליצור קישוריות פרטית לשרת ה-MCP של Cloud Run דרך נתיב ברשת פנימית, בלי לחשוף את התעבורה לאינטרנט הציבורי. קריאות לכלים יוצאות שיוצאות מ-Agent Gateway לרשת ה-VPC יפתרו את כתובת ה-URL של שירות Cloud Run (*.run.app) לכתובת ה-IP הפרטית של נקודת הקצה הזו.
שומרים כתובת IPv4 פנימית גלובלית לנקודת הקצה של PSC. כתובת ה-IP שנבחרה צריכה להיות כתובת /32 שלא חופפת לאף רשת משנה קיימת ברשת ה-VPC:
# set env var for psc ep ip address
export PSC_EP_IP="172.16.20.20"
echo ${PSC_EP_IP}
# reserve internal global ipv4 address
gcloud compute addresses create ip-psc2gapis \
--global \
--purpose=PRIVATE_SERVICE_CONNECT \
--addresses=${PSC_EP_IP} \
--network=vnet-${SLUG}
יוצרים נקודת קצה (endpoint) של PSC עבור Google APIs באמצעות חבילת all-apis, שכוללת את Cloud Run (run.app).
# create psc endpoint for google apis
gcloud compute forwarding-rules create psc2gapis \
--global \
--network=vnet-${SLUG} \
--address=ip-psc2gapis \
--target-google-apis-bundle=all-apis
אימות נקודת הקצה של PSC
# show psc endpoint details
gcloud compute forwarding-rules describe psc2gapis --global
יצירת תחום DNS ורשומות
משתמשים ב-Cloud DNS כדי לאפשר ל-Agent Gateway לתקשר באופן פרטי עם שרת ה-MCP שמתארח ב-Cloud Run. כש-Agent Gateway מעריך בקשות לכלים יוצאים שמיועדות ל-Cloud Run, הוא משתמש בקישור בין רשתות שכנות (peering) ב-DNS (dnsPeeringConfig.domains) כדי לפתור שאילתות DNS עבור *.run.app באמצעות אזור ה-DNS הפרטי ב-Cloud שמשויך לרשת ה-VPC שלכם. רשומת ה-DNS הפרטית מחזירה את השאילתה עם כתובת ה-IP של נקודת הקצה (endpoint) הפנימית של PSC (172.16.20.20), וכך מאפשרת לנתב בקשות של כלי MCP דרך נתיב רשת פרטי.
יוצרים תחום מנוהל פרטי ב-Cloud DNS לדומיין run.app.:
# create private dns zone
gcloud dns managed-zones create priv-zone-run \
--description="private zone for run.app" \
--dns-name="run.app." \
--visibility=private \
--networks=vnet-${SLUG}
יוצרים רשומת DNS עם תו כללי A עבור *.run.app. שמפנה לכתובת ה-IP של נקודת הקצה (endpoint) של PSC:
# create dns record
gcloud dns record-sets create "*.run.app." \
--zone=priv-zone-run \
--type=A \
--ttl=300 \
--rrdatas=${PSC_EP_IP}
יוצרים מדיניות Cloud DNS כדי להפעיל רישום ביומן של שאילתות DNS. רישום ביומן של DNS מתעד בקשות לרזולוציית דומיין שמקורן ב-Agent Gateway ברשת ה-VPC שלכם, ומאפשר לכם לבדוק ש*.run.app בקשות לכלים מתורגמות בצורה נכונה לנקודת הקצה הפנימית של PSC:
# create dns policy (logging)
gcloud dns policies create dns-policy-${SLUG} \
--description="dns logging for vnet-${SLUG}" \
--networks=vnet-${SLUG} \
--enable-logging
כאן מסתיים החלק שקשור לרשת... נעבור עכשיו לקטע Agent Gateway.
5. Agent Gateway
Agent Gateway מציין registries למופעים של Agent Registry לצד השדות networkConfig שמגדירים את מחבר הרשת של PSC ואת הגדרות הקישור בין שרתי DNS לקישוריות פרטית של VPC:
-
registries: משייך את שער הסוכנים לעד שני מופעים של Agent Registry: אחד אזורי (../locations/${REGION}) ואחד גלובלי (../locations/global). הפעולה הזו משלבת את Agent Gateway עם Agent Registry כדי לפתור פריסות אזוריות (כמו שרתי MCP של Cloud Run ב-${REGION}) ומשאבים גלובליים (כמו סוכני Gemini Enterprise ונקודות קצה גלובליות) לצורך אכיפה מדויקת של מדיניות IAP v2. כשמנתחים כתובות URL של יעדים, רשומות אזוריות מקבלות עדיפות על פני רשומות גלובליות. -
networkAttachment: מצביע על רכיב ה-PSC לחיבור לרשת (psc-na-${REGION}-agw), שמחבר את Agent Gateway לרשת ה-VPC שלכם ליציאה פרטית. -
dnsPeeringConfig.domains: מגדיר אתrun.app.כך ששאילתות DNS שמקורן ב-Agent Gateway לשירותי Cloud Run ישתמשו ב-DNS peering כדי לפתור שמות מארחים לכתובת ה-IP של נקודת הקצה הפרטית של Google APIs PSC (172.16.20.20) שהוגדרה באזור הפרטי של Cloud DNS.
פריסת Agent Gateway
יוצרים ומייבאים את קובץ ההגדרות של Agent Gateway.
# create agent gateway config file
cat > cfg/${AGW_NAME}-networkConfig.yaml << EOF
name: ${AGW_NAME}
protocols:
- MCP
googleManaged:
governedAccessPath: AGENT_TO_ANYWHERE
registries:
- "//agentregistry.googleapis.com/projects/${PROJ_ID}/locations/${REGION}"
networkConfig:
egress:
networkAttachment: ${PSC_NA_URI}
dnsPeeringConfig:
domains:
- run.app.
targetProject: ${PROJ_ID}
targetNetwork: projects/${PROJ_ID}/global/networks/vnet-${SLUG}
EOF
# import agent gateway config file (create gateway)
gcloud network-services agent-gateways import ${AGW_NAME} \
--source="cfg/${AGW_NAME}-networkConfig.yaml" \
--location=${REGION}
אימות הפריסה של Agent Gateway
מאשרים את Agent Registry ואת הגדרת הרשת:
# show agent gateway registries and network config
gcloud network-services agent-gateways describe ${AGW_NAME} \
--location=${REGION} \
--format="yaml(registries,networkConfig)"
הפלט הצפוי:
networkConfig:
dnsPeeringConfig:
domains:
- run.app.
targetNetwork: projects/${PROJ_ID}/global/networks/vnet-${SLUG}
targetProject: ${PROJ_ID}
egress:
networkAttachment: projects/${PROJ_ID}/regions/${REGION}/networkAttachments/psc-na-${REGION}-agw
registries:
- //agentregistry.googleapis.com/projects/${PROJ_ID}/locations/${REGION}
מוודאים שהפלט מציג את פרטי ההגדרה הנדרשים:
-
registries: מציג את ה-URI של Agent Registry האזורי (${REGION}) שמשויך לשער. -
egress.networkAttachment: מציין את ה-URI של רשת PSC ליציאה מרשת VPC. -
dnsPeeringConfig.domains: מכילrun.app.שמצביע עלtargetNetworkלפתרון של דומיין פרטי.
בודקים את הקובץ המצורף לרשת PSC כדי לוודא שהשער מחובר:
# show psc network attachment details
gcloud compute network-attachments describe psc-na-${REGION}-agw \
--region=${REGION} \
--format="yaml(connectionEndpoints)"
בודקים שיש נקודת קצה (endpoint) של חיבור שאושרה:
connectionEndpoints:
- ipAddress: 192.168.10.2
projectIdOrNum: '<AGW_TENANT_PROJ_NO>'
status: ACCEPTED
subnetwork: https://www.googleapis.com/compute/v1/projects/${PROJ_ID}/regions/${REGION}/subnetworks/subnet-${REGION}-agw
הענקת הרשאה
Agent Gateway מאבטח את התעבורה של כלי יוצאים ושולט בה באמצעות מדיניות הרשאות (networksecurity.authzPolicies) שמשולבת עם מדיניות גישה מאוחדת (UAP) של שרת proxy לאימות זהויות (IAP).
למרות ש-Agent Gateway תומך בכללים בסיסיים של ALLOW ו-DENY, בסביבות ארגוניות נדרש ניהול מרכזי שמבוסס על זהות. באמצעות מדיניות גישה מאוחדת ב-IAM (או מדיניות גישה), אתם יכולים לנהל כללי גישה ליציאה באמצעות מדיניות גישה רגילה ב-IAM v3.
איור 3. ארכיטקטורת הרשאות
תהליך ההרשאה מחבר בין שלושה רכיבים:
- מדיניות הרשאות ל-Gateway (
authzPolicy):- משאב אזורי שמכוון ל-Agent Gateway.
- ההגדרה בוצעה באמצעות
policyProfile: REQUEST_AUTHZו-action: CUSTOMכדי להפנות את כל בדיקות ההרשאה היוצאות לתוסף IAP Authz.
- IAP Service Extension (
authzExtension):- משאב אזורי שמקצה הרשאת בקשה לשרת proxy לאימות זהויות (
iap.googleapis.com). - המערכת מעריכה את כללי המדיניות במצב
ENFORCEבאמצעות גרסת המדיניותV2.
- משאב אזורי שמקצה הרשאת בקשה לשרת proxy לאימות זהויות (
- מדיניות מאוחדת של IAM וקישור (
accessPolicyו-policyBinding):- משאבי IAM v3 גלובליים שמכילים כללי גישה פרטניים.
- הפונקציה מאמתת את זהות המנהל (principal) של הסוכן המתקשר ב-SPIFFE, בודקת את הרשאת
iap.googleapis.com/resources.egressViaIAPהאוניברסלית ומעריכה תנאים של Common Expression Language (CEL) ביחס למאפייני היעד.
פריסת תוסף הרשאות
יוצרים הגדרת תוסף הרשאה של service-extensions שמקצה את ההחלטות בנוגע להרשאה לשירות IAP:
# 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 iap authz extension (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,
updateTime.date(tz=LOCAL):label=MODIFIED,
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,
customProvider.list().sub('\W.*', ''):label=CUSTOM_PROVIDER_TYPE,
policyProfile:label=POLICY_PROFILE,
customProvider.authzExtension.resources[0].basename():label=CUSTOM_PROVIDER_RESOURCE
)"
יצירת מדיניות גישה ב-IAM
הסמכת סוכנים (Agent Gateway) מעבירה עכשיו את בדיקות ההרשאות ל-IAP ומקבלת את המטא-נתונים של היעד מ-Agent Registry. בשלב הבא, מגדירים כלל מדיניות גישה מאוחדת ב-IAM כדי לשלוט בהפעלת כלי יוצאים.
IAP מעריך ביטויי מאפיינים של CEL ביחס למאפייני היעד הבאים של Agent Registry:
- סטטוס רשום (
destination.is_registered):- ערך בוליאני (
true/false) שמציין אם היעד רשום ב-Agent Registry.
- ערך בוליאני (
- שם שרת MCP (
destination.agent_registry.mcp_server.name):- שם משאב קנוני של שרת MCP שרשום ב-Agent Registry.
- שיטת MCP (
destination.agent_registry.mcp_server.method):- שיטת ה-MCP שמופעלת (למשל,
tools/call, tools/list, initialize).
- שיטת ה-MCP שמופעלת (למשל,
- שם הכלי (
destination.agent_registry.mcp_server.tool.name):- השם הספציפי של הכלי שהופעל (למשל,
subtractאוadd), שמאפשר הרשאה ברמת הכלי בשרתי MCP רשומים.
- השם הספציפי של הכלי שהופעל (למשל,
הגדרת כלל של מדיניות הגישה ב-IAM
מניפסט הכללים של מדיניות IAM מציין:
- חשבונות ראשיים: זהות החשבון הראשי של SPIFFE שמייצגת את סוכן העוזר הראשי של Gemini Enterprise.
- הרשאות: ההרשאה האוניברסלית
iap.googleapis.com/resources.egressViaIAPנדרשת לכל תעבורת הנתונים היוצאת שמנוהלת על ידי IAP. - תנאים: ביטוי CEL (
destination.is_registered == true) שמבטיח שהסוכן יכול להפעיל רק נקודות קצה שמקוטלגות ב-Agent Registry.
יוצרים את קובץ המניפסט של כלל המדיניות:
# create access policy rule file
cat > cfg/${UAP_POLICY_NAME}-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_NAME} \
--details-rules=cfg/${UAP_POLICY_NAME}-rules.json \
--project=${PROJ_ID} \
--location=global
אימות מדיניות הגישה ב-IAM
בודקים שמדיניות הגישה ב-IAM נוצרה בהצלחה, ומסתכלים על פרטי הכלל:
# show iam access policy details
gcloud iam access-policies describe ${UAP_POLICY_NAME} \
--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/${GE_APP_INIT}/assistants/default_assistant/agents/default/core_assistant
name: projects/${PROJ_ID}/locations/global/accessPolicies/${UAP_POLICY_NAME}
קישור מדיניות גישה ב-IAM לפרויקט
כדי להפעיל את האכיפה בכל שער הסוכנים בפרויקט, יוצרים קשר מדיניות שמצרף את מדיניות הגישה של IAM למשאב הפרויקט:
# bind iam access policy to project resource
gcloud iam policy-bindings create ${UAP_BINDING_NAME} \
--policy="projects/${PROJ_ID}/locations/global/accessPolicies/${UAP_POLICY_NAME}" \
--target-resource="//cloudresourcemanager.googleapis.com/projects/${PROJ_ID}" \
--project=${PROJ_ID} \
--location=global
אימות של קשירת מדיניות הגישה ב-IAM
בודקים את נקודות הקישור הפעילות למדיניות הנכונה ולטירגוט הנכון:
# show policy binding details
gcloud iam policy-bindings describe ${UAP_BINDING_NAME} \
--project=${PROJ_ID} \
--location=global
הפלט הצפוי:
name: projects/${PROJ_ID}/locations/global/policyBindings/${UAP_BINDING_NAME}
policy: projects/${PROJ_ID}/locations/global/accessPolicies/${UAP_POLICY_NAME}
policyKind: ACCESS
target:
resource: //cloudresourcemanager.googleapis.com/projects/${PROJ_ID}
כאן מסתיים החלק שקשור ל-Agent Gateway... עכשיו נעבור לקטע בנושא שרת MCP.
6. שרת MCP
בקטע הזה ניצור שרת FastMCP בהתאמה אישית שחושף את הכלים add ו-subtract, ונפרוס אותו ב-Cloud Run ישירות מהמקור. במהלך פריסת קוד המקור (--source), Cloud Build יארוז את קובץ האימג' של הקונטיינר באמצעות Dockerfile ו-uv (שמתקין את התלות שמוגדרת ב-pyproject.toml ומפעיל את server.py).
אחרי פריסת שירות Cloud Run, רושמים את שרת ה-MCP ב-Agent Registry יחד עם מפרט הכלים שלו (toolspec.json), כדי ש-Gemini Enterprise יוכל לגלות את הכלים שלו ולהשתמש בהם.
יצירת אפליקציית שרת MCP
יוצרים ספריית פרויקט math-wizard לקוד האפליקציה:
# create directory for code
mkdir -p math-wizard
כתיבת קובץ המניפסט של פרויקט Python:
# create python project manifest file
cat > math-wizard/pyproject.toml << 'EOF'
[project]
name = "math-wizard"
version = "0.1.0"
description = "math wizard mcp server"
requires-python = ">=3.12"
dependencies = [
"fastmcp==2.13.1",
]
EOF
כדי לתעד כותרות HTTP נכנסות (mcp-session-id, x-forwarded-for, user-agent ו-x-cloud-trace-context) לצורך אימות של Cloud Logging ו-Cloud Trace, כללנו בקוד כמה פונקציות נוספות של מכשור.
כותבים את קובץ קוד האפליקציה:
# create mcp server application code
cat > math-wizard/server.py << 'EOF'
import asyncio
import json
import logging
import os
from fastmcp import FastMCP
from fastmcp.server.dependencies import get_http_headers
from mcp.types import ToolAnnotations
logger = logging.getLogger(__name__)
logging.basicConfig(format="[%(levelname)s]: %(message)s", level=logging.INFO)
mcp = FastMCP("math wizard mcp server")
def log_network_context(tool_name: str, a: int, b: int) -> None:
headers = get_http_headers()
print(json.dumps({
"severity": "INFO",
"message": f">>> 🛠️ Tool: '{tool_name}' called with numbers '{a}' and '{b}'",
"tool": tool_name,
"mcp_session_id": headers.get("mcp-session-id"),
"x_forwarded_for": headers.get("x-forwarded-for"),
"user_agent": headers.get("user-agent"),
"trace_header": headers.get("x-cloud-trace-context"),
}), flush=True)
@mcp.tool(
annotations=ToolAnnotations(
readOnlyHint=True,
)
)
def add(a: int, b: int) -> int:
"""Use this to add two numbers together.
Args:
a: The first number.
b: The second number.
Returns:
The sum of the two numbers.
"""
logger.info(f">>> 🛠️ Tool: 'add' called with numbers '{a}' and '{b}'")
log_network_context("add", a, b)
return a + b
@mcp.tool(
annotations=ToolAnnotations(
readOnlyHint=True,
)
)
def subtract(a: int, b: int) -> int:
"""Use this to subtract two numbers.
Args:
a: The first number.
b: The second number.
Returns:
The difference of the two numbers.
"""
logger.info(f">>> 🛠️ Tool: 'subtract' called with numbers '{a}' and '{b}'")
log_network_context("subtract", a, b)
return a - b
if __name__ == "__main__":
logger.info(f"🚀 MCP server started on port {os.getenv('PORT', 8080)}")
asyncio.run(
mcp.run_async(
transport="streamable-http",
host="0.0.0.0",
port=int(os.getenv("PORT", 8080)),
)
)
EOF
כותבים את Dockerfile כדי להגדיר הוראות ליצירת קובץ אימג' של קונטיינר ופקודות הפעלה:
# create dockerfile
cat > math-wizard/Dockerfile << 'EOF'
# use official python 3.12 image
FROM python:3.12-slim
# install uv
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
# install the project into /app
COPY . /app
WORKDIR /app
# allow statements and log messages to immediately appear in the logs
ENV PYTHONUNBUFFERED=1
# install dependencies
RUN uv sync
EXPOSE 8080
# run the mcp server
CMD ["uv", "run", "server.py"]
EOF
פריסת שירות ב-Cloud Run
פריסת שרת ה-MCP ממקור באמצעות Cloud Build (שמשתמש בחשבון השירות שמוגדר כברירת מחדל בפרויקט ${PROJ_NO}-compute@developer.gserviceaccount.com):
# deploy cloud run service
gcloud run deploy ${MCP_NAME} \
--source math-wizard \
--region=${REGION} \
--no-invoker-iam-check \
--ingress=internal \
--quiet
אימות הפריסה ב-Cloud Run
בודקים את פרטי השירות של Cloud Run כדי לוודא שההגדרה שלו פעילה:
# show cloud run service details
gcloud run services describe ${MCP_NAME} --region=${REGION}
הפלט הצפוי:
<snip>
✔ Service math-wizard in region ${REGION}
URL: https://math-wizard-${PROJ_NO}.${REGION}.run.app
Ingress: internal
Traffic:
100% LATEST (currently math-wizard-00001-<id>)
</snip>
רישום שרת MCP ב-Agent Registry
כדי לאפשר ל-Gemini Enterprise לגלות את הכלים המדויקים שזמינים בשרת ה-MCP, צריך לספק קובץ מפרט כלים (toolspec.json) במהלך הרישום ל-Agent Registry.
יצירת מפרט של כלי MCP
# create tool spec file
cat > cfg/toolspec.json << 'EOF'
{
"tools": [
{
"name": "add",
"description": "Use this to add two numbers together.",
"inputSchema": {
"type": "object",
"properties": {
"a": { "type": "integer", "description": "The first number." },
"b": { "type": "integer", "description": "The second number." }
},
"required": ["a", "b"]
},
"isReadOnly": true,
"isDestructive": false,
"isIdempotent": true,
"isOpenWorld": false
},
{
"name": "subtract",
"description": "Use this to subtract two numbers.",
"inputSchema": {
"type": "object",
"properties": {
"a": { "type": "integer", "description": "The first number." },
"b": { "type": "integer", "description": "The second number." }
},
"required": ["a", "b"]
},
"isReadOnly": true,
"isDestructive": false,
"isIdempotent": true,
"isOpenWorld": false
}
]
}
EOF
רישום שרת MCP ב-Agent Registry
# register mcp server in agent registry
gcloud agent-registry services create ${MCP_NAME} \
--project=${PROJ_ID} \
--location=${REGION} \
--display-name="${MCP_NAME}-${PROJ_NO}.${REGION}.run.app" \
--description="MANDATORY MATH & ARITHMETIC AGENT: You MUST ALWAYS invoke \
this tool for ANY mathematical calculation, addition (+), subtraction (-), \
sum, difference, or arithmetic question (including simple questions like \
'what is 67 + 345?'). NEVER compute arithmetic yourself and NEVER transfer \
math queries to file_and_coding_agent / code interpreter. Always delegate \
every math question 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
מוודאים ששירות Cloud Run שנפרס מופיע כאחד משרתי ה-MCP הרשומים באזור, יחד עם כתובת ה-URL של נקודת הקצה והכלים הזמינים:
# list registered mcp servers in agent registry
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-0012-3456789abcde math-wizard-${PROJ_NO}.${REGION}.run.app https://math-wizard-${PROJ_NO}.${REGION}.run.app/mcp add,subtract
כדי לראות שהשירות רושם את ההגדרות המדויקות של הכלים, את סכימות הקלט ואת הערות ההתנהגות של כל כלי, אפשר לעיין במפרט ההגדרה של השירות:
# describe mcp server tool specs
gcloud agent-registry services describe ${MCP_NAME} \
--location=${REGION} \
--project=${PROJ_ID} \
--format="yaml(mcpServerSpec.content.tools)"
כאן מסתיים החלק שקשור לשרת ה-MCP… ועכשיו נעבור לקטע Gemini Enterprise.
7. Gemini Enterprise
בקטע הזה תיצרו ותגדירו אפליקציית Gemini Enterprise ומשאב מקושר של מאגר נתונים מותאם אישית של שרת MCP.
מודל המשאבים של Discovery Engine
אפליקציית Gemini Enterprise (שמיוצגת כמשאב Engine ב-Discovery Engine API) היא שכבת התיאום המרכזית וממשק השיחה למשתמשי קצה. הוא מנהל סשנים של צ'אטים עם משתמשים, מבסס מודלים גנרטיביים על נתונים ארגוניים ומתאם בין הפעלות דינמיות של כלים.
אפליקציות Gemini Enterprise מקיימות אינטראקציה עם נתונים ומערכות באמצעות מאגרי נתונים:
- מאגרי נתונים של ידע: הטמעה ואינדוקס של תוכן סטטי (למשל, Cloud Storage, Google Drive, BigQuery) לצורך יצירה משופרת באחזור (RAG).
- מחברי נתונים (ספקי פעולות): מתחברים לממשקי API דינמיים של צד שלישי או לממשקי API בהתאמה אישית. מאגר נתונים של שרת MCP מותאם אישית חושף כלים שמוגדרים על ידי Model Context Protocol (MCP), ומאפשר למודל להפעיל באופן דינמי פונקציות חיצוניות במהלך שיחה.
ניתוב יוצא דרך Agent Gateway
כברירת מחדל, Gemini Enterprise מנתב את התעבורה של מחברים וכלים ברשתות ציבוריות. עם זאת, כדי לנהל עומסי עבודה פרטיים ב-VPC וליישם מדיניות של אפס אמון, אפשר להגדיר את המנוע כך שינתב תעבורת נתונים יוצאת דרך Agent Gateway:
- כשיוצרים את מאגר הנתונים של שרת ה-MCP המותאם אישית בהמשך המעבדה הזו, מפעילים את האפשרות ניתוב יציאה דרך Agent Gateway בהגדרות של מאגר הנתונים.
- הפעולה הזו מקשרת את הקריאות לכלים היוצאות של המנוע ל-Agent Gateway האזורי שלכם, כדי לוודא שכל בקשות ה-MCP נושאות את
Agent Identityשל האפליקציה, עוברות הרשאה בזמן הריצה באמצעות IAP ומדיניות גישה מאוחדת (UAP) של IAM, ועוברות דרך קובץ ה-PSC המצורף אל ה-VPC הפרטי שלכם.
יצירת אפליקציית Gemini Enterprise
השיטה הבאה משתמשת ב-API discoveryengine.googleapis.com כדי ליצור את המשאבים וההגדרות של אפליקציית Gemini Enterprise. הוראות להגדרה באמצעות ממשק המשתמש של מסוף 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}"
}
}
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}"
שימו לב למאפיינים הבאים שמאוכלסים על ידי השרת בתגובת ה-JSON:
-
name: נתיב משאב קנוני (projects/${PROJ_NO}/locations/global/collections/default_collection/engines/${GE_APP_ID}). -
sessionConfig.sessionManagementPolicy: ברירת המחדל היא"VERTEX_AI_MANAGED", ששומרת את מצב השיחה עם זיכרון ואת מצב ההפעלה של הכלי ב-Agent Platform (לשעבר Vertex AI). -
observabilityConfig.observabilityEnabled: ברירת המחדל היאtrueלמדדי בסיס (רישום מפורט של הנחיות ומטען ייעודי (payload) של כלי מופעל בשלב מאוחר יותר).
הפעלת ספק הזהויות
מפעילים את Google Identity כספק הזהויות לאימות משתמשי קצה באפליקציית Gemini Enterprise.
בשיטה הבאה משתמשים ב-discoveryengine.googleapis.com API כדי להגדיר את ספק הזהויות של אפליקציית Gemini Enterprise. הוראות להגדרה באמצעות ממשק המשתמש של מסוף 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.
(אופציונלי) הפעלת רישיון ניסיון ל-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 מאפשרת לכם לראות את האינטראקציות של העוזר הראשי עם נתוני מדדים ב-Metrics Explorer, ולקשר בין עקבות מקצה לקצה ב-Cloud Trace.
# set observability on engine (ge app)
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=observabilityConfig" \
-H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
-H "X-Goog-User-Project: ${PROJ_ID}" -H "Content-Type: application/json" \
-d @- <<EOF
{
"observabilityConfig": {
"observabilityEnabled": true,
"sensitiveLoggingEnabled": true
}
}
EOF
אימות הגדרות יכולת הצפייה
# verify observability is enabled on engine (ge app)
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 '{observabilityConfig: .observabilityConfig}'
בודקים אם יש "sensitiveLoggingEnabled": true.
איגוד אל Agent Gateway
ניתוב תנועה יוצאת מ-Gemini Enterprise דרך Agent Gateway יוצר גבול מרכזי של ניהול אפס-אמון ואכיפת אבטחה לכל ההפעלות של כלי סוכני AI:
- אכיפת מדיניות מרכזית: Agent Gateway פועל כפרוקסי מוטבע שבודק בקשות לכלים יוצאים מול מדיניות הרשאות ובקרות ניהול לפני שהתנועה יוצאת מסביבת הסוכן.
- תעבורת נתונים יוצאת (egress) ברשת פרטית: קישור Gemini Enterprise ל-Agent Gateway מבטיח שקריאות לכלים שמיועדות לשרתי MCP פרטיים ב-Cloud Run ינותבו בצורה מאובטחת דרך Private Service Connect (PSC), בלי לעבור דרך האינטרנט הציבורי.
- יכולת ביקורת מאוחדת: מספקת רישום מרכזי של בקשות, טלמטריה ועקבות ביקורת בכל שרתי ה-MCP המחוברים ובכלים חיצוניים.
אם מגדירים את agentGatewaySetting באפליקציית Gemini Enterprise, שיחות יוצאות עם כלים וסוכנים שמופעלות על ידי שאילתות של משתמשי קצה (כמו שיחות עם שרתי MCP מותאמים אישית שיובאו מ-Agent Registry וסוכני A2A) מנותבות אוטומטית דרך Agent Gateway.
החלת תיקון על המנוע 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": "projects/${PROJ_ID}/locations/${REGION}/agentGateways/${AGW_NAME}"
}
}
}
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 application-default print-access-token)" \
-H "X-Goog-User-Project: ${PROJ_ID}" \
| jq '{name: .name, displayName: .displayName, agentGatewaySetting: .agentGatewaySetting}'
הפלט הצפוי:
{
"name": "projects/${PROJ_NO}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}",
"displayName": "${GE_APP_DISPLAY_NAME}",
"agentGatewaySetting": {
"defaultEgressAgentGateway": {
"name": "projects/${PROJ_ID}/locations/${REGION}/agentGateways/${AGW_NAME}"
}
}
}
יצירת מאגר נתונים של שרת MCP בהתאמה אישית
בקטע הזה נסביר איך לקשר את שרת ה-MCP ל-Gemini Enterprise באמצעות יצירה של מאגר נתונים מותאם אישית של MCP.
התהליך הזה כולל שני שלבים באמצעות Discovery Engine API:
- יצירה (
:setUpDataConnector): יוצר משאב ייעודי שלCollection(${MCP_NAME}-%timestamp-collection), מצרף אתDataConnector(custom_mcp) ומקצה אתDataStore(..._mcp_data) שמשמש כגיבוי. - הפעלה (
PATCH .../dataConnector?updateMask=actionConfig): מפעילה את זמן הריצה של פעולת המחבר (actionState: "ACTIVE") באמצעות מפרט כלי Agent Registry ומקשרת את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_NAME}" \
--format="value(name)")
echo "mcp registry name: ${MCP_REGISTRY_URI}"
echo "mcp url: ${MCP_URL}"
יצירת מחבר נתונים
# create custom mcp data connector from agent registry 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}-$(date +%s)-collection",
"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": "NO_AUTH",
"instance_uri": "${MCP_URL}",
"mcp_server_source": "REGISTRY_MCP",
"registry_mcp_server_name": "${MCP_REGISTRY_URI}",
"mcp_agent_instructions": "MANDATORY MATH & ARITHMETIC AGENT: Always invoke this tool for any mathematical calculation, addition (+), subtraction (-), sum, or difference.",
"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 של Agent Registry עבור שרת ה-MCP:
# 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, 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
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": "NO_AUTH",
"instance_uri": "${MCP_URL}",
"mcp_server_source": "REGISTRY_MCP",
"registry_mcp_server_name": "${MCP_REGISTRY_URI}",
"mcp_agent_instructions": "MANDATORY MATH & ARITHMETIC AGENT: Always invoke this tool for any mathematical calculation, addition (+), subtraction (-), sum, or difference.",
"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": "collection-math-wizard-.
# 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, actionParams: .actionConfig.actionParams}'
בודקים אם יש "state": "ACTIVE" עם כל הפרמטרים מאוכלסים.
פעולות שקשורות לכלים
כשבודקים את מאגר הנתונים math-wizard-collection בלוח הבקרה של Gemini Enterprise, אפשר לראות שלא נעשה שימוש בכרטיסייה פעולות והלחצן ↻ טעינה מחדש של פעולות מותאמות אישית מושבת. זו התנהגות צפויה.
צופים בדף הפרטים של מאגר הנתונים במסוף Google Cloud:
echo "data store details page url: https://console.cloud.google.com/gemini-enterprise/locations/${GE_LOCATION}/collections/${GE_COLLECTION_ID}/connector/details?project=${PROJ_ID}"
בהתאם לאופן שבו מקשרים שרת 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… עכשיו נעבור לקטע אימות.
8. אימות
בקטע הזה תפעילו קריאות בזמן אמת לכלים של MCP מאפליקציית האינטרנט של Gemini Enterprise ותעקבו אחרי זרימת הבקשה דרך Agent Gateway, Cloud DNS, חומת האש של VPC ויומני Cloud Run. לאחר מכן, תהדקו את מדיניות הגישה המאוחדת של IAM כדי לאפשר subtract ולחסום add, ותאמתו את האכיפה של מודל האבטחה אפס אמון בשער.
גישת משתמש
יוצרים את כתובת ה-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 application-default 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}"
לוחצים על הקישור כדי לפתוח את ממשק הצ'אט של Gemini Enterprise בדפדפן, ואז לוחצים על Get started (התחלת העבודה).
בדיקת שאילתות של סוכנים בצ'אט
בממשק המשתמש של הצ'אט, לוחצים על סמל חלקי הפאזל של מחברים בתחתית תיבת הצ'אט כדי לוודא שmath-wizard-collection מחבר הנתונים מופעל. אמור להופיע לחצן הפעלה/השבתה (צבעוני).
כדאי לנסות את שאילתות הבדיקה הבאות:
what is 2342345 - 98234798324?
what is 72347234 + 234234?
מוודאים שהתשובות של העוזר הדיגיטלי נכונות ושהוא מציג תג אינטראקטיבי של ציטוט פעולה (כמו Math Calculation (8s) 🤖 Agentgateway Agent) מתחת לכל תשובה, כדי לאשר שהכלי הופעל.
עיון ביומנים ב-Cloud Logging
בודקים את היומנים ב-Cloud Logging כדי לוודא ש-Gemini Enterprise העביר את הקריאות לכלים דרך Agent Gateway ורשת ה-VPC הפרטית.
1. אימות ההרשאה של Agent Gateway ו-IAP
מוודאים ש-Agent Gateway יירט את הבקשה, פתר את היעד ב-Agent Registry, העביר את ההרשאה ל-IAP והתיר את הקריאה לכלי:
# show agent gateway logs
gcloud logging read 'resource.type="networkservices.googleapis.com/Gateway"' \
--project=${PROJ_ID} \
--limit=5 \
--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
)"
מוודאים שהפלט מכיל:
-
STATUS:200(ביצוע מוצלח) ו-202(לחיצת יד שלnotifications/initialized). -
SERVER_IP: כתובת ה-IP של נקודת הקצה של Google APIs PSC (172.16.20.20:443). -
MCP_METHODו-TOOL: הרצף של פרוטוקול ה-MCP (notifications/initialized,tools/listו-tools/callעםaddאוsubtract). -
AUTHZ:ALLOWED(יציאה מורשית של IAP). REGISTRY_MCP: מזהה המשאב של Agent Registry (agentregistry-...).
2. אימות של מעבר DNS וחומת אש
מוודאים ש-Cloud DNS פתר את שם המארח לנקודת הקצה של PSC ושהתנועה מממשק Agent Gateway אושרה על ידי חומת האש:
# show dns logs
gcloud logging read 'resource.type="dns_query"' \
--project=${PROJ_ID} \
--limit=5 \
--format="table( \
timestamp.date(tz=LOCAL):label=TIMESTAMP, \
jsonPayload.queryName:label=QUERY_NAME, \
jsonPayload.queryType:label=TYPE, \
jsonPayload.responseCode:label=RCODE, \
jsonPayload.rdata:label=RDATA
)"
# show firewall logs
gcloud logging read 'logName:"compute.googleapis.com%2Ffirewall"' \
--project=${PROJ_ID} \
--limit=5 \
--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.rule_details.reference.basename():label=RULE, \
jsonPayload.disposition:label=DISPOSITION
)"
בודקים את הערכים הבאים:
- DNS
QUERY_NAME&RDATA: פותר אתmath-wizard-...run.app.(רשומתA, NOERROR) ל-172.16.20.20. - חומת אש
SRC_IPו-DEST_IP:192.168.10.2(כתובת ה-IP של ממשק ה-PSC של Agent Gateway) אל172.16.20.20:443. - Firewall
RULE&DISPOSITION: התאמה שלfirewallPolicy:fw-policy-...ל-ALLOWED.
3. אימות ההפעלה של כלי Cloud Run
מוודאים שהקונטיינר של Cloud Run קיבל את הקריאה לכלי ועיבד אותה:
# show cloud run logs
gcloud logging read 'resource.type="cloud_run_revision"
AND textPayload:"Tool:"' \
--project=${PROJ_ID} \
--limit=5 \
--format="value(timestamp.date(tz=LOCAL), textPayload)"
מוודאים שמוצגים ב-textPayload רשומות של הרצת כלי (לדוגמה, >>> 🛠️ Tool: 'subtract' called with numbers '[x]' and '[y]').
בדיקת אכיפת מדיניות של הרשאות מינימליות
במדיניות הגישה הראשונית ב-IAM, כל שיטה או כלי היו מורשים כל עוד היעד היה רשום (destination.is_registered == true). בשלב הזה, מעדכנים את המדיניות כדי לאכוף את עיקרון ההרשאה המינימלית, כך שרק הכלי subtract יהיה מורשה והכלי add ייחסם.
עדכון מדיניות הגישה ב-IAM
כשמגבילים את ההרצה של הכלי MCP, משתמשים בתבנית של שני כללים:
- כלל 1 (גילוי MCP ושידור נתונים): מאפשר שימוש בשיטות מחזור החיים של MCP שלא קשורות להפעלת כלים (
destination.is_registered == trueו-destination.agent_registry.mcp_server.method != 'tools/call'). מכיוון ש-Gemini Enterprise מנהל משא ומתן על הגדרת הזרם וגילוי (initialize, notifications/initialized, tools/list) לפני הפעלת כלי – ו-destination.agent_registry.mcp_server.tool.nameמאוכלס רק במהלךtools/call– כלל 1 נחוץ כדי לשמור על תהליך תחילת ההפעלה של הסשן וגילוי הקטלוג. - כלל 2 (הגבלה ברמת הכלי): מגביל את ההפעלה של
tools/callכך שרק הכליsubtractמורשה (destination.is_registered == true,destination.agent_registry.mcp_server.method == 'tools/call'ו-destination.agent_registry.mcp_server.tool.name == 'subtract').
מעדכנים את קובץ המניפסט של כלל מדיניות הגישה עם שני הכללים:
# create access policy rule file (update: allow subtract only)
cat > cfg/${UAP_POLICY_NAME}-rule-update.json << EOF
[
{
"description": "allow ge assistant to any registered endpoint to perform mcp discovery and handshake",
"effect": "ALLOW",
"principals": [
"principal://${TRUST_DOMAIN}/resources/discoveryengine/projects/${PROJ_NO}/locations/global/engines/${GE_APP_ID}/assistants/default_assistant/agents/default/core_assistant"
],
"operation": {
"permissions": [
"iap.googleapis.com/resources.egressViaIAP"
]
},
"conditions": {
"iap.googleapis.com": {
"expression": \
"destination.is_registered == true && \
destination.agent_registry.mcp_server.method != 'tools/call'"
}
}
},
{
"description": "allow ge assistant to any registered mcp server with tool call subtract",
"effect": "ALLOW",
"principals": [
"principal://${TRUST_DOMAIN}/resources/discoveryengine/projects/${PROJ_NO}/locations/global/engines/${GE_APP_ID}/assistants/default_assistant/agents/default/core_assistant"
],
"operation": {
"permissions": [
"iap.googleapis.com/resources.egressViaIAP"
]
},
"conditions": {
"iap.googleapis.com": {
"expression": \
"destination.is_registered == true && \
destination.agent_registry.mcp_server.method == 'tools/call' && \
destination.agent_registry.mcp_server.tool.name == 'subtract'"
}
}
}
]
EOF
מחילים את הכללים המעודכנים על מדיניות הגישה של IAM:
# update iam access policy
gcloud iam access-policies update ${UAP_POLICY_NAME} \
--details-rules=cfg/${UAP_POLICY_NAME}-rule-update.json \
--project=${PROJ_ID} \
--location=global
אימות מדיניות הגישה ב-IAM
בודקים שמדיניות הגישה החדשה ב-IAM הוחלה ורק כלי ההפחתה מורשה:
# show iam access policy details
gcloud iam access-policies describe ${UAP_POLICY_NAME} \
--project=${PROJ_ID} \
--location=global \
--flatten="details.rules[]" \
--format="table( \
details.rules.principals[0].scope(engines).sub('assistants/default_assistant/agents/default', '...'):label=PRINCIPAL, \
details.rules.effect:label=EFFECT, \
details.rules.conditions.'iap.googleapis.com'.expression.sub('\s*&&\s*', '\n&& ').sub('\s*\|\|\s*', '\n|| '):label=EXPRESSION
)"
בדיקת קריאה אסורה לכלי
חוזרים לממשק המשתמש של הצ'אט ב-Gemini Enterprise בדפדפן ומנסים שאילתת בדיקה אחרת:
what is 100 plus 20?
העוזר הדיגיטלי מנסה להפעיל את add, אבל Agent Gateway ו-IAP מעריכים את תנאי מדיניות IAM כ-false ודוחים את בקשת היציאה עם HTTP 403 Forbidden. בממשק המשתמש של הצ'אט, תראו את הסמל של העוזר הדיגיטלי Calculate Sum מסתובב ב-🤖 Agentgateway Agent ... Working on it. בזמן שהוא מנסה שוב לבצע את הקריאה החסומה לכלי. זו התנהגות צפויה. האישור הזה מעיד על כך ש-Agent Gateway ו-IAP מיירטים באופן פעיל את ההרצה של כלים שלא אושרו ומונעים אותה ברמת הרשת.
בדיקה מחדש של יומנים ב-Cloud Logging
אפשר לראות את הרשומות ביומן של Agent Gateway ולשים לב לרשומות החדשות 403 שמתאימות לקריאה לכלי add שלא הותר:
# show agent gateway logs
gcloud logging read 'resource.type="networkservices.googleapis.com/Gateway"' \
--project=${PROJ_ID} \
--limit=5 \
--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 403 tools/call add DENIED agentregistry-00000000-0000-0000-0012-3456789abcde
YYYY-MM-DDTHH:MM:SS 403
YYYY-MM-DDTHH:MM:SS 202 172.16.20.20:443 notifications/initialized ALLOWED agentregistry-00000000-0000-0000-0012-3456789abcde
YYYY-MM-DDTHH:MM:SS 172.16.20.20:443 ALLOWED agentregistry-00000000-0000-0000-0012-3456789abcde
YYYY-MM-DDTHH:MM:SS 200 172.16.20.20:443 initialize ALLOWED agentregistry-00000000-0000-0000-0012-3456789abcde
בודקים שהבקשה הנוספת לא הגיעה לעורף של Cloud Run:
# show cloud run logs
gcloud logging read 'resource.type="cloud_run_revision"
AND textPayload:"Tool:"' \
--project=${PROJ_ID} \
--limit=5 \
--format="value(timestamp.date(tz=LOCAL), textPayload)"
הפקודה לא מחזירה רשומות חדשות, מה שמאשר ש-Agent Gateway אכף בהצלחה את מדיניות הגישה של IAM.
כאן מסתיים חלק האימות… עכשיו עוברים לקטע ניקוי.
9. הסרת המשאבים
כדי למחוק את המשאבים וההגדרות שנוצרו בשיעור ה-Lab הזה, פועלים לפי השלבים הבאים.
הסרת רכיבים של 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"}}'
הסרת רכיבי שרת ה-MCP
# delete agent registry service
gcloud -q agent-registry services delete ${MCP_NAME} \
--location=${REGION} \
--project=${PROJ_ID}
# delete cloud run service, source-deploy artifact registry repo, and staging bucket
gcloud -q run services delete ${MCP_NAME} \
--region=${REGION} \
--project=${PROJ_ID}
gcloud -q artifacts repositories delete cloud-run-source-deploy \
--location=${REGION} \
--project=${PROJ_ID}
gcloud -q storage rm --recursive gs://run-sources-${PROJ_ID}-${REGION} \
--project=${PROJ_ID}
הסרת Agent Gateway ומדיניות הגישה של IAM
# delete gateway authorization policy, iap extension, and agent gateway
gcloud -q network-security authz-policies delete ${AGW_NAME}-authz-policy-iap \
--location=${REGION} \
--project=${PROJ_ID}
gcloud -q service-extensions authz-extensions delete ${AGW_NAME}-svc-ext-authz-iap \
--location=${REGION} \
--project=${PROJ_ID}
gcloud -q network-services agent-gateways delete ${AGW_NAME} \
--location=${REGION} \
--project=${PROJ_ID}
# delete iam policy binding and access policy
gcloud -q iam policy-bindings delete ${UAP_BINDING_NAME} \
--location=global \
--project=${PROJ_ID}
gcloud -q iam access-policies delete ${UAP_POLICY_NAME} \
--location=global \
--project=${PROJ_ID}
הסרת רכיבי DNS וחומת אש
# delete dns record set, managed zone, and policy
gcloud -q dns record-sets delete "*.run.app." \
--type=A \
--zone=priv-zone-run \
--project=${PROJ_ID}
gcloud -q dns managed-zones delete priv-zone-run \
--project=${PROJ_ID}
gcloud -q dns policies update dns-policy-${SLUG} \
--networks="" \
--project=${PROJ_ID}
gcloud -q dns policies delete dns-policy-${SLUG} \
--project=${PROJ_ID}
# delete firewall policy association, rule, and policy
gcloud -q compute network-firewall-policies associations delete \
--name=fw-policy-bind-${SLUG} \
--firewall-policy=fw-policy-${SLUG} \
--global-firewall-policy \
--project=${PROJ_ID}
gcloud -q compute network-firewall-policies rules delete 1001 \
--firewall-policy=fw-policy-${SLUG} \
--global-firewall-policy \
--project=${PROJ_ID}
gcloud -q compute network-firewall-policies delete fw-policy-${SLUG} \
--global \
--project=${PROJ_ID}
הסרת רכיבי PSC ורשת VPC
# delete psc forwarding rule and internal ip address
gcloud -q compute forwarding-rules delete psc2gapis \
--global \
--project=${PROJ_ID}
gcloud -q compute addresses delete ip-psc2gapis \
--global \
--project=${PROJ_ID}
# delete psc network attachment, subnet, and vpc network
gcloud -q compute network-attachments delete psc-na-${REGION}-agw \
--region=${REGION} \
--project=${PROJ_ID}
gcloud -q compute networks subnets delete subnet-${REGION}-agw \
--region=${REGION} \
--project=${PROJ_ID}
gcloud -q compute networks delete vnet-${SLUG} \
--project=${PROJ_ID}
הסרת ביטולים של מדיניות הארגון וקבצים מקומיים
# delete project-level organization policy overrides
gcloud -q org-policies delete discoveryengine.managed.disableCustomMcpServerConnector --project=${PROJ_ID}
gcloud -q org-policies delete iam.managed.disableAccessPolicyBinding --project=${PROJ_ID}
# remove local project files
rm -rf cfg math-wizard
סיימנו את עבודת ניקוי הנתונים... עכשיו נעבור אל המסקנה!
10. סיכום
מעולה! יצרתם ארכיטקטורה מקצה לקצה שמאפשרת לאפליקציית Gemini Enterprise לגלות ולהפעיל כלים בצורה מאובטחת בשרת MCP פרטי בהתאמה אישית:
- שרת MCP בהתאמה אישית ו-Agent Registry: פרסנו שירות FastMCP פרטי ב-Cloud Run (
--ingress=internal) ורשמנו את נקודת הקצה ואת סכימת הכלים שלו (addו-subtract) ב-Agent Registry. - שילוב של Gemini Enterprise: הוקצתה אפליקציית Gemini Enterprise, תנועת הנתונים היוצאת של הכלי קושרה ל-Agent Gateway, ושרת ה-MCP הרשום צורף כ-
REGISTRY_MCPמחבר נתונים. - תעבורת נתונים יוצאת (egress) פרטית של VPC וניהול לפי עקרון אפס אמון: הפעלת כלי עם ניתוב פרטי דרך PSC (
172.16.20.20) ואכיפה של הרשאות מינימליות ברמת הכלי באמצעות IAP ומדיניות מאוחדת של הרשאות גישה (destination.agent_registry.*).

Cosmpup חושב ש-Codelabs הם הכי טובים שיש!
מה השלב הבא?
- במסמכי Gemini Enterprise Agent Platform אפשר למצוא מידע על תכונות מתקדמות והדרכות.
- כדי לשפר את הבטיחות והאבטחה של ה-AI, אפשר להגדיר גדרות בטיחות של הגנה מוגברת על המודל ב-Agent Gateway.
- כדי לאכוף כללים עסקיים ותאימות לשאילתות בשפה טבעית, אפשר לעיין במדיניות בנושא ניהול סמנטי.
אתם מוזמנים לשלוח הערות, שאלות או תיקונים באמצעות טופס המשוב הזה.
תודה!