ניהול מרכזי של Agent Gateway עם Agent Registry חוצה פרויקטים עבור Agent Runtime

1. מבוא

ככל שארגונים מאמצים את ה-AI הגנרטיבי, הארכיטקטורות מתפתחות במהירות מצ'אטבוטים מונוליתיים עצמאיים למערכות מרובות סוכנים מבוזרות (סוכן לסוכן / A2A). בטופולוגיות המודרניות האלה, סוכני תזמור ברמה גבוהה מתאמים תהליכי עבודה עסקיים מורכבים על ידי הקצאת משימות לסוכני עבודה ייעודיים בתחום, לשרתי כלים של Model Context Protocol‏ (MCP) ולמסדי נתונים ארגוניים לקצה העורפי בפרויקטים בענן עצמאיים של Google.

עם זאת, הפעלת מערכות מרובות סוכנים בקנה מידה נרחב מציבה אתגרים משמעותיים בתחום האבטחה, הפיקוח והתפעול:

  • סוכנים לא מורשים וריבוי כלים: כשצוותי פיתוח פורסים סוכנים בפרויקטים מבודדים בלי קטלוג מרכזי, הארגונים מאבדים את היכולת לראות אילו כלים וסוכני משנה קיימים.
  • תעבורת נתונים יוצאת בין פרויקטים ללא מעקב: אם מאפשרים לסוכנים גישה ישירה לנתיבי רשת ללא בדיקה, זה יוצר סיכונים לזליגת נתונים ועוקף את גבולות האבטחה.
  • שילובים שבריריים בתוך הקוד: הטמעה של כתובות URL של סוכנים ומזהים של מנועי חשיבה רציונלית בתוך הקוד יוצרת תלויות שבריריות שעלולות להשתבש במהלך שדרוגים או פריסות מחדש.
  • חוסר בזהות עם הרשאות מינימליות: חשבונות שירות משותפים לא מספקים מניעת הכחשה קריפטוגרפית ברמת המכונה של הסוכן הספציפי.

כדי לפתור את האתגרים האלה, Gemini Enterprise Agent Platform מספקת מישור בקרה מאוחד לניהול משילות מידע וקישוריות, שמורכב מ-4 עמודי תווך:

  1. ‫Agent Gateway (networkservices.googleapis.com): שרת proxy מנוהל לאכיפת מדיניות ורשתות אזוריות. הוא פועל במצב תעבורת נתונים יוצאת (egress) של AGENT_TO_ANYWHERE, מיירט תעבורת נתונים יוצאת של סוכנים, מאציל הערכות הרשאה לתוספי אבטחה ומנתב בקשות בין גבולות הפרויקט.
  2. ‫Agent Registry (agentregistry.googleapis.com): קטלוג השירותים היחיד של הארגון. הוא מספק ספרייה מרכזית ומאומתת של כל הכלים הזמינים, שרתי ה-MCP והסוכנים המקבילים בארגון, ומאפשר גילוי אוטומטי דינמי בזמן ריצה בלי נקודות קצה (endpoints) בתוך הקוד.
  3. ‫Agent Identity ו-IAP v2 Governance (iap.googleapis.com ו-iam.googleapis.com): מסגרת קריפטוגרפית לניהול זהויות והרשאות גישה. סוכני ההפעלה מקבלים מזהי URN ייחודיים ומאומתים של מכונות SPIFFE‏ (principal://...). תעבורת הנתונים היוצאת נבדקת מול מדיניות הגישה המאוחדת (UAP / IAP v2) של IAM, שמאמתת את ההרשאה האוניברסלית iap.googleapis.com/resources.egressViaIAP באמצעות תנאי קטלוג עשירים של Common Expression Language‏ (CEL) ‏ (destination.agent_registry.*).
  4. ‫Agent Runtime (מנועי חשיבה רציונלית): פלטפורמה מנוהלת לחלוטין, ללא שרת (serverless), להרצת אפליקציות מבוססות-סוכנים ב-Python, עם קישורי הגדרות מקוריים (agent_gateway_config) לשערים מרכזיים.

תרחיש עסקי ב-Codelab: רכישת מזון ומשקאות בכמה פרויקטים

ב-Codelab הזה תבנו ותנהלו סביבה עסקית של רכישות בעולם האמיתי, שכוללת כמה פרויקטים ומתפרסת על פני שלושה פרויקטים נפרדים ב-Google Cloud:

  • פרויקט ניהול מרכזי (PROJECT_GOVERNANCE): בבעלות של צוות ה-IT המרכזי ו-SecOps, ומארח את Agent Gateway המרכזי, את Agent Registry המרכזי ואת מערכת גישה מאוחדת לכללי מדיניות (UAP) של IAM.
  • פרויקט Consumer Orchestrator‏ (PROJECT_CONCIERGE): בבעלות צוות הרכש, מארח את סוכן הרכישה שמגלה ספקים באופן דינמי ומנתב הזמנות של לקוחות.
  • פרויקט של ספק דומיין (PROJECT_SELLERS): בבעלות של ספקים חיצוניים או מחלקתיים, שמארח את סוכן מכירת ההמבורגרים ואת סוכן מכירת הפיצות.

figure1

איור 1. ארכיטקטורת פיקוח מרכזית על כמה פרויקטים

למה כדאי להשתמש בניהול מרכזי של פרויקטים שונים?

בארגונים גדולים, צוותי מוצר וקבוצות של מדעני נתונים יוצרים סוכני AI בעשרות פרויקטים בענן עצמאיים ב-Google Cloud. אם נותנים לכל צוות שליטה ישירה על רישום הכלים, נתיבי הרשת של תעבורת הנתונים היוצאת (egress) ומעקות הבטיחות, זה יוצר ריבוי כלים לא מבוקרים, מדיניות DLP לא עקבית, תעבורת נתונים יוצאת לא מנוטרת ב-VPC ויומני ביקורת מפוצלים.

ניהול מרכזי של פרויקטים שונים מפריד בין יצירת המדיניות לבין הפעלת הנציגים:

  • צוותי ה-IT וה-SecOps המרכזיים יוצרים מדיניות אבטחה, בודקים כלים ועוקבים אחרי תעבורת הנתונים היוצאת בפרויקט ניהול מרכזי אחד.
  • צוותי המוצרים והאפליקציות מתמקדים רק בלוגיקה העסקית בפרויקטים העצמאיים של Agent Runtime, ומתחברים ישירות לשער המרכזי בלי התקורה התפעולית של ניהול רשתות VPC מקומיות, חיבורים או מנועי מדיניות מפוצלים.

figure2

איור 2. ארכיטקטורה וגבולות של ניהול פרויקטים בשלוש רמות

מודל היקף זהויות דו-שלבי במערכת גישה מאוחדת לכללי מדיניות (UAP)

כשנציגים מתקשרים דרך Central Agent Gateway, שירות Identity-Aware Proxy‏ (IAP v2) מעריך את הגישה על סמך זהות הנציג של המתקשר – זהות מאומתת באופן קריפטוגרפי, מבוססת-SPIFFE, שמונפקת באופן אוטומטי למאגר של זמן הריצה – בהשוואה למדיניות גישה גלובלית של IAM:

  • ‫רמה 1: ממשקי Google Cloud API בסיסיים (ברזולוציה גסה באמצעות principalSet:// בכלל 1): הרשאת תעבורת נתונים יוצאת ברמת הפרויקט שמאפשרת לכל סביבות זמן הריצה של הסוכנים בפרויקטים מסוג Spoke להגיע לממשקי Google API רגילים (aiplatform,‏ iamcredentials,‏ telemetry,‏ agentregistry) לצורך גילוי, יצירת טוקנים והסקת מסקנות.
  • רמה 2: כלים עסקיים ושירותי A2A (גישה פרטנית באמצעות principal:// בכללים 2 ו-3): גישה מחמירה לפי העיקרון של הרשאות מינימליות, שמוגבלת למכונות ספציפיות של מנוע החשיבה הרציונלית. הגישה נאכפת באמצעות תנאים של Common Expression Language ‏ (CEL) שמטרגטים שירותים ספציפיים שרשומים במרשם הסוכנים (destination.agent_registry.agent.name).

מה אתם מפתחים

  • ‫Agent Gateway מרכזי (centralized-agw) ב-PROJECT_GOVERNANCE
  • תוסף שירות ההרשאות של IAP v2 ומדיניות Authz במצב אכיפה מחמיר (failOpen: false)
  • מדיניות גישה מאוחדת בסיסית של IAM‏ (uap-rules.json) וקישור מדיניות של פרויקט
  • הרשאות IAM של סוכן שירות בפרויקטים שונים (ar_agw_cross_project_sa)
  • קטגוריית Google Cloud Storage‏ (GCS) מרכזית משותפת להכנת נתונים
  • סוכני מכירות מבודדים של המבורגרים ופיצות בPROJECT_SELLERS
  • סוכן רכישה עם גילוי אוטומטי דינמי של REST ב-PROJECT_CONCIERGE
  • רישומי שירותים ב-Central Agent Registry עם כתובות URL של mTLS בפרויקטים שונים
  • עדכונים דינמיים של מדיניות תעבורת הנתונים היוצאת (egress) ב-IAP גרסה 2, עם אימות בזמן אמת וביקורות ב-Cloud Logging

figure3

איור 3. רצף הטמעה מפורט

מה לומדים

  • איך מגדירים הרשאות IAM לסוכני שירות בפרויקטים שונים בשביל שערים מרכזיים
  • איך להעביר תעבורת נתונים יוצאת (egress) של Agent Runtime דרך Agent Gateway מרכזי בסביבות עם כמה פרויקטים
  • איך להקצות הרשאה ל-Agent Gateway לשרת proxy לאימות זהויות (IAP v2) באמצעות Service Extensions‏ (iapPolicyVersion: "V2")
  • איך יוצרים ומשייכים כללי מדיניות גישה מאוחדת (UAP) של IAM עם כללים של Common Expression Language ‏ (CEL) שמנהלים את היעדים הרשומים של Agent Registry (destination.agent_registry.*)
  • איך להסיר מזהי סוכנים וכתובות URL בתוך הקוד באמצעות גילוי אוטומטי בזמן ריצה מול Agent Registry
  • איך בודקים חסימה אמיתית של היקף הרשת ב-Zero Trust‏ (HTTP 403 Forbidden) ומאמתים עדכוני מדיניות בזמן אמת ב-Cloud Logging

מה צריך

  • ‫3 פרויקטים ב-Google Cloud שהחיוב מופעל בהם:
    • ‫PROJECT_GOVERNANCE: מדיניות גישה מרכזית לניהול, לשער, למרשם ול-IAM
    • ‫PROJECT_CONCIERGE: סוכן תזמור לרכישת שירותי קונסיירז'
    • ‫PROJECT_SELLERS: סוכני מכירות שמתמחים בהמבורגרים ובפיצות
  • משתמש IAM או חשבון שירות עם הרשאות roles/owner או הרשאות אדמין בכל 3 הפרויקטים
  • ארגון ב-Google Cloud (למיפוי מתחם האמון של SPIFFE)
  • ‫Google Cloud Shell או מכונה מקומית שמותקנים בה gcloud CLI,‏ python (גרסה 3.11 ואילך) ו-uv

זהו סוף החלק של המבוא. עכשיו נעבור לחלק הגדרה וסביבה.

2. הגדרה

למרות שהארכיטקטורה הזו כוללת 3 פרויקטים בענן נפרדים ב-Google Cloud, אתם יכולים להריץ את כל פקודות הפריסה של הטרמינל, הורדות המאגרים ופעולות ה-staging מטרמינל אחד של Cloud Shell שמוגדר ל-PROJECT_GOVERNANCE. כל סקריפט פריסה ופקודת gcloud מטרגטים באופן מפורש את פרויקט היעד המתאים באמצעות דגלי CLI‏ (--project).

קודם כל, נכנסים לשורת הפקודה של הפרויקט בענן ב-Google Cloud:

הגדרת ההקשר של הפרויקט

# set terminal project context to Central Governance Project
gcloud config set project SET_YOUR_GOVERNANCE_PROJECT_ID_HERE
# login to gcloud cli
gcloud auth login
# login for application default credentials
gcloud auth application-default login
# update gcloud components
gcloud components update --quiet

הגדרת משתני סביבה של מעטפת

מזינים את המזהים הספציפיים של הפרויקט.

# 1. Project Identifiers
export PROJECT_GOVERNANCE="SET_YOUR_GOVERNANCE_PROJECT_ID_HERE"
export PROJECT_CONCIERGE="SET_YOUR_CONCIERGE_PROJECT_ID_HERE"
export PROJECT_SELLERS="SET_YOUR_SELLERS_PROJECT_ID_HERE"

משתני המעטפת האלה יופקו באופן אוטומטי.

# 2. Regional & Gateway Settings
export REGION="us-central1"
export AGW_NAME="centralized-agw"
export UAP_POLICY_NAME="uap-policy-${AGW_NAME}"
export UAP_BINDING_NAME="uap-binding-${AGW_NAME}"

# 3. Retrieve Project Numbers
export PROJECT_NUMBER_GOVERNANCE=$(gcloud projects describe ${PROJECT_GOVERNANCE} --format="value(projectNumber)")
export PROJECT_NUMBER_CONCIERGE=$(gcloud projects describe ${PROJECT_CONCIERGE} --format="value(projectNumber)")
export PROJECT_NUMBER_SELLERS=$(gcloud projects describe ${PROJECT_SELLERS} --format="value(projectNumber)")

# 4. Obtain Organization ID
export ORG_ID=$(gcloud projects get-ancestors ${PROJECT_GOVERNANCE} --format="value(id, type)" | grep organization | awk '{print $1}')

# 5. Set Application Default Credentials (ADC) Quota Project
gcloud auth application-default set-quota-project ${PROJECT_GOVERNANCE}

echo "Governance Project: ${PROJECT_GOVERNANCE} (${PROJECT_NUMBER_GOVERNANCE})"
echo "Concierge Project:  ${PROJECT_CONCIERGE} (${PROJECT_NUMBER_CONCIERGE})"
echo "Sellers Project:    ${PROJECT_SELLERS} (${PROJECT_NUMBER_SELLERS})"
echo "Organization ID:    ${ORG_ID}"
echo "UAP Policy Name:    ${UAP_POLICY_NAME}"
echo "UAP Binding Name:   ${UAP_BINDING_NAME}"

יצירת ספרייה מקומית לקובצי תצורה

# create config folder
mkdir -p cfg

הקצאת תפקיד אדמין של מדיניות גישה למערכת גישה מאוחדת לכללי מדיניות (UAP)

# grant Access Policy Admin and Project IAM Admin to current user in Governance Project
for ROLE in "roles/iam.accessPolicyAdmin" "roles/resourcemanager.projectIamAdmin"; do
  gcloud projects add-iam-policy-binding ${PROJECT_GOVERNANCE} \
    --member="user:$(gcloud config get-value account)" \
    --role="${ROLE}" \
    --condition=None
done

הפעלת יומני ביקורת של גישה לנתונים ב-Cloud ל-IAP v2

כברירת מחדל, Google Cloud משבית את יומני הביקורת של הגישה לנתונים כדי למנוע עלויות אחסון לא מכוונות. גרסה 2 של IAP מפיקה החלטות הרשאה (granted=true ו-granted=false) כיומני ביקורת של גישה לנתונים, לכן צריך להפעיל את הרישום ביומן של ADMIN_READ,‏ DATA_READ ו-DATA_WRITE בשביל iap.googleapis.com ב-PROJECT_GOVERNANCE:

# 1. export current IAM policy for PROJECT_GOVERNANCE
gcloud projects get-iam-policy ${PROJECT_GOVERNANCE} \
  --format=json > cfg/gov_iam_policy.json
# 2. append auditConfigs for iap.googleapis.com
python3 -c "
import json
with open('cfg/gov_iam_policy.json') as f:
    policy = json.load(f)
audit_configs = [c for c in policy.get('auditConfigs', []) if c.get('service') != 'iap.googleapis.com']
audit_configs.append({
    'service': 'iap.googleapis.com',
    'auditLogConfigs': [
        {'logType': 'ADMIN_READ'},
        {'logType': 'DATA_READ'},
        {'logType': 'DATA_WRITE'}
    ]
})
policy['auditConfigs'] = audit_configs
with open('cfg/gov_iam_policy.json', 'w') as f:
    json.dump(policy, f, indent=2)
"
# 3. apply updated policy
gcloud projects set-iam-policy ${PROJECT_GOVERNANCE} cfg/gov_iam_policy.json
# 4. verify auditConfigs applied
gcloud projects get-iam-policy ${PROJECT_GOVERNANCE} --format="yaml(auditConfigs)"

הפעלת ממשקי ה-API הנדרשים של Google Cloud

# enable google apis (agent platform & security bundle, part 1)
for PROJ in ${PROJECT_GOVERNANCE} ${PROJECT_CONCIERGE} ${PROJECT_SELLERS}; do
  gcloud services enable \
    agentregistry.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 \
    agentidentity.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 \
    --project=${PROJ}
done
# enable google apis (agent platform bundle, part 2)
for PROJ in ${PROJECT_GOVERNANCE} ${PROJECT_CONCIERGE} ${PROJECT_SELLERS}; do
  gcloud services enable \
    securitycenter.googleapis.com \
    saasservicemgmt.googleapis.com \
    storage.googleapis.com \
    telemetry.googleapis.com \
    texttospeech.googleapis.com \
    --project=${PROJ}
done
# enable google apis (foundational & agent runtime build bundle, part 3)
for PROJ in ${PROJECT_GOVERNANCE} ${PROJECT_CONCIERGE} ${PROJECT_SELLERS}; do
  gcloud services enable \
    artifactregistry.googleapis.com \
    cloudbuild.googleapis.com \
    cloudresourcemanager.googleapis.com \
    iamcredentials.googleapis.com \
    serviceusage.googleapis.com \
    run.googleapis.com \
    orgpolicy.googleapis.com \
    --project=${PROJ}
done

אימות הפעלת ה-API בכל הפרויקטים

כדי לשמור על עקביות תפעולית ולמנוע כשלים בהנפקת אסימונים בזמן ריצה, שגיאות בקטלוג הסכימות או הפסקות בטלמטריה, צריך לוודא שבכל שלושת הפרויקטים (PROJECT_GOVERNANCE,‏ PROJECT_CONCIERGE ו-PROJECT_SELLERS) מופעלים בדיוק אותם ממשקי API.

מריצים את סקריפט האימות הבא ב-Cloud Shell כדי לוודא שוויון בין ממשקי ה-API בכל שלושת הפרויקטים:

# validate that all required APIs are enabled across all 3 projects
python3 - << 'EOF'
import subprocess
import os
import sys

REQUIRED_APIS = [
    "agentregistry.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",
    "agentidentity.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",
    "securitycenter.googleapis.com",
    "saasservicemgmt.googleapis.com",
    "storage.googleapis.com",
    "telemetry.googleapis.com",
    "texttospeech.googleapis.com",
    "artifactregistry.googleapis.com",
    "cloudbuild.googleapis.com",
    "cloudresourcemanager.googleapis.com",
    "iamcredentials.googleapis.com",
    "serviceusage.googleapis.com",
    "run.googleapis.com",
    "orgpolicy.googleapis.com"
]

projects = {
    "GOVERNANCE": os.environ.get("PROJECT_GOVERNANCE", ""),
    "CONCIERGE": os.environ.get("PROJECT_CONCIERGE", ""),
    "SELLERS": os.environ.get("PROJECT_SELLERS", "")
}

enabled = {}
for role, proj in projects.items():
    if not proj:
        print(f"Error: Environment variable for {role} is not set.")
        sys.exit(1)
    res = subprocess.run(
        ["gcloud", "services", "list", "--enabled", f"--project={proj}", "--format=value(config.name)"],
        capture_output=True, text=True, check=True
    )
    enabled[role] = set(res.stdout.strip().splitlines())

print(f"\n{'API Name':<36} | {'GOVERNANCE':<12} | {'CONCIERGE':<12} | {'SELLERS':<12}")
print("-" * 78)

all_synced = True
for api in REQUIRED_APIS:
    g_status = "ENABLED" if api in enabled["GOVERNANCE"] else "MISSING"
    c_status = "ENABLED" if api in enabled["CONCIERGE"] else "MISSING"
    s_status = "ENABLED" if api in enabled["SELLERS"] else "MISSING"
    if "MISSING" in (g_status, c_status, s_status):
        all_synced = False
    print(f"{api:<36} | {g_status:<12} | {c_status:<12} | {s_status:<12}")

print("-" * 78)
if all_synced:
    print("✅ All 29 required APIs are ENABLED and synchronized across all three projects.\n")
else:
    print("❌ Discrepancies detected. Please re-run the enablement commands for missing services.\n")
    sys.exit(1)
EOF

פלט אימות לדוגמה:

כל ממשקי ה-API אמורים להיות מופעלים.

✅ All 30 required APIs are ENABLED and synchronized across all three projects.

הגדרת כללי מדיניות של הארגון

כללי מדיניות ברירת המחדל של הארגון ב-Google Cloud אוכפים אילוצים שמגבילים את הקישורים של מדיניות הגישה של IAM v3 למשאבים (constraints/iam.managed.disableAccessPolicyBinding).

כדי לשנות את כל ההגבלות של מדיניות הארגון שעוברות בירושה ברמת הפרויקט, צריך להגדיר באופן מפורש את enforce: false ל-allow.

# disable iam v3 constraint (allow v3 access policies)
gcloud org-policies set-policy /dev/stdin << EOF
name: projects/${PROJECT_NUMBER_GOVERNANCE}/policies/iam.managed.disableAccessPolicyBinding
spec:
  rules:
  - enforce: false
EOF
# verify org policy constraints on project
gcloud org-policies describe iam.managed.disableAccessPolicyBinding \
  --project=${PROJECT_GOVERNANCE} --effective

בשלב הזה מסתיים חלק ההגדרה… עכשיו עוברים לקטע רישום ממשקי Google API בסיסיים.

‫3. Agent Registry

רישום שירות נקודת הקצה של ממשקי ה-API העיקריים של Google

כדי שסוכנים שמוגדרים עם agent_gateway_config יוכלו לנתב תנועה יוצאת באופן מאובטח לשירותי קצה עורפי מרכזיים של Google Cloud (כמו aiplatform, פרטי כניסה של IAM וטלמטריה), צריך לרשום את כתובות ה-URL של Google API ב-Central Agent Registry.

יצירת core-gapi-services ב-Agent Registry

# register core google api endpoints in agent registry with standard and :443 port variants
gcloud agent-registry services create core-gapi-services \
  --project=${PROJECT_GOVERNANCE} \
  --location=${REGION} \
  --display-name="gapi.core.services" \
  --description="Core Google Cloud APIs and Service Endpoints" \
  --endpoint-spec-type=no-spec \
  --interfaces=protocolBinding=JSONRPC,url=https://telemetry.googleapis.com \
  --interfaces=protocolBinding=JSONRPC,url=https://telemetry.mtls.googleapis.com \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com:443 \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com:443 \
  --interfaces=protocolBinding=JSONRPC,url=https://aiplatform.googleapis.com \
  --interfaces=protocolBinding=JSONRPC,url=https://aiplatform.googleapis.com:443 \
  --interfaces=protocolBinding=JSONRPC,url=https://aiplatform.mtls.googleapis.com \
  --interfaces=protocolBinding=JSONRPC,url=https://aiplatform.mtls.googleapis.com:443 \
  --interfaces=protocolBinding=JSONRPC,url=https://cloudresourcemanager.googleapis.com \
  --interfaces=protocolBinding=JSONRPC,url=https://cloudresourcemanager.googleapis.com:443 \
  --interfaces=protocolBinding=JSONRPC,url=https://cloudresourcemanager.mtls.googleapis.com \
  --interfaces=protocolBinding=JSONRPC,url=https://cloudresourcemanager.mtls.googleapis.com:443 \
  --interfaces=protocolBinding=JSONRPC,url=https://iamcredentials.googleapis.com \
  --interfaces=protocolBinding=JSONRPC,url=https://iamcredentials.googleapis.com:443 \
  --interfaces=protocolBinding=JSONRPC,url=https://iamcredentials.mtls.googleapis.com \
  --interfaces=protocolBinding=JSONRPC,url=https://iamcredentials.mtls.googleapis.com:443 \
  --interfaces=protocolBinding=JSONRPC,url=https://agentregistry.googleapis.com \
  --interfaces=protocolBinding=JSONRPC,url=https://agentregistry.mtls.googleapis.com \
  --interfaces=protocolBinding=JSONRPC,url=https://agentregistry.googleapis.com:443 \
  --interfaces=protocolBinding=JSONRPC,url=https://agentregistry.mtls.googleapis.com:443

מזהה המשאב של נקודת קצה ל-API של Capture Core

# capture the underlying Agent Registry endpoint ID
export ENDPOINT_ID=$(gcloud agent-registry services describe core-gapi-services \
  --project=${PROJECT_GOVERNANCE} \
  --location=${REGION} \
  --format="value(registryResource)" | awk -F'/' '{print $NF}')
echo "Core APIs Endpoint ID: ${ENDPOINT_ID}"

ההבדל בין principalSet ל-principal ב-Agent Identity

ב-Google Cloud IAM וב-Gemini Enterprise Agent Platform, זהויות של מכונות שמונפקות לקונטיינרים של סוכנים שפועלים משתמשות במזהי SPIFFE URN מאומתים באופן קריפטוגרפי שנבדקים על ידי שרת proxy לאימות זהויות (IAP v2). כשמגדירים מערכת גישה מאוחדת לכללי מדיניות (UAP) ב-IAM, אפשר לטרגט principal ספציפי אחד או principalSet שמבוסס על מאפיינים:

מאפיין

principal:// (זהות מכונה יחידה)

‫principalSet:// (קבוצה מבוססת-מאפיינים)

תחביר של IAM

principal://...

principalSet://...

רמת הפירוט

ברמת פירוט גבוהה (ברמת המכונה): מזהה מכונה ספציפית אחת של קונטיינר של מנוע חשיבה רציונלית.

ברמה כללית (רמת הפרויקט): זיהוי כל מנועי החשיבה הרציונלית שחולקים מאפיין פרויקט משותף.

תבנית URN

principal://agents.global.org-${ORG_ID}.system.id.goog/resources/aiplatform/projects/${PROJECT_NUMBER}/locations/${REGION}/reasoningEngines/${ENGINE_ID}

principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJECT_NUMBER}

תרחיש לדוגמה בפלטפורמת הסוכנים

רמה 2 (כלים עסקיים ו-A2A): מתן הרשאה לסוכני תזמור ספציפיים להפעיל כלים של דומיין היעד (למשל, סוכן הרכישה $\rightarrow$ סוכן המכירה של ההמבורגרים).

‫רמה 1 (תשתית בסיסית): מתן גישה לכל הסוכנים בפרויקט ל-Google Cloud APIs‏ (core-gapi-services).

ההשפעה של מחזור החיים

אם סוכן נמחק ונוצר מחדש, מזהה המנוע החדש שלו דורש קישור מעודכן למדיניות IAM.

הוא חל באופן אוטומטי על נציגים חדשים שנפרסו בפרויקט הזה, בלי עדכוני IAM נוספים.

ניהול הצהרתי באמצעות מערכת גישה מאוחדת לכללי מדיניות (UAP / IAP v2)

בגרסה הקודמת של IAP (גרסה 1), כללי מדיניות התעבורה היו מחוברים ישירות למשאבים ספציפיים של Agent Registry באמצעות gcloud beta iap web add-iam-policy-binding. ב-IAP v2 ובמערכת גישה מאוחדת לכללי מדיניות, הקישורים לכל משאב מבוטלים לטובת מדיניות גישה אחת מרכזית של IAM (cfg/uap-rules.json).

הרשאת היציאה הבסיסית של core-gapi-services תוגדר בתור כלל 1 במדיניות הגישה המאוחדת (UAP) בסעיף 5, כדי לוודא שלכל קונטיינרי הסוכנים יש נתיבי תעבורת נתונים יוצאת בסיסיים לפני ה-Deployment.

לפרטים טכניים נוספים על מזהי חשבונות משתמשים ועל המכניקה של Workload Identity, קראו את המאמרים הבאים:

בשלב הזה מסתיים רישום נקודות קצה ל-API העיקריים. עכשיו אפשר לעבור לקטע פריסת Agent Gateway מרכזי.

4. Agent Gateway

פריסת Agent Gateway מרכזי

פורסים את Agent Gateway המרוכז (centralized-agw) במצב תעבורה יוצאת (egress) של AGENT_TO_ANYWHERE בפרויקט $PROJECT_GOVERNANCE.

הגדרת מניפסט של הגדרות שער הגישה

יוצרים cfg/${AGW_NAME}.yaml לניהול תעבורת הנתונים היוצאת:

# generate agent gateway config yaml
cat > cfg/${AGW_NAME}.yaml << EOF
name: ${AGW_NAME}
protocols:
  - MCP
googleManaged:
  governedAccessPath: AGENT_TO_ANYWHERE
registries:
  - "//agentregistry.googleapis.com/projects/${PROJECT_GOVERNANCE}/locations/${REGION}"
EOF

ייבוא הגדרות של Agent Gateway

# import and create agent gateway
gcloud network-services agent-gateways import ${AGW_NAME} \
  --source="cfg/${AGW_NAME}.yaml" \
  --location=${REGION} \
  --project=${PROJECT_GOVERNANCE}

אימות הפרטים של Agent Gateway

# show agent gateway status
gcloud network-services agent-gateways describe ${AGW_NAME} \
  --location=${REGION} \
  --project=${PROJECT_GOVERNANCE}

פלט לדוגמה:

agentGatewayCard:
  mtlsEndpoint: projects/${AGW_TP_ID}/regions/us-central1/serviceAttachments/unitkind1-swp-mtls-psc-sa
  rootCertificates:
  - |
    -----BEGIN CERTIFICATE-----
    MIIDwzCCAqugAwIBAgITNQuWGopdOZaHdcK7r7AYFhonqDANBgkqhkiG9w0BAQsF
    ...
    -----END CERTIFICATE-----
  serviceExtensionsServiceAccount: service-${PROJ_NO}@gcp-sa-dep.iam.gserviceaccount.com
createTime: 'YYYY-MM-DDT12:34:56.789098765Z'
googleManaged:
  governedAccessPath: AGENT_TO_ANYWHERE
name: projects/${PROJECT_GOVERNANCE}/locations/us-central1/agentGateways/centralized-agw
protocols:
- MCP
registries:
- //agentregistry.googleapis.com/projects/${PROJECT_GOVERNANCE}/locations/us-central1
updateTime: 'YYYY-MM-DDT12:34:56.789098765Z'

בשלב הזה מסתיימת פריסת השער, ואפשר לעבור לקטע הגדרת ההרשאה.

5. אישור

הגדרת ההרשאה של Agent Gateway ו-UAP בסיסי

‫Agent Gateway מאבטח ומנהל את תעבורת הנתונים היוצאת של הכלים והסוכנים באמצעות כללי מדיניות הרשאות (networksecurity.authzPolicies) שמשולבים עם מערכת הגישה המאוחדת לכללי מדיניות (UAP) של שרת proxy לאימות זהויות (IAP גרסה 2).

סקירה כללית של ארכיטקטורת ההרשאות

figure4

איור 4. סקירה כללית על ארכיטקטורת ההרשאות

ארכיטקטורת ההרשאות מורכבת משלוש שכבות שמקושרות זו לזו:

  1. ‫IAP Service Extension (authzExtension): משאב אזורי שמוגדר עם service: iap.googleapis.com,‏ metadata: iapPolicyVersion: "V2" ו-failOpen: false לאכיפה קפדנית של היקף האבטחה בגישת אבטחה של אפס אמון.
  2. מדיניות הרשאה של שער (authzPolicy): משאב אזורי שמטרגט את Agent Gateway באמצעות policyProfile: REQUEST_AUTHZ ו-action: CUSTOM, ומנתב את בדיקות ההרשאה לתוסף IAP Authz.
  3. ‫מדיניות גישה מאוחדת וקישור של IAM‏ (accessPolicy ו-policyBinding): משאב גלובלי של IAM v3 שנבדק על ידי IAP. הוא מאמת את ההרשאה האוניברסלית iap.googleapis.com/resources.egressViaIAP מול זהויות SPIFFE של מבצע הקריאה החוזרת ותנאי קטלוג CEL.

שלב 1: יוצרים ומייבאים את תוסף ההרשאות של IAP גרסה 2

יוצרים את המניפסט של תוסף השירות עם iapPolicyVersion: "V2" ו-failOpen: false במצב ENFORCE מחמיר:

# create authz extension config file in ENFORCE mode
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

מייבאים את התוסף Authz:

# import IAP v2 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} \
  --project=${PROJECT_GOVERNANCE}

מוודאים שתוסף Authz פעיל:

# describe authz extension
gcloud service-extensions authz-extensions describe ${AGW_NAME}-svc-ext-authz-iap \
  --location=${REGION} \
  --project=${PROJECT_GOVERNANCE}

פלט לדוגמה:

createTime: 'YYYY-MM-DDT12:34:56.789098765Z'
failOpen: false
metadata:
  iapPolicyVersion: V2
name: projects/${PROJECT_GOVERNANCE}/locations/us-central1/authzExtensions/centralized-agw-svc-ext-authz-iap
service: iap.googleapis.com
timeout: 1s

‫שלב 2: יצירה וייבוא של מדיניות הרשאה לשער

יוצרים הגדרה של Authorization Policy שמצורפת ל-Agent Gateway ומעבירה את אימות הבקשה ל-IAP Authz Extension:

# create authz policy manifest
cat > cfg/${AGW_NAME}-authz-policy-profile-iap.yaml << EOF
name: ${AGW_NAME}-authz-policy-profile-iap
target:
  resources:
    - "projects/${PROJECT_GOVERNANCE}/locations/${REGION}/agentGateways/${AGW_NAME}"
policyProfile: REQUEST_AUTHZ
action: CUSTOM
customProvider:
  authzExtension:
    resources:
      - "projects/${PROJECT_GOVERNANCE}/locations/${REGION}/authzExtensions/${AGW_NAME}-svc-ext-authz-iap"
EOF

מייבאים את מדיניות ההרשאה:

# import authz policy
gcloud beta network-security authz-policies import ${AGW_NAME}-authz-policy-profile-iap \
  --source=cfg/${AGW_NAME}-authz-policy-profile-iap.yaml \
  --location=${REGION} \
  --project=${PROJECT_GOVERNANCE}

מאמתים את מדיניות ההרשאות הפעילה:

# describe authz policy
gcloud beta network-security authz-policies describe ${AGW_NAME}-authz-policy-profile-iap \
  --location=${REGION} \
  --project=${PROJECT_GOVERNANCE}

שלב 3: כתיבת מדיניות הגישה המאוחדת הראשונית (כלל 1: ממשקי Google API בסיסיים)

יוצרים את cfg/uap-rules.json עם כלל 1 שמאשר לשלושת ה-principalSet של הפרויקט להגיע אל core-gapi-services:

# create initial unified access policy rules manifest
cat > cfg/uap-rules.json << EOF
[
  {
    "description": "Rule 1: Allow agent runtimes across all 3 projects to reach Core Google APIs",
    "effect": "ALLOW",
    "principals": [
      "principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJECT_NUMBER_GOVERNANCE}",
      "principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJECT_NUMBER_CONCIERGE}",
      "principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJECT_NUMBER_SELLERS}"
    ],
    "operation": {
      "permissions": [
        "iap.googleapis.com/resources.egressViaIAP"
      ]
    },
    "conditions": {
      "iap.googleapis.com": {
        "expression": \
        "destination.is_registered == true && \
         destination.agent_registry.resource_type == 'ENDPOINT' && ( \
         destination.agent_registry.endpoint.name == 'projects/${PROJECT_GOVERNANCE}/locations/${REGION}/endpoints/core-gapi-services' || \
         destination.agent_registry.endpoint.name == 'projects/${PROJECT_GOVERNANCE}/locations/${REGION}/endpoints/${ENDPOINT_ID}' || \
         destination.agent_registry.endpoint.name == 'projects/${PROJECT_NUMBER_GOVERNANCE}/locations/${REGION}/endpoints/${ENDPOINT_ID}')"
      }
    }
  }
]
EOF

שלב 4: יצירה וקישור של מדיניות הגישה של IAM

יוצרים את מדיניות הגישה הגלובלית של IAM:

# create global IAM access policy
gcloud iam access-policies create ${UAP_POLICY_NAME} \
  --details-rules=cfg/uap-rules.json \
  --project=${PROJECT_GOVERNANCE} \
  --location=global

מקשרים את מדיניות הגישה אל PROJECT_GOVERNANCE:

# bind access policy to governance project
gcloud iam policy-bindings create ${UAP_BINDING_NAME} \
  --policy="projects/${PROJECT_GOVERNANCE}/locations/global/accessPolicies/${UAP_POLICY_NAME}" \
  --target-resource="//cloudresourcemanager.googleapis.com/projects/${PROJECT_GOVERNANCE}" \
  --project=${PROJECT_GOVERNANCE} \
  --location=global

מוודאים שקישור המדיניות פעיל:

# verify policy binding
gcloud iam policy-bindings describe ${UAP_BINDING_NAME} \
  --project=${PROJECT_GOVERNANCE} \
  --location=global

פלט לדוגמה:

name: projects/${PROJECT_GOVERNANCE}/locations/global/policyBindings/uap-binding-centralized-agw
policy: projects/${PROJECT_GOVERNANCE}/locations/global/accessPolicies/uap-policy-centralized-agw
policyKind: ACCESS_POLICY
target:
  resource: //cloudresourcemanager.googleapis.com/projects/${PROJECT_GOVERNANCE}

עכשיו, תעבורת הנתונים היוצאת הבסיסית של Google Cloud API מאושרת באופן מאובטח בכל שלושת הפרויקטים במצב ENFORCE קפדני.

בשלב הזה מסתיימת הגדרת ההרשאות לשער, ואפשר לעבור לקטע הגדרת הרשאות IAM בפרויקטים שונים.

6. ‫IAM בפרויקטים שונים

הגדרת הרשאות IAM בפרויקטים שונים

בטופולוגיה הזו של כמה פרויקטים, Agent Runtimes נמצאים בפרויקטים מסוג Spoke (PROJECT_CONCIERGE ו-PROJECT_SELLERS), ו-Central Agent Gateway ו-Agent Registry נמצאים ב-PROJECT_GOVERNANCE.

מכיוון שהפרויקטים ב-Google Cloud הם גבולות אבטחה מבודדים, צריך לתת באופן מפורש גישה בין פרויקטים בשתי שכבות תפעוליות:

  1. Control Plane (זמן פריסה): כשפורסים קונטיינר של סוכן שהוגדר עם --agent-gateway-config, Agent Runtime Service Agent (service-@gcp-sa-aiplatform.iam.gserviceaccount.com) בפרויקט Spoke צריך לצרף את הקונטיינר לשער המרכזי. אנחנו יוצרים תפקיד מינימלי בהתאמה אישית (ar_agw_cross_project_sa) שמעניק את ההרשאות networkservices.agentGateways.use,‏ get ו-operations.get ב-PROJECT_GOVERNANCE.
  2. מישור הנתונים (הרצה בזמן ריצה):
    • גילוי קטלוג: זהויות Spoke צריכות את roles/agentregistry.viewer ב-PROJECT_GOVERNANCE כדי לפתור באופן דינמי את נקודות הקצה של סוכן היעד.
    • הפעלת היעד: סוכן ה-Concierge צריך את roles/aiplatform.user ב-PROJECT_SELLERS כדי להריץ שאילתות במנועי החשיבה הרציונלית של אתר המכירה.

יצירת תפקיד IAM בהתאמה אישית ב-PROJECT_GOVERNANCE

# create custom role in central governance project
gcloud iam roles create ar_agw_cross_project_sa \
  --project=${PROJECT_GOVERNANCE} \
  --title="Runtime Agent Gateway Cross-Project SA" \
  --description="Custom role for cross-project service agents to access Central Agent Gateway" \
  --permissions="networkservices.agentGateways.get,networkservices.agentGateways.use,networkservices.operations.get" \
  --stage="GA"

הקצאת תפקיד בהתאמה אישית לסוכני שירות של Agent Runtime

# 1. ensure aiplatform service identities are provisioned across all projects
for PROJ in ${PROJECT_GOVERNANCE} ${PROJECT_CONCIERGE} ${PROJECT_SELLERS}; do
  gcloud beta services identity create --service=aiplatform.googleapis.com --project=${PROJ}
done
# 2. derive aiplatform service agent emails
export CONCIERGE_AI_SA="service-${PROJECT_NUMBER_CONCIERGE}@gcp-sa-aiplatform.iam.gserviceaccount.com"
export CONCIERGE_RE_SA="service-${PROJECT_NUMBER_CONCIERGE}@gcp-sa-aiplatform-re.iam.gserviceaccount.com"
export CONCIERGE_COMPUTE_SA="${PROJECT_NUMBER_CONCIERGE}-compute@developer.gserviceaccount.com"

export SELLERS_AI_SA="service-${PROJECT_NUMBER_SELLERS}@gcp-sa-aiplatform.iam.gserviceaccount.com"
export SELLERS_RE_SA="service-${PROJECT_NUMBER_SELLERS}@gcp-sa-aiplatform-re.iam.gserviceaccount.com"
export SELLERS_COMPUTE_SA="${PROJECT_NUMBER_SELLERS}-compute@developer.gserviceaccount.com"
# 3. grant custom role & network viewer to Concierge and Sellers Service Agents
for SA in ${CONCIERGE_AI_SA} ${SELLERS_AI_SA}; do
  gcloud projects add-iam-policy-binding ${PROJECT_GOVERNANCE} \
    --member="serviceAccount:${SA}" \
    --role="projects/${PROJECT_GOVERNANCE}/roles/ar_agw_cross_project_sa" \
    --condition=None

  gcloud projects add-iam-policy-binding ${PROJECT_GOVERNANCE} \
    --member="serviceAccount:${SA}" \
    --role="roles/networkservices.viewer" \
    --condition=None
done
# 4. grant agent registry viewer on Governance Project for dynamic autodiscovery
for MEMBER in "serviceAccount:${CONCIERGE_AI_SA}" "serviceAccount:${CONCIERGE_RE_SA}" "serviceAccount:${CONCIERGE_COMPUTE_SA}" "serviceAccount:${SELLERS_AI_SA}" "serviceAccount:${SELLERS_RE_SA}" "serviceAccount:${SELLERS_COMPUTE_SA}" "principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJECT_NUMBER_CONCIERGE}" "principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJECT_NUMBER_SELLERS}"; do
  gcloud projects add-iam-policy-binding ${PROJECT_GOVERNANCE} \
    --member="${MEMBER}" \
    --role="roles/agentregistry.viewer" \
    --condition=None
done
# 5. grant agent project viewer on Governance Project for dynamic autodiscovery
for SA in ${CONCIERGE_COMPUTE_SA} ${CONCIERGE_AI_SA}; do
  gcloud projects add-iam-policy-binding ${PROJECT_GOVERNANCE} \
    --member="serviceAccount:${SA}" \
    --role="roles/viewer" \
    --condition=None
done
# 6. grant aitplatform user on Sellers project to Concierge for cross-project A2A invocation
for MEMBER in "serviceAccount:${CONCIERGE_AI_SA}" "serviceAccount:${CONCIERGE_RE_SA}" "serviceAccount:${CONCIERGE_COMPUTE_SA}" "principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJECT_NUMBER_CONCIERGE}"; do
  gcloud projects add-iam-policy-binding ${PROJECT_SELLERS} \
    --member="${MEMBER}" \
    --role="roles/aiplatform.user" \
    --condition=None
done

בשלב הזה מסתיימת הגדרת ה-IAM בפרויקטים השונים. עכשיו אפשר לעבור לחלק פריסת סוכני המכירות והקונסיירז'.

7. Agent Runtime

פריסת סוכני מכירות וסוכני קונסיירז'

בסיס הקוד של האפליקציה עם כמה סוכנים והסקריפטים לפריסה שמשמשים ב-Codelab הזה מנוהלים במאגר מרוחק של Google Cloud ב-GitHub. בשלבים הבאים, המאגר ישוכפל באופן מקומי, הקבצים הנדרשים יועתקו למבנה של ספריית העבודה הנוכחית, הקבצים הזמניים יימחקו והתלויות יותקנו באמצעות uv.

אחזור פריטי מידע מרחוק

# clone remote repository to temp local dir
git clone https://github.com/GoogleCloudPlatform/cloud-networking-solutions.git ./temp_agw_multiproject
# copy multi-agent application files to current working directory
cp -r temp_agw_multiproject/codelabs/agw-multiproject ./cross-project-multiagent
# remove temporary directory
rm -rf temp_agw_multiproject
# install dependencies
uv sync --directory ./cross-project-multiagent

יצירת קטגוריית Shared Central Staging

# create shared central staging bucket
gcloud storage buckets create gs://${PROJECT_GOVERNANCE}-shared-staging \
  --project=${PROJECT_GOVERNANCE} \
  --location=${REGION}
# grant cross-project read/write access to runtime service agents
gcloud storage buckets add-iam-policy-binding gs://${PROJECT_GOVERNANCE}-shared-staging \
  --member="serviceAccount:service-${PROJECT_NUMBER_CONCIERGE}@gcp-sa-aiplatform.iam.gserviceaccount.com" \
  --role="roles/storage.objectAdmin"

gcloud storage buckets add-iam-policy-binding gs://${PROJECT_GOVERNANCE}-shared-staging \
  --member="serviceAccount:service-${PROJECT_NUMBER_SELLERS}@gcp-sa-aiplatform.iam.gserviceaccount.com" \
  --role="roles/storage.objectAdmin"

איך פועל קישור של Agent Gateway בין פרויקטים

בשלב הזה תפרסו את הסוכנים של אתר המכירה בפרויקט ה-spoke‏ (PROJECT_SELLERS) ותגדירו אותם לנתב את תעבורת הנתונים היוצאת דרך ה-Agent Gateway המרכזי ב-PROJECT_GOVERNANCE:

# !-- for example purposes -- NOT a command to execute --!
# snippet from deploy_burger.py
burger_config = {
    "staging_bucket": staging_bucket_uri,
    "gcs_dir_name": "burger_agent",
    "display_name": "burger-seller-agent-adk",
    "identity_type": "AGENT_IDENTITY",
    "agent_gateway_config": {
        "agent_to_anywhere_config": {
            "agent_gateway": f"projects/{args.governance_project}/locations/{args.region}/agentGateways/{args.gateway}"
        }
    },
}
deployed_burger = client.agent_engines.create(agent=burger_playground, config=burger_config)

בגלל שכלל 1 הוגדר קודם במדיניות הגישה המאוחדת, בקשות לאתחול קונטיינרים ל-Google Cloud APIs מורשות דרך השער ללא הפרעה.

פריסת סוכני מכירות של המבורגרים ופיצות ב-PROJECT_SELLERS

# 1. deploy Burger Seller Agent to PROJECT_SELLERS
uv run --directory ./cross-project-multiagent python deploy_burger.py \
  --project=${PROJECT_SELLERS} \
  --region=${REGION} \
  --governance-project=${PROJECT_GOVERNANCE} \
  --gateway=projects/${PROJECT_GOVERNANCE}/locations/${REGION}/agentGateways/${AGW_NAME}
# 2. deploy Pizza Seller Agent to PROJECT_SELLERS
uv run --directory ./cross-project-multiagent python deploy_pizza.py \
  --project=${PROJECT_SELLERS} \
  --region=${REGION} \
  --governance-project=${PROJECT_GOVERNANCE} \
  --gateway=projects/${PROJECT_GOVERNANCE}/locations/${REGION}/agentGateways/${AGW_NAME}

אימות הניתוב של שער הגישה של אתר המכירה

# retrieve deployed seller reasoning engine IDs
export BURGER_ENGINE_ID=$(grep BURGER_SELLER_AGENT_ID cross-project-multiagent/burger_agent.env | awk -F'/' '{print $NF}')
export PIZZA_ENGINE_ID=$(grep PIZZA_SELLER_AGENT_ID cross-project-multiagent/pizza_agent.env | awk -F'/' '{print $NF}')

echo "Burger Engine ID: ${BURGER_ENGINE_ID}"
echo "Pizza Engine ID:  ${PIZZA_ENGINE_ID}"
# inspect runtime configuration for both Seller Agents
for ENGINE_ID in ${BURGER_ENGINE_ID} ${PIZZA_ENGINE_ID}; do
  curl -s -X GET "https://${REGION}-aiplatform.googleapis.com/v1beta1/projects/${PROJECT_SELLERS}/locations/${REGION}/reasoningEngines/${ENGINE_ID}" \
    -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
    -H "Content-Type: application/json" \
    | jq '{displayName: .displayName, identityType: .spec.identityType, effectiveIdentity: .spec.effectiveIdentity, agentGatewayConfig: .spec.deploymentSpec.agentGatewayConfig}'
done

פריסת סוכן הרכישה ב-PROJECT_CONCIERGE

# deploy Purchasing Concierge to PROJECT_CONCIERGE
uv run --directory ./cross-project-multiagent python deploy_concierge_adk.py \
  --project=${PROJECT_CONCIERGE} \
  --region=${REGION} \
  --staging-bucket=gs://${PROJECT_GOVERNANCE}-shared-staging \
  --gateway-name=${AGW_NAME} \
  --gateway-project=${PROJECT_GOVERNANCE}

אימות הניתוב של שער הרכישה

# retrieve Concierge engine ID
export CONCIERGE_ENGINE_ID=$(grep CONCIERGE_AGENT_ID cross-project-multiagent/concierge_agent.env | awk -F'/' '{print $NF}')
echo "Concierge Engine ID: ${CONCIERGE_ENGINE_ID}"
# inspect runtime configuration for Purchasing Concierge
curl -s -X GET "https://${REGION}-aiplatform.googleapis.com/v1beta1/projects/${PROJECT_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "Content-Type: application/json" \
  | jq '{displayName: .displayName, identityType: .spec.identityType, effectiveIdentity: .spec.effectiveIdentity, agentGatewayConfig: .spec.deploymentSpec.agentGatewayConfig}'

בפלט אמורים להופיע זהות Agent Runtime והפרויקט של סוכן Concierge, והקישור ל-Agent Gateway של פרויקט הפיקוח.

{
  "displayName": "purchasing-concierge-adk",
  "identityType": "AGENT_IDENTITY",
  "effectiveIdentity": "agents.global.org-${ORG_ID}.system.id.goog/resources/aiplatform/projects/${PROJECT_CONCIERGE}/locations/us-central1/reasoningEngines/${CONCIERGE_ENGINE_ID}",
  "agentGatewayConfig": {
    "agentToAnywhereConfig": {
      "agentGateway": "projects/${PROJECT_GOVERNANCE}/locations/us-central1/agentGateways/centralized-agw"
    }
  }
}

בשלב הזה מסתיימת פריסת הסוכנים, ואפשר לעבור לחלק רישום סוכנים במרשם הסוכנים המרכזי.

8. מרשם בין פרויקטים

רישום סוכנים ב-Central Agent Registry

רושמים את כל שלושת הסוכנים ב-Central Agent Registry ב-PROJECT_GOVERNANCE באמצעות נקודות קצה אזוריות של mTLS בפרויקטים שונים ומספרי פרויקטים מספריים.

רישום שירותים כסוכנים שאינם A2A ב-Agent Registry

# 1. register Burger Seller Agent
gcloud agent-registry services create burger-seller-agent \
  --project=${PROJECT_GOVERNANCE} \
  --location=${REGION} \
  --display-name="Burger Seller Agent" \
  --description="Specialist agent that sells burgers and fries" \
  --agent-spec-type=no-spec \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${BURGER_ENGINE_ID}:query \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com/v1beta1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${BURGER_ENGINE_ID}:query \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com:443/v1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${BURGER_ENGINE_ID}:query \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com:443/v1beta1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${BURGER_ENGINE_ID}:query \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com/v1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${BURGER_ENGINE_ID}:query \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com/v1beta1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${BURGER_ENGINE_ID}:query \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com:443/v1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${BURGER_ENGINE_ID}:query \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com:443/v1beta1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${BURGER_ENGINE_ID}:query
# 2. register Pizza Seller Agent
gcloud agent-registry services create pizza-seller-agent \
  --project=${PROJECT_GOVERNANCE} \
  --location=${REGION} \
  --display-name="Pizza Seller Agent" \
  --description="Specialist agent that sells pizzas and pasta" \
  --agent-spec-type=no-spec \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${PIZZA_ENGINE_ID}:query \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com/v1beta1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${PIZZA_ENGINE_ID}:query \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com:443/v1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${PIZZA_ENGINE_ID}:query \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com:443/v1beta1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${PIZZA_ENGINE_ID}:query \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com/v1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${PIZZA_ENGINE_ID}:query \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com/v1beta1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${PIZZA_ENGINE_ID}:query \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com:443/v1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${PIZZA_ENGINE_ID}:query \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com:443/v1beta1/projects/${PROJECT_NUMBER_SELLERS}/locations/${REGION}/reasoningEngines/${PIZZA_ENGINE_ID}:query
# 3. register Purchasing Concierge Agent
gcloud agent-registry services create purchasing-concierge-adk \
  --project=${PROJECT_GOVERNANCE} \
  --location=${REGION} \
  --display-name="Purchasing Concierge Agent" \
  --description="Orchestrator concierge agent that routes purchasing requests" \
  --agent-spec-type=no-spec \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJECT_NUMBER_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}:query \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com/v1beta1/projects/${PROJECT_NUMBER_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}:query \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com:443/v1/projects/${PROJECT_NUMBER_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}:query \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.googleapis.com:443/v1beta1/projects/${PROJECT_NUMBER_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}:query \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com/v1/projects/${PROJECT_NUMBER_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}:query \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com/v1beta1/projects/${PROJECT_NUMBER_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}:query \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com:443/v1/projects/${PROJECT_NUMBER_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}:query \
  --interfaces=protocolBinding=JSONRPC,url=https://${REGION}-aiplatform.mtls.googleapis.com:443/v1beta1/projects/${PROJECT_NUMBER_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}:query

תיעוד מזהי הרישום של הסוכנים הבסיסיים

# capture underlying Agent Registry Agent UUIDs
export BURGER_AGENT_ID=$(gcloud agent-registry services describe burger-seller-agent --project=${PROJECT_GOVERNANCE} --location=${REGION} --format="value(registryResource)" | awk -F'/' '{print $NF}')
export PIZZA_AGENT_ID=$(gcloud agent-registry services describe pizza-seller-agent --project=${PROJECT_GOVERNANCE} --location=${REGION} --format="value(registryResource)" | awk -F'/' '{print $NF}')
export CONCIERGE_AGENT_ID=$(gcloud agent-registry services describe purchasing-concierge-adk --project=${PROJECT_GOVERNANCE} --location=${REGION} --format="value(registryResource)" | awk -F'/' '{print $NF}')

echo "Burger Agent ID:    ${BURGER_AGENT_ID}"
echo "Pizza Agent ID:     ${PIZZA_AGENT_ID}"
echo "Concierge Agent ID: ${CONCIERGE_AGENT_ID}"

בשלב הזה מסתיימת הגדרת המרשם. עכשיו אפשר לעבור לקטע הגדרת מדיניות תעבורת נתונים יוצאת של A2A.

9. כללי מדיניות של UAP

הגדרת מדיניות תעבורת נתונים יוצאת (egress) מסוג A2A במדיניות גישה מאוחדת (UAP)

בארכיטקטורה Default Deny של Agent Gateway במצב ENFORCE מחמיר:

  1. כלל 1 (ממשקי Google Cloud API בסיסיים): מאפשר לקונטיינרים של הסוכנים בכל 3 הפרויקטים להגיע אל core-gapi-services.
  2. כלל 2 (סוכן המכירות של ההמבורגרים: ALLOW): מאפשר למכונה של סוכן הרכישה להפעיל באופן ספציפי את סוכן המכירות של ההמבורגרים.
  3. סוכן מכירות של פיצה (נדחה כברירת מחדל): הושאר בכוונה מחוץ לכללי המדיניות. במצב ENFORCE (failOpen: false), כל ניסיון של Concierge להפעיל את Pizza Seller יסתיים מיד בגבולות השער עם HTTP 403 Forbidden.

הגדרת הזהות של סוכן Formulate Concierge

# formulate the exact SPIFFE machine identity for the Concierge Agent
export CONCIERGE_SPIFFE_PRINCIPAL="principal://agents.global.org-${ORG_ID}.system.id.goog/resources/aiplatform/projects/${PROJECT_NUMBER_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}"
echo "Concierge SPIFFE Principal: ${CONCIERGE_SPIFFE_PRINCIPAL}"

עדכון מניפסט העדכונים עם כלל 1 וכלל 2

כדי לעדכן את מדיניות הגישה בלי לפגוע בכללים הקיימים, מגדירים את המניפסט המלא והמאוחד שמכיל את כלל 1 (Google APIs בסיסיים של Google) ואת כלל 2 (סוכן Burger Seller):

# create consolidated policy manifest with Rule 1 and Rule 2
cat > cfg/uap-rules-consolidated.json << EOF
[
  {
    "description": "Rule 1: Allow agent runtimes across all 3 projects to reach Core Google APIs",
    "effect": "ALLOW",
    "principals": [
      "principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJECT_NUMBER_GOVERNANCE}",
      "principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJECT_NUMBER_CONCIERGE}",
      "principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJECT_NUMBER_SELLERS}"
    ],
    "operation": {
      "permissions": [
        "iap.googleapis.com/resources.egressViaIAP"
      ]
    },
    "conditions": {
      "iap.googleapis.com": {
        "expression": \
        "destination.is_registered == true && \
         destination.agent_registry.resource_type == 'ENDPOINT' && ( \
         destination.agent_registry.endpoint.name == 'projects/${PROJECT_GOVERNANCE}/locations/${REGION}/endpoints/core-gapi-services' || \
         destination.agent_registry.endpoint.name == 'projects/${PROJECT_GOVERNANCE}/locations/${REGION}/endpoints/${ENDPOINT_ID}' || \
         destination.agent_registry.endpoint.name == 'projects/${PROJECT_NUMBER_GOVERNANCE}/locations/${REGION}/endpoints/${ENDPOINT_ID}')"
      }
    }
  },
  {
    "description": "Rule 2: Allow Purchasing Concierge to invoke Burger Seller Agent via Central Gateway",
    "effect": "ALLOW",
    "principals": [
      "${CONCIERGE_SPIFFE_PRINCIPAL}",
      "principal://agents.global.org-${ORG_ID}.system.id.goog/attribute.agentIdentity/projects/${PROJECT_NUMBER_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}",
      "principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.agentIdentity/projects/${PROJECT_NUMBER_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}"
    ],
    "operation": {
      "permissions": [
        "iap.googleapis.com/resources.egressViaIAP"
      ]
    },
    "conditions": {
      "iap.googleapis.com": {
        "expression": \
        "destination.is_registered == true && \
         destination.agent_registry.resource_type == 'AGENT' && ( \
         destination.agent_registry.agent.name == 'projects/${PROJECT_GOVERNANCE}/locations/${REGION}/agents/burger-seller-agent' || \
         destination.agent_registry.agent.name == 'projects/${PROJECT_GOVERNANCE}/locations/${REGION}/agents/${BURGER_AGENT_ID}' || \
         destination.agent_registry.agent.name == 'projects/${PROJECT_NUMBER_GOVERNANCE}/locations/${REGION}/agents/${BURGER_AGENT_ID}')"
      }
    }
  }
]
EOF

החלת מדיניות הגישה המעודכנת

מחילים את מניפסט הכללים המאוחד באופן הצהרתי באמצעות --details-rules:

# update IAM access policy with consolidated manifest (Rule 1 + Rule 2)
gcloud iam access-policies update ${UAP_POLICY_NAME} \
  --details-rules=cfg/uap-rules-consolidated.json \
  --project=${PROJECT_GOVERNANCE} \
  --location=global

אימות פרטי מדיניות הגישה של IAM

# inspect updated access policy
gcloud iam access-policies describe ${UAP_POLICY_NAME} \
  --project=${PROJECT_GOVERNANCE} \
  --location=global

פלט לדוגמה:

details:
  rules:
  - conditions:
      iap.googleapis.com:
        expression: destination.is_registered == true && destination.agent_registry.resource_type
          == 'ENDPOINT' && (destination.agent_registry.endpoint.name == 'projects/${PROJECT_GOVERNANCE}/locations/us-central1/endpoints/core-gapi-services'
          || destination.agent_registry.endpoint.name == 'projects/${PROJECT_NUMBER_GOVERNANCE}/locations/us-central1/endpoints/${ENDPOINT_ID}')
    description: 'Rule 1: Allow agent runtimes across all 3 projects to reach Core
      Google APIs'
    effect: ALLOW
    operation:
      permissions:
      - iap.googleapis.com/resources.egressViaIAP
    principals:
    - principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJECT_NUMBER_GOVERNANCE}
    - principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJECT_NUMBER_CONCIERGE}
    - principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJECT_NUMBER_SELLERS}
  - conditions:
      iap.googleapis.com:
        expression: (destination.is_registered == true) && (destination.agent_registry.resource_type
          == 'AGENT') && (destination.agent_registry.agent.name == 'projects/${PROJECT_GOVERNANCE}/locations/us-central1/agents/burger-seller-agent'
          || destination.agent_registry.agent.name == 'projects/${PROJECT_NUMBER_GOVERNANCE}/locations/us-central1/agents/${BURGER_AGENT_ID}')
    description: 'Rule 2: Allow Purchasing Concierge to invoke Burger Seller Agent
      via Central Gateway'
    effect: ALLOW
    operation:
      permissions:
      - iap.googleapis.com/resources.egressViaIAP
    principals:
    - principal://agents.global.org-${ORG_ID}.system.id.goog/resources/aiplatform/projects/${PROJECT_NUMBER_CONCIERGE}/locations/us-central1/reasoningEngines/${CONCIERGE_ENGINE_ID}
name: projects/${PROJECT_GOVERNANCE}/locations/global/accessPolicies/uap-policy-centralized-agw

בשלב הזה מסתיימת הגדרת המדיניות. עכשיו אפשר לעבור לקטע בדיקה ואימות של מדיניות המשילות.

10. אימות המדיניות

בדיקה ואימות של מדיניות הפיקוח באמצעות Cloud Logging

בקטע הזה תבדקו אינטראקציות בין סוכנים (A2A) בפרויקטים שונים ב-AI Playground של Agent Runtime, תצפו בחסימה של היקף HTTP 403 Forbidden אמיתי במצב ENFORCE קפדני, תשנו את המדיניות המאוחדת של בקרת הגישה (UAP) בזמן אמת ותאמתו אישור הזמנה מיידי.

שלב 1: פותחים את Agent Runtime AI Playground ב-PROJECT_CONCIERGE

  1. פותחים את מסוף Google Cloud.
  2. בסרגל העליון לבחירת פרויקטים, עוברים אל PROJECT_CONCIERGE.
  3. בתפריט הניווט, עוברים אל Agent Platform > Agents > Deployments.
  4. לוחצים על purchasing-concierge-adk.
  5. לוחצים על Playground כדי לפתוח את ממשק הצ'אט האינטראקטיבי בצד שמאל של המסך.

שלב 2: בדיקת הזמנת המבורגר (התאמה לכלל 2 -> 200 OK)

בחלון הצ'אט של Playground, שולחים את ההנחיה הבאה:

I would like 10 Classic Cheeseburgers. Place this order now.

אם נדרשת תגובת אישור, צריך לשלוח את התשובה הבאה:

Confirmed, please place the order.

לחלופין, אפשר לבדוק באופן פרוגרמטי מ-Cloud Shell או מהטרמינל:

uv run --directory ./cross-project-multiagent python -c "
import vertexai
from vertexai.preview import reasoning_engines
vertexai.init(project='${PROJECT_CONCIERGE}', location='${REGION}')
agent = reasoning_engines.ReasoningEngine('projects/${PROJECT_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}')
response = agent.query(input={'message': 'I would like 22 Spicy Cajun Burgers please. Place this order now.'})
print(response)
"

אם נדרשת תגובת אישור, משתמשים בפקודה הזו:

uv run --directory ./cross-project-multiagent python -c "
import vertexai
from vertexai.preview import reasoning_engines
vertexai.init(project='${PROJECT_CONCIERGE}', location='${REGION}')
agent = reasoning_engines.ReasoningEngine('projects/${PROJECT_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}')
response = agent.query(input='Yes please place the order now.')
print(response['text'])
"

מה קורה מאחורי הקלעים:

  1. גילוי דינמי: במהלך הפעלת הסשן, סוכן הרכש שלח שאילתה למרשם הסוכנים המרכזי ב-PROJECT_GOVERNANCE (דרך core-gapi-services באמצעות Agent Gateway שאושר על ידי כלל 1) כדי לגלות את נקודת הקצה האזורית של mTLS עבור burger-seller-agent.
  2. זיהוי הכוונה והפעלת A2A: Gemini בתוך Purchasing Concierge מנתח את הכוונה להזמנה ממסעדה ומפעיל את Burger Seller Agent באמצעות RPC יוצא אל https://${REGION}-aiplatform.mtls.googleapis.com/.../reasoningEngines/${BURGER_ENGINE_ID}.
  3. יירוט של Gateway והפצת SPIFFE: תעבורת הנתונים היוצאת נלכדת על ידי agent_gateway_config ומופנית אל Central Agent Gateway ב-PROJECT_GOVERNANCE, ונושאת את הזהות הקריפטוגרפית של SPIFFE של Concierge‏ (principal://...).
  4. בדיקת המדיניות של IAP v2: שער ה-Agent המרכזי מפעיל את התוסף של IAP שמפנה לבדיקת הרשאות (authzExtension). ב-IAP v2 נבדק כלל 2 במדיניות הגישה המאוחדת של IAM. מכיוון שהמתקשר תואם ל-${CONCIERGE_SPIFFE_PRINCIPAL} והיעד תואם ל-burger-seller-agent, ‏IAP מחזיר את הערך ALLOW (granted: true).
  5. ביצוע בפרויקטים שונים: שרת ה-proxy של Agent Gateway מעביר את הבקשה המורשית בין פרויקטים אל PROJECT_SELLERS, שבו מנוע החשיבה הרציונלית של Burger Seller מעבד את ההזמנה ומחזיר אישור.

התשובה הצפויה:

Your order for 10 Classic Cheeseburger(s) has been placed!
Here is a summary of your order:
- 10x Classic Cheeseburger @ IDR 85,000/each = IDR 850,000

Total: IDR 850,000
Your Order ID is: e8f9c732-f347-4cc4-acff-cfe09ccbeddd

שלב 3: בודקים את יומני הביקורת של Agent Gateway ו-IAP v2‏ (HTTP 200 / ALLOWED)

שליחת שאילתות על יומני הבקשות של Agent Gateway ב-PROJECT_GOVERNANCE:

# query Agent Gateway logs for successful 200 OK requests
gcloud logging read "
  logName=\"projects/${PROJECT_GOVERNANCE}/logs/networkservices.googleapis.com%2Fgateway_requests\"
  AND jsonPayload.authzPolicyInfo.result=\"ALLOWED\"
" \
  --project="${PROJECT_GOVERNANCE}" \
  --limit=10 \
  --format="table(
    timestamp.date('%H:%M:%S'):label=TIME,
    httpRequest.requestMethod:label=METHOD,
    httpRequest.status:label=STATUS,
    jsonPayload.authzPolicyInfo.result:label=AUTHZ,
    httpRequest.requestUrl:label=URL
  )"

היומנים צריכים לתעד תעבורת נתונים יוצאת שמגיעה משני הפרויקטים המקושרים (PROJECT_CONCIERGE ו-PROJECT_SELLERS) עם שדות תעבורת נתונים יוצאת (egress) כמו קריאות להסקת מסקנות של Gemini‏ (generateContent), נתוני טלמטריה של Cloud Trace‏ (/v1/traces) וחיפושים של פרטי כניסה ל-IAM – שמיורטים ומורשים באופן שקוף על ידי כלל 1 (core-gapi-services).

שליחת שאילתה ליומני הגישה לנתונים של Cloud Audit ב-IAP v2 כדי לאמת את גרסת המדיניות POLICY_VERSION_V2:

# query IAP v2 audit logs with shortened principal and resource fields
gcloud logging read "
  logName=\"projects/${PROJECT_GOVERNANCE}/logs/cloudaudit.googleapis.com%2Fdata_access\"
  AND protoPayload.serviceName=\"iap.googleapis.com\"
" \
  --project="${PROJECT_GOVERNANCE}" \
  --limit=5 \
  --format="table(
    timestamp.date('%H:%M:%S'):label=TIME,
    protoPayload.authenticationInfo.principalSubject.sub('\.global\..*\/reasoningEngines\/', '.[...]/reasoningEngines/'):label=CALLER,
    protoPayload.authorizationInfo[0].granted:label=GRANTED,
    protoPayload.metadata.destination.agent_registry.resource_type.basename():label=TYPE,
    protoPayload.metadata.destination.agent_registry.resource_id.basename():label=RESOURCE_ID,
    protoPayload.authorizationInfo[0].permission.basename():label=PERMISSION
  )"

פלט לדוגמה:

TIME      CALLER                                                            GRANTED  TYPE      RESOURCE_ID     PERMISSION
HH:MM:SS  principal://agents.[...]/reasoningEngines/${CONCIERGE_ENGINE_ID}  True     Endpoint  ${ENDPOINT_ID}  resources.egressViaIAP
HH:MM:SS  principal://agents.[...]/reasoningEngines/${BURGER_ENGINE_ID}     True     Endpoint  ${ENDPOINT_ID}  resources.egressViaIAP
HH:MM:SS  principal://agents.[...]/reasoningEngines/${CONCIERGE_ENGINE_ID}  True     Endpoint  ${ENDPOINT_ID}  resources.egressViaIAP
HH:MM:SS  principal://agents.[...]/reasoningEngines/${BURGER_ENGINE_ID}     True     Endpoint  ${ENDPOINT_ID}  resources.egressViaIAP

שלב 4: בדיקת הזמנת פיצה (דחייה כברירת מחדל -> HTTP 403 Forbidden ENFORCED)

באותו חלון צ'אט ב-Playground, שלחו את ההנחיה הבאה להזמנת פיצה:

I would like 10 BBQ Chicken Pizzas. Place this order now.

אם נדרשת תגובת אישור, צריך לשלוח את התשובה הבאה:

Confirmed, please place the order.

לחלופין, אפשר לבדוק באופן פרוגרמטי מ-Cloud Shell או מהטרמינל:

uv run --directory ./cross-project-multiagent python -c "
import vertexai
from vertexai.preview import reasoning_engines
vertexai.init(project='${PROJECT_CONCIERGE}', location='${REGION}')
agent = reasoning_engines.ReasoningEngine('projects/${PROJECT_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}')
response = agent.query(input='I would like 8 Hawaiian pizzas, please. Place this order now.')
print(response)
"

אם נדרשת תגובת אישור, משתמשים בפקודה הזו:

uv run --directory ./cross-project-multiagent python -c "
import vertexai
from vertexai.preview import reasoning_engines
vertexai.init(project='${PROJECT_CONCIERGE}', location='${REGION}')
agent = reasoning_engines.ReasoningEngine('projects/${PROJECT_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}')
response = agent.query(input='Yes please place the order now.')
print(response['text'])
"

התשובה הצפויה:

I apologize, but I am unable to process that request at the moment. It seems
there was an issue connecting to the pizza seller agent. Please try again later.

מה קורה מאחורי הקלעים:

  1. איתור דינמי: סוכן הרכישה פתר את נקודת הקצה (endpoint) של pizza-seller-agent מ-Central Agent Registry במהלך ההפעלה.
  2. זיהוי הכוונה והפעלת A2A: ‏Gemini בתוך Purchasing Concierge מנסה לשלוח את בקשת ההזמנה של הפיצה לנקודת הקצה של Pizza Seller ב-PROJECT_SELLERS.
  3. יירוט בשער: ה-RPC היוצא נתפס על ידי agent_gateway_config ומופנה אל Central Agent Gateway.
  4. הערכת מדיניות של IAP v2 (דחייה כברירת מחדל): ה-Central Agent Gateway מפעיל את IAP v2. בגלל שאין כלל במדיניות הגישה המאוחדת שתואם ל-pizza-seller-agent, ‏IAP מחזיר את הערך DENY (granted: false).
  5. חסימה קפדנית של היקף השירות: בגלל שתוסף Authz נמצא במצב אכיפה (failOpen: false), Agent Gateway מנתק מיד את החיבור היוצא ומחזיר את השגיאה HTTP 403 Forbidden. תעבורת הנתונים אף פעם לא יוצאת מהשער ואף פעם לא מגיעה אל PROJECT_SELLERS.

שלב 5: בודקים את היומנים של Agent Gateway כדי לאתר בקשות חסומות (HTTP 403 / DENIED)

# query Agent Gateway logs for blocked 403 requests
gcloud logging read "
  logName=\"projects/${PROJECT_GOVERNANCE}/logs/networkservices.googleapis.com%2Fgateway_requests\"
  AND httpRequest.status=403
" \
  --project="${PROJECT_GOVERNANCE}" \
  --limit=5 \
  --format="table(
    timestamp.date('%H:%M:%S'):label=TIME,
    httpRequest.requestMethod:label=METHOD,
    httpRequest.status:label=STATUS,
    jsonPayload.authzPolicyInfo.result:label=AUTHZ,
    httpRequest.requestUrl:label=URL
  )"

פלט לדוגמה של יומן דחייה:

TIME      METHOD  STATUS  AUTHZ   URL
HH:MM:SS  POST    403     DENIED  https://us-central1-aiplatform.mtls.googleapis.com/v1beta1/projects/${PROJECT_SELLERS}/locations/us-central1/reasoningEngines/${PIZZA_ENGINE_ID}:query

שליחת שאילתה ליומני הביקורת של Data Access ב-IAP v2 לגבי ההחלטה לדחות:

# query IAP v2 audit logs with shortened principal and resource fields
gcloud logging read "
  logName=\"projects/${PROJECT_GOVERNANCE}/logs/cloudaudit.googleapis.com%2Fdata_access\"
  AND protoPayload.serviceName=\"iap.googleapis.com\"
" \
  --project="${PROJECT_GOVERNANCE}" \
  --limit=5 \
  --format="table(
    timestamp.date('%H:%M:%S'):label=TIME,
    protoPayload.authenticationInfo.principalSubject.sub('\.global\..*\/reasoningEngines\/', '.[...]/reasoningEngines/'):label=CALLER,
    protoPayload.authorizationInfo[0].granted:label=GRANTED,
    protoPayload.metadata.destination.agent_registry.resource_type.basename():label=TYPE,
    protoPayload.metadata.destination.agent_registry.resource_id.basename():label=RESOURCE_ID,
    protoPayload.authorizationInfo[0].permission.basename():label=PERMISSION
  )"

פלט לדוגמה של יומן ביקורת שנדחה:

TIME      CALLER                                                            GRANTED  TYPE      RESOURCE_ID     PERMISSION
HH:MM:SS  principal://agents.[...]/reasoningEngines/${PIZZA_ENGINE_ID}      True     Endpoint  ${REGISTRY_ID}  resources.egressViaIAP
HH:MM:SS  principal://agents.[...]/reasoningEngines/${PIZZA_ENGINE_ID}      True     Endpoint  ${REGISTRY_ID}  resources.egressViaIAP
HH:MM:SS  principal://agents.[...]/reasoningEngines/${CONCIERGE_ENGINE_ID}  False    Agent     ${REGISTRY_ID}  resources.egressViaIAP
HH:MM:SS  principal://agents.[...]/reasoningEngines/${PIZZA_ENGINE_ID}      True     Endpoint  ${REGISTRY_ID}  resources.egressViaIAP

שלב 6: מתן גישה דינמית לתעבורת נתונים יוצאת לסוכן הפיצה

יוצרים cfg/uap-rules-update-3.json חדש שכולל את כלל 1 (ממשקי API בסיסיים), כלל 2 (סוכן למכירת המבורגרים) ועכשיו גם את כלל 3 (סוכן למכירת פיצות).

# create addendum to update policy manifest with Rule 3 for Pizza Agent
cat > cfg/uap-rules-update-3.json << EOF
[
  {
    "description": "Rule 3: Allow Purchasing Concierge to invoke Pizza Seller Agent via Central Gateway",
    "effect": "ALLOW",
    "principals": [
      "${CONCIERGE_SPIFFE_PRINCIPAL}"
    ],
    "operation": {
      "permissions": [
        "iap.googleapis.com/resources.egressViaIAP"
      ]
    },
    "conditions": {
      "iap.googleapis.com": {
        "expression": \
        "destination.is_registered == true && \
         destination.agent_registry.resource_type == 'AGENT' && ( \
         destination.agent_registry.agent.name == 'projects/${PROJECT_GOVERNANCE}/locations/${REGION}/agents/pizza-seller-agent' || \
         destination.agent_registry.agent.name == 'projects/${PROJECT_GOVERNANCE}/locations/${REGION}/agents/${PIZZA_AGENT_ID}' || \
         destination.agent_registry.agent.name == 'projects/${PROJECT_NUMBER_GOVERNANCE}/locations/${REGION}/agents/${PIZZA_AGENT_ID}')"
      }
    }
  }
]
EOF

מחילים את עדכון המדיניות בזמן אמת:

# update IAM access policy with Pizza rule
gcloud iam access-policies update ${UAP_POLICY_NAME} \
  --add-details-rules=cfg/uap-rules-update-3.json \
  --project=${PROJECT_GOVERNANCE} \
  --location=global

שלב 7: שולחים שאילתה נוספת לסוכן הפיצה (תגובת הצלחה מיידית 200 OK)

בחלון הצ'אט של Playground, שולחים מחדש את ההנחיה להזמנת פיצה:

I would like 10 BBQ Chicken Pizzas. Place this order now.

אם נדרשת תגובת אישור, צריך לשלוח את התשובה הבאה:

Confirmed, please place the order.

לחלופין, אפשר לבדוק באופן פרוגרמטי מ-Cloud Shell או מהטרמינל:

uv run --directory ./cross-project-multiagent python -c "
import vertexai
from vertexai.preview import reasoning_engines
vertexai.init(project='${PROJECT_CONCIERGE}', location='${REGION}')
agent = reasoning_engines.ReasoningEngine('projects/${PROJECT_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}')
response = agent.query(input='I would like 11 Veggie pizzas, please. Place this order now.')
print(response)
"

אם נדרשת תגובת אישור, משתמשים בפקודה הזו:

uv run --directory ./cross-project-multiagent python -c "
import vertexai
from vertexai.preview import reasoning_engines
vertexai.init(project='${PROJECT_CONCIERGE}', location='${REGION}')
agent = reasoning_engines.ReasoningEngine('projects/${PROJECT_CONCIERGE}/locations/${REGION}/reasoningEngines/${CONCIERGE_ENGINE_ID}')
response = agent.query(input='Yes please place the order now.')
print(response['text'])
"

התשובה הצפויה:

Your order has been placed!

**Order ID:** 8d6c13d7-31dc-4d80-b6a7-80d1e50b6411

**Order Details:**
*   10 x BBQ Chicken Pizza @ IDR 130,000 each = IDR 1,300,000

**Total: IDR 1,300,000**

מה קורה מאחורי הקלעים:

  1. רענון דינמי של המדיניות: עדכון של מדיניות הגישה המאוחדת של IAM נכנס לתוקף באופן מיידי במנוע ההערכה של IAP, בלי זמן השבתה ובלי פריסה מחדש של קונטיינרים.
  2. הפעלת A2A: הסוכן האישי שולח את הבקשה דרך ה-Central Agent Gateway.
  3. הערכת המדיניות של IAP v2 (אישור): גרסה 2 של IAP תואמת לכלל 3, מאמתת את זהות מבצע הקריאה החוזרת ואת ביטוי היעד של CEL, ומחזירה את הערך ALLOW (granted: true).
  4. ביצוע בין פרויקטים: ה-Central Agent Gateway מעביר את התנועה המורשית אל PROJECT_SELLERS, שבו מוכר הפיצה מעבד את ההזמנה.

‫שלב 8: בודקים את היומנים של Agent Gateway כדי לראות את הבקשות שקיבלו הרשאה ב-Granted Pizza

# query Agent Gateway logs for successful 200 OK requests
gcloud logging read "
  logName=\"projects/${PROJECT_GOVERNANCE}/logs/networkservices.googleapis.com%2Fgateway_requests\"
  AND jsonPayload.authzPolicyInfo.result=\"ALLOWED\"
" \
  --project="${PROJECT_GOVERNANCE}" \
  --limit=10 \
  --format="table(
    timestamp.date('%H:%M:%S'):label=TIME,
    httpRequest.requestMethod:label=METHOD,
    httpRequest.status:label=STATUS,
    jsonPayload.authzPolicyInfo.result:label=AUTHZ,
    httpRequest.requestUrl:label=URL
  )"

פלט לדוגמה של יומן הרשאות:

TIME      METHOD  STATUS  AUTHZ    URL
HH:MM:SS  POST    200     ALLOWED  https://aiplatform.mtls.googleapis.com/v1beta1/projects/${PROJECT_SELLERS}/locations/global/publishers/google/models/gemini-3.5-flash:generateContent
HH:MM:SS  POST    200     ALLOWED  https://us-central1-aiplatform.mtls.googleapis.com/v1beta1/projects/${PROJECT_SELLERS}/locations/us-central1/reasoningEngines/${PIZZA_ENGINE_ID}:query

בשלב הזה מסתיימות הבדיקה והאימות. השלב הבא הוא ניקוי.

11. הסרת המשאבים

כדי להימנע מחיובים בחשבון Google Cloud על המשאבים שבהם השתמשתם ב-Codelab הזה, בצעו את שלבי הפירוק בסדר הפוך של התלות:

1. ניקוי פריסות של מנוע חשיבה רציונלית

מריצים את הסקריפט cleanup_old_deployments.py שכלול בשני פרויקטי זמן הריצה כדי למחוק את מנועי החשיבה הרציונלית, וממתינים לסיום הפעולות הארוכות שלהם:

# delete all Reasoning Engines deployed in Concierge and Sellers projects
uv run --directory ./cross-project-multiagent python cleanup_old_deployments.py --project=${PROJECT_CONCIERGE} --region=${REGION}
uv run --directory ./cross-project-multiagent python cleanup_old_deployments.py --project=${PROJECT_SELLERS} --region=${REGION}

אפשר גם להציג ולמחוק מנועי חשיבה רציונלית בשורה:

uv run --directory ./cross-project-multiagent python -c '
import vertexai
import os
from vertexai.preview import reasoning_engines

region = os.environ.get("REGION", "us-central1")
for proj in [os.environ.get("PROJECT_CONCIERGE"), os.environ.get("PROJECT_SELLERS")]:
    if not proj:
        continue
    print(f"Cleaning reasoning engines in {proj}...")
    vertexai.init(project=proj, location=region)
    for eng in reasoning_engines.ReasoningEngine.list():
        print(f"  Deleting {eng.resource_name} ({eng.display_name})...")
        eng.delete()
'

2. מחיקת שירותי רישום של נציגים

# delete agent registry services in Central Governance Project
for SERVICE in burger-seller-agent pizza-seller-agent purchasing-concierge-adk core-gapi-services; do
  gcloud agent-registry services delete ${SERVICE} \
    --project=${PROJECT_GOVERNANCE} \
    --location=${REGION} \
    --quiet || true
done

‫3. מחיקת קישור למערכת גישה מאוחדת לכללי מדיניות (UAP) ומדיניות גישה ב-IAM

# 1. delete IAM policy binding
gcloud -q iam policy-bindings delete ${UAP_BINDING_NAME} \
  --project=${PROJECT_GOVERNANCE} \
  --location=global || true

# 2. delete IAM access policy
gcloud -q iam access-policies delete ${UAP_POLICY_NAME} \
  --project=${PROJECT_GOVERNANCE} \
  --location=global || true

4. מחיקת Agent Gateway וכללי מדיניות האבטחה

# 1. delete authorization policy
gcloud beta network-security authz-policies delete ${AGW_NAME}-authz-policy-profile-iap \
  --location=${REGION} \
  --project=${PROJECT_GOVERNANCE} --quiet || true

# 2. delete authorization extension
gcloud service-extensions authz-extensions delete ${AGW_NAME}-svc-ext-authz-iap \
  --location=${REGION} \
  --project=${PROJECT_GOVERNANCE} --quiet || true
# 3. delete agent gateway
gcloud network-services agent-gateways delete ${AGW_NAME} \
  --project=${PROJECT_GOVERNANCE} \
  --location=${REGION} --quiet || true

5. הסרת קישורי IAM ותפקיד בהתאמה אישית בין פרויקטים

# 1. remove custom role and network viewer bindings for spoke service agents
for NUM in "${PROJECT_NUMBER_CONCIERGE}" "${PROJECT_NUMBER_SELLERS}"; do
  SA="service-${NUM}@gcp-sa-aiplatform.iam.gserviceaccount.com"
  
  gcloud projects remove-iam-policy-binding ${PROJECT_GOVERNANCE} \
    --member="serviceAccount:${SA}" \
    --role="projects/${PROJECT_GOVERNANCE}/roles/ar_agw_cross_project_sa" --quiet || true

  gcloud projects remove-iam-policy-binding ${PROJECT_GOVERNANCE} \
    --member="serviceAccount:${SA}" \
    --role="roles/networkservices.viewer" --quiet || true
done
# 2. remove registry viewer permissions across both spoke projects
for NUM in "${PROJECT_NUMBER_CONCIERGE}" "${PROJECT_NUMBER_SELLERS}"; do
  for MEMBER in \
    "serviceAccount:service-${NUM}@gcp-sa-aiplatform.iam.gserviceaccount.com" \
    "serviceAccount:service-${NUM}@gcp-sa-aiplatform-re.iam.gserviceaccount.com" \
    "serviceAccount:${NUM}-compute@developer.gserviceaccount.com" \
    "principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${NUM}"; do
      gcloud projects remove-iam-policy-binding ${PROJECT_GOVERNANCE} \
        --member="${MEMBER}" \
        --role="roles/agentregistry.viewer" --quiet || true
  done
done
# 3. remove project viewer permissions
for MEMBER in \
  "serviceAccount:${PROJECT_NUMBER_CONCIERGE}-compute@developer.gserviceaccount.com" \
  "serviceAccount:service-${PROJECT_NUMBER_CONCIERGE}@gcp-sa-aiplatform.iam.gserviceaccount.com"; do
    gcloud projects remove-iam-policy-binding ${PROJECT_GOVERNANCE} \
      --member="${MEMBER}" \
      --role="roles/viewer" --quiet || true
done
# 4. remove spoke-to-spoke delegation in Sellers project
for MEMBER in \
  "serviceAccount:service-${PROJECT_NUMBER_CONCIERGE}@gcp-sa-aiplatform.iam.gserviceaccount.com" \
  "serviceAccount:service-${PROJECT_NUMBER_CONCIERGE}@gcp-sa-aiplatform-re.iam.gserviceaccount.com" \
  "serviceAccount:${PROJECT_NUMBER_CONCIERGE}-compute@developer.gserviceaccount.com" \
  "principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJECT_NUMBER_CONCIERGE}"; do
    gcloud projects remove-iam-policy-binding ${PROJECT_SELLERS} \
      --member="${MEMBER}" \
      --role="roles/aiplatform.user" --quiet || true
done
# 5. delete custom IAM role after all bindings have been unlinked
gcloud iam roles delete ar_agw_cross_project_sa \
  --project=${PROJECT_GOVERNANCE} --quiet || true

אם הקציתם את התפקידים roles/iam.accessPolicyAdmin ו-roles/resourcemanager.projectIamAdmin במהלך שלב ההגדרה, הסירו אותם מחשבון המשתמש הפעיל כדי לשחזר את ההרשאות המינימליות:

# 6. remove Access Policy Admin and Project IAM Admin roles from user
for ROLE in "roles/iam.accessPolicyAdmin" "roles/resourcemanager.projectIamAdmin"; do
  gcloud projects remove-iam-policy-binding ${PROJECT_GOVERNANCE} \
    --member="user:$(gcloud config get-value account)" \
    --role="${ROLE}" \
    --condition=None --quiet || true
done

6. ביטול השינויים ביומני הביקורת ובאילוצים של מדיניות הארגון

# 1. Export current Central Governance IAM policy
gcloud projects get-iam-policy ${PROJECT_GOVERNANCE} --format=json > cfg/gov_iam_policy.json
# 2. Filter out iap.googleapis.com from auditConfigs
python3 -c "
import json
with open('cfg/gov_iam_policy.json') as f:
    policy = json.load(f)

if 'auditConfigs' in policy:
    # Remove iap.googleapis.com; if nothing else remains, clear the list
    policy['auditConfigs'] = [
        ac for ac in policy['auditConfigs'] if ac.get('service') != 'iap.googleapis.com'
    ]

with open('cfg/gov_iam_policy.json', 'w') as f:
    json.dump(policy, f, indent=2)
"
# 3. Apply the updated policy to revert audit logging to default
gcloud projects set-iam-policy ${PROJECT_GOVERNANCE} cfg/gov_iam_policy.json

7. ביטול האילוצים של מדיניות הארגון

# revert iam v3 access policy binding org policy on project to org level setting
gcloud org-policies delete iam.managed.disableAccessPolicyBinding --project=${PROJECT_GOVERNANCE}

8. מחיקת קטגוריית ה-Staging המשותפת ב-GCS ופריטי המידע המקומיים שנוצרו בתהליך הפיתוח

# delete central staging bucket
gcloud storage rm -r gs://${PROJECT_GOVERNANCE}-shared-staging
# remove local configuration manifests, environment files, and application
rm -rf cfg/ cross-project-multiagent/ *.env

בזה מסתיים החלק של הניקוי… השלב הבא הוא סיכום.

12. סיכום

מעולה! פרסתם וניהלתם ארכיטקטורה של סוכן AI לסוכן AI (A2A) בכמה פרויקטים ב-Google Cloud באמצעות Vertex AI Agent Runtime,‏ Central Agent Gateway,‏ Agent Registry וכללי מדיניות גישה מאוחדת (UAP) של IAM.

סיכום של מושגי מפתח

  • היקף מרכזי של תעבורת נתונים יוצאת: קונטיינרים של סביבות זמן ריצה של Spoke מנותבים (PROJECT_CONCIERGE, PROJECT_SELLERS) דרך Agent Gateway מרכזי ב-PROJECT_GOVERNANCE באמצעות agentGatewayConfig.
  • ‫Declarative Governance (UAP): החלפנו את הקישורים המפוצלים לכל משאב במדיניות גישה אחת של IAM שניתנת לביקורת, ומוערכת בשער על ידי IAP v2.
  • זהות קריפטוגרפית: אכיפת הרשאות מינימליות לתעבורת נתונים יוצאת באמצעות זהויות SPIFFE של קונטיינרים (principal://...) במקום מפתחות לטווח ארוך.
  • זיהוי שירותים דינמי: פתרון נקודות קצה של סוכנים מקבילים בזמן הריצה באמצעות Central Agent Registry, בלי צורך בכתובות URL ובמזהי פרויקטים בתוך הקוד.
  • גמישות של מדיניות זמן הריצה: העברנו את pizza-seller-agent מ"דחייה כברירת מחדל" (403 Forbidden) ל"מותר" (200 OK) בזמן אמת באמצעות עדכון מדיניות, בלי להפעיל מחדש את הקונטיינר.

cosmopup

Cosmopup אומר: "סוכנים הם נהדרים – הם עושים את כל העבודה בין הפרויקטים בזמן שאני מתמקד במטרה העיקרית שלי: לישון!"

השלבים הבאים ומסמכי תיעוד