إدارة مركزية في Agent Gateway باستخدام Agent Registry على مستوى المشاريع لبيئة تشغيل الوكيل

1. مقدمة

مع اعتماد المؤسسات الكبيرة على الذكاء الاصطناعي التوليدي، تتطوّر البُنى بسرعة من روبوتات دردشة مستقلة وموحّدة إلى أنظمة موزّعة متعددة الوكلاء (من وكيل إلى وكيل / A2A). في هذه التصاميم الحديثة، تنسّق وكلاء التنسيق الرفيع المستوى مهام سير العمل المعقّدة في المؤسسة من خلال تفويض المهام إلى وكلاء عاملين متخصصين في المجال وخوادم أدوات بروتوكول Model Context Protocol (MCP) وقواعد بيانات المؤسسة الخلفية في جميع مشاريع Google Cloud المستقلة.

ومع ذلك، فإنّ تشغيل أنظمة متعددة الوكلاء على نطاق واسع يطرح تحديات مهمة على مستوى الأمان والإدارة والتشغيل، وهي:

  • انتشار الأدوات و"الوكلاء الخفيون": عندما تنشر فِرق التطوير وكلاء في مشاريع معزولة بدون قائمة مركزية، تفقد المؤسسات إمكانية الاطّلاع على الأدوات والوكلاء الفرعيين المتوفّرين.
  • الخروج غير المراقب من المشاريع: يؤدي السماح للوكلاء بمسارات شبكة مباشرة وغير خاضعة للفحص إلى حدوث مخاطر استخراج البيانات وتجاوز حدود الأمان.
  • عمليات الدمج المرمّزة ثابتةً وغير المرنة: يؤدي الترميز الثابت لعناوين URL الخاصة بالوكيل في اتجاه المصب وأرقام تعريف محرك الاستدلال إلى إنشاء تبعيات غير مرنة تتوقف أثناء عمليات الترقية أو إعادة النشر.
  • عدم توفّر هوية بأقل امتيازات: لا توفّر حسابات الخدمة المشتركة إمكانية إثبات صحة التشفير على مستوى مثيل الوكيل الفردي.

لحلّ هذه التحديات، توفّر منصة وكيل Gemini Enterprise مستوى تحكّم موحّدًا في الحوكمة والاتصال يتألف من أربع ركائز أساسية:

  1. بوابة الوكيل (networkservices.googleapis.com): هي خادم وكيل مُدار ومحلي لفرض السياسات على الشبكة. يعمل هذا الوكيل في وضع الخروج AGENT_TO_ANYWHERE، ويعترض زيارات الوكيل الصادرة، ويفوّض عمليات تقييم الأذونات إلى إضافات الأمان، ويوجه الطلبات عبر حدود المشروع.
  2. سجلّ الوكلاء (agentregistry.googleapis.com): هو فهرس خدمات المؤسسة الفردي. يوفر هذا النظام دليلاً مركزيًا معتمَدًا لجميع الأدوات وخوادم MCP وعملاء النظراء المتاحين في جميع أنحاء المؤسسة، ما يتيح الاكتشاف التلقائي الديناميكي في وقت التشغيل بدون أي نقاط نهاية مبرمَجة.
  3. إدارة هوية الوكيل والإذن بالوصول إلى الإصدار 2 (iap.googleapis.com وiam.googleapis.com): إطار عمل مشفّر لإدارة الهوية وإذن الوصول. تتلقّى عوامل التنفيذ أرقام تعريف الموارد الموحّدة (URN) الفريدة والمصدّقة الخاصة بأجهزة SPIFFE (principal://...). يتم تقييم حركة الخروج الصادرة استنادًا إلى سياسات الوصول الموحّد (UAP / IAP v2) لإدارة الهوية وإمكانية الوصول المركزية التي تتحقّق من الإذن العام iap.googleapis.com/resources.egressViaIAP باستخدام شروط كتالوج Common Expression Language (CEL) الغنية (destination.agent_registry.*).
  4. بيئة تشغيل الوكيل (محركات الاستدلال): هي منصة تنفيذ مُدارة بالكامل وبدون خادم للتطبيقات المستندة إلى Python، وتتضمّن عمليات ربط الإعدادات الأصلية (agent_gateway_config) ببوابات مركزية.

سيناريو Codelab للأعمال: شراء الأطعمة والمشروبات في مشاريع متعددة

في هذا الدرس التطبيقي حول الترميز، ستنشئ منظومة متكاملة للشراء في مشاريع متعددة وتديرها، وتشمل ثلاثة مشاريع مختلفة على Google Cloud:

  • مشروع الإدارة المركزية (PROJECT_GOVERNANCE): تملكه أقسام تكنولوجيا المعلومات المركزية وعمليات الأمان، ويستضيف بوابة الوكيل المركزي وسجل الوكيل المركزي وسياسات الوصول الموحَّدة لإدارة الهوية وإمكانية الوصول.
  • مشروع Consumer Orchestrator (PROJECT_CONCIERGE): تملكه "فريق المشتريات"، ويستضيف وكيل شراء (Concierge) الذي يعثر ديناميكيًا على البائعين ويوجه طلبات العملاء.
  • مشروع مورّد النطاق (PROJECT_SELLERS): يملكه مورّدون خارجيون أو مورّدون تابعون لأقسام أخرى، ويستضيف وكيل بائع البرغر ووكيل بائع البيتزا.

figure1

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

لماذا الحوكمة المركزية على مستوى عدة مشاريع؟

في المؤسسات الكبيرة، تنشئ فِرق المنتجات ومجموعات علوم البيانات وكلاء الذكاء الاصطناعي في عشرات مشاريع Google Cloud المستقلة. يؤدي منح كل فريق إمكانية التحكّم المباشر في تسجيل الأدوات ومسارات شبكة الخروج وضوابط الأمان إلى انتشار الأدوات غير المُدقَّقة، وسياسات "منع فقدان البيانات" غير المتسقة، وعمليات الخروج من السحابة الافتراضية الخاصة غير الخاضعة للمراقبة، وسجلات التدقيق المجزأة.

تتيح الحوكمة المركزية على مستوى المشاريع فصل عملية إنشاء السياسات عن تنفيذ الوكيل:

  • تضع فِرق تكنولوجيا المعلومات المركزية وعمليات الأمان سياسات الأمان، وتتحقّق من الأدوات، وتراقب عمليات نقل البيانات خارج المؤسسة ضمن مشروع إدارة مركزية واحد.
  • تركّز فرق المنتجات والتطبيقات بشكل كامل على منطق النشاط التجاري في مشاريع وقت تشغيل الوكيل المستقلة، مع الربط مباشرةً ببوابة مركزية بدون عبء تشغيلي لإدارة شبكات VPC المحلية أو عمليات الربط البيني أو محركات السياسات المجزأة.

figure2

الشكل 2. بنية وحدود الحوكمة الثلاثية المستويات على مستوى المشاريع

نموذج تحديد نطاق الهوية ذو المستويين في سياسات الوصول الموحَّدة

عندما تتواصل البرامج مع "بوابة الوكيل المركزي"، تقيّم خدمة Identity-Aware Proxy (الإصدار 2) أذونات الوصول استنادًا إلى هوية البرنامج الخاصة بالمتصل، وهي هوية مستندة إلى SPIFFE ومصدّقة تشفيرًا ويتم إصدارها تلقائيًا لحاوية وقت التشغيل، وذلك مقارنةً بسياسة الوصول العالمية لإدارة الهوية وإمكانية الوصول:

  • المستوى 1: واجهات Google Cloud APIs الأساسية (الوصول المحدود من خلال principalSet:// في القاعدة 1): إذن خروج على مستوى المشروع يسمح لجميع أوقات تشغيل الوكيل في جميع المشاريع الفرعية بالوصول إلى واجهات Google APIs العادية (aiplatform وiamcredentials وtelemetry وagentregistry) من أجل الاكتشاف وإنشاء الرموز المميزة والاستنتاج.
  • المستوى 2: أدوات الأنشطة التجارية وخدمات التطبيق إلى التطبيق (التحكّم الدقيق من خلال principal:// في القاعدة 2 والقاعدة 3): وصول صارم بأقل امتيازات مرتبط بمثيلات فردية من "محرك الاستدلال"، ويتم فرضه باستخدام شروط "لغة التعبير العادي" (CEL) التي تستهدف خدمات محدّدة مسجّلة في "سجلّ الوكلاء" (destination.agent_registry.agent.name).

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

  • Centralized Agent Gateway (centralized-agw) في PROJECT_GOVERNANCE
  • إضافة خدمة التفويض في الإصدار 2 من IAP وسياسة التفويض في وضع "التنفيذ الصارم" (failOpen: false)
  • سياسة الوصول الموحّدة الأساسية في "إدارة الهوية وإمكانية الوصول" (uap-rules.json) وربط السياسات بالمشاريع
  • أذونات إدارة الهوية وإمكانية الوصول لوكيل الخدمة على مستوى المشاريع (ar_agw_cross_project_sa)
  • حزمة مرحلية مركزية مشتركة في Google Cloud Storage (GCS)
  • Isolated Burger and Pizza Seller Agents in PROJECT_SELLERS
  • وكيل شراء (Concierge) مع ميزة الاكتشاف التلقائي الديناميكي لخدمة REST في PROJECT_CONCIERGE
  • عمليات تسجيل الخدمات في Central Agent Registry باستخدام عناوين URL لبروتوكول أمان النقل المتبادل (mTLS) على مستوى المشاريع
  • تعديلات على سياسات الخروج في الإصدار 2 من Dynamic IAP مع عمليات التحقّق المباشر وعمليات التدقيق في Cloud Logging

figure3

الشكل 3. تسلسل التنفيذ المفصّل

ما ستتعلمه

  • كيفية ضبط أذونات "إدارة الهوية وإمكانية الوصول" لوكيل الخدمة على مستوى المشاريع في البوابات المركزية
  • كيفية توجيه حركة الخروج من Agent Runtime من خلال Agent Gateway مركزي على مستوى بيئات المشاريع المتعدّدة
  • كيفية تفويض إذن Agent Gateway إلى Identity-Aware Proxy (الإصدار 2 من IAP) باستخدام "إضافات الخدمة" (iapPolicyVersion: "V2")
  • كيفية إنشاء سياسات الوصول الموحّد (UAP) في "إدارة الهوية وإمكانية الوصول" وربطها بقواعد "لغة التعبير العادي" (CEL) التي تحكم وجهات "سجلّ الوكلاء" المسجّلة (destination.agent_registry.*)
  • كيفية إزالة معرّفات الوكيل وعناوين URL المرمّزة ثابتًا باستخدام الاكتشاف التلقائي في وقت التشغيل مقابل "سجلّ الوكلاء"
  • كيفية اختبار الحظر الفعلي للوصول بدون ثقة إلى المحيط (HTTP 403 Forbidden) والتحقّق من تعديلات السياسة المباشرة في Cloud Logging

ما تحتاج إليه

  • ‫3 مشاريع على Google Cloud تم تفعيل الفوترة فيها:
    • PROJECT_GOVERNANCE: الإدارة المركزية والبوابة والسجل وسياسات الوصول إلى "إدارة الهوية وإمكانية الوصول"
    • PROJECT_CONCIERGE: وكيل تنسيق خدمة الاستقبال والإرشاد المتعلقة بالشراء
    • PROJECT_SELLERS: وكلاء متخصصون في بيع البرغر والبيتزا
  • مستخدم أو حساب خدمة في "إدارة الهوية وإمكانية الوصول" لديه أذونات roles/owner أو أذونات إدارية في جميع المشاريع الثلاثة
  • مؤسسة Google Cloud (لتحديد نطاق الثقة في SPIFFE)
  • ‫Google Cloud Shell أو جهاز محلي مثبَّت عليه gcloud CLI وpython (الإصدار 3.11 أو إصدار أحدث) وuv

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

2. الإعداد

على الرغم من أنّ هذه البنية تمتدّ على 3 مشاريع مختلفة على Google Cloud، يمكنك تنفيذ% 100 من أوامر نشر الجهاز الطرفي وعمليات تنزيل المستودع وعمليات الإعداد من وحدة طرفية واحدة في Cloud Shell تم ضبطها على PROJECT_GOVERNANCE. يستهدف كل نص برمجي للنشر وأمر gcloud المشروع الوجهة المناسب بشكل صريح من خلال علامات واجهة سطر الأوامر (--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

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

أدخِل المعرّفات الخاصة بمشروعك.

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

سيتم استنتاج متغيرات shell هذه تلقائيًا.

# 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

تعيين دور "مشرف سياسة الوصول" لسياسات الوصول الموحّدة

# 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 الإصدار 2

توقف 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)"

تفعيل واجهات Google Cloud APIs المطلوبة

# 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

التحقّق من تفعيل واجهات برمجة التطبيقات في جميع المشاريع

يضمن تفعيل واجهات برمجة التطبيقات نفسها في جميع المشاريع الثلاثة (PROJECT_GOVERNANCE وPROJECT_CONCIERGE وPROJECT_SELLERS) تحقيق اتساق تشغيلي ويمنع حدوث أخطاء في إنشاء الرموز المميزة في وقت التشغيل أو أخطاء في تصنيف المخططات أو حالات توقّف القياس عن بُعد.

نفِّذ نص التحقّق التالي في Cloud Shell للتأكّد من تطابق واجهات برمجة التطبيقات في جميع المشاريع الثلاثة:

# 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

مثال على نتيجة التحقّق:

من المفترض أن تظهر لك جميع واجهات برمجة التطبيقات المفعّلة.

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

ضبط سياسات المؤسسة

تفرض سياسات المؤسسة التلقائية في Google Cloud قيودًا تحصر ربط سياسات الوصول في الإصدار 3 من "إدارة الهوية وإمكانية الوصول" (IAM) بالموارد (constraints/iam.managed.disableAccessPolicyBinding).

تجاوز أي قيود مفروضة على مستوى المشروع من خلال سياسة المؤسسة المكتسبة عن طريق ضبط enforce: false على "السماح" بشكل صريح.

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

3- Agent Registry

تسجيل خدمة نقطة نهاية لواجهات Google APIs الأساسية

يتطلّب Agent Gateway تسجيل عناوين URL الخاصة بواجهات Google API في "سجلّ الوكلاء المركزي" (Central Agent Registry) حتى تتمكّن الوكلاء الذين تمّت تهيئتهم باستخدام agent_gateway_config من توجيه حركة الخروج بشكل آمن إلى خدمات الخلفية الأساسية في Google Cloud (مثل aiplatform وIAM Credentials وTelemetry).

إنشاء core-gapi-services في "قاعدة بيانات الوكلاء"

# 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://iamcredentials.googleapis.com \
  --interfaces=protocolBinding=JSONRPC,url=https://iamcredentials.mtls.googleapis.com \
  --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

معرّف مورد نقطة النهاية لواجهات Capture Core APIs

# 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 في "هوية الوكيل"

في Google Cloud IAM وGemini Enterprise Agent Platform، تستخدم هويات الآلات الصادرة إلى حاويات الوكيل المنفِّذ معرّفات موارد موحّدة (URN) من SPIFFE تم إثبات صحتها بشكلٍ مشفّر وتقييمها من خلال خدمة Identity-Aware Proxy (الإصدار 2). عند إعداد "سياسات الوصول الموحّدة" في "إدارة الهوية وإمكانية الوصول"، يمكنك استهداف principal واحد محدّد أو principalSet مستند إلى السمات:

السمة

principal:// (هوية جهاز واحد)

principalSet:// (مجموعة مستندة إلى سمات)

بنية IAM

principal://...

principalSet://...

مستوى التفاصيل

دقيق (على مستوى المثيل): يحدّد مثيلاً واحدًا ومحدّدًا لحاوية Reasoning Engine.

التصنيف العام (على مستوى المشروع): يحدّد جميع محركات الاستدلال التي تشترك في سمة مشروع مشتركة.

نمط 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 (core-gapi-services).

التأثير في مراحل النشاط

في حال حذف وكيل وإعادة إنشائه، يتطلّب معرّف المحرك الجديد ربطًا معدَّلاً لسياسة إدارة الهوية وإمكانية الوصول (IAM).

يتم تطبيقه تلقائيًا على العملاء الافتراضيين الذين تم نشرهم حديثًا في هذا المشروع بدون إجراء أي تعديلات إضافية على إدارة الهوية وإمكانية الوصول.

الحوكمة التعريفية باستخدام سياسات الوصول الموحّدة (UAP / IAP v2)

في الإصدار القديم 1 من IAP، تم ربط سياسات الخروج مباشرةً بموارد "سجلّ الوكلاء" الفردية باستخدام gcloud beta iap web add-iam-policy-binding. ضمن IAP الإصدار 2 وسياسات الوصول الموحّدة، يتم إلغاء عمليات الربط على مستوى كل مورد لصالح سياسة وصول واحدة ومركزية لإدارة الهوية وإمكانية الوصول (cfg/uap-rules.json).

سيتم ضبط إذن الخروج الأساسي لـ core-gapi-services على أنّه القاعدة 1 في "سياسة الوصول الموحّدة" في القسم 5، ما يضمن توفّر مسارات الخروج الأساسية لجميع حاويات الوكيل قبل النشر.

للحصول على تفاصيل فنية أعمق حول معرّفات الجهات الرئيسية وآليات تحديد هوية أحمال العمل، يُرجى الاطّلاع على ما يلي:

بهذا نكون قد انتهينا من تسجيل نقطة نهاية واجهات برمجة التطبيقات الأساسية، وسننتقل الآن إلى قسم نشر بوابة الوكيل المركزية.

4. Agent Gateway

نشر Agent Gateway مركزي

انشر Agent Gateway (centralized-agw) المركزي في وضع الخروج 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

استيراد إعدادات "بوابة الوكيل"

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

تأكيد تفاصيل بوابة الوكيل

# 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- التفويض

ضبط أذونات الوصول إلى بوابة الوكيل وUAP الأساسي

تؤمّن "بوابة الوكيل" حركة بيانات الأدوات والوكلاء الصادرة وتتحكّم فيها باستخدام سياسات التفويض (networksecurity.authzPolicies) المدمجة مع سياسات الوصول الموحّدة (UAP) في Identity-Aware Proxy (الإصدار 2).

نظرة عامة على بنية نظام منح الأذونات

figure4

الشكل 4. نظرة عامة على بنية التفويض

تتألف بنية التفويض من ثلاث طبقات مترابطة:

  1. إضافة خدمة IAP (authzExtension): مورد إقليمي تم إعداده باستخدام service: iap.googleapis.com وmetadata: iapPolicyVersion: "V2" وfailOpen: false لفرض نموذج أمان الثقة المعدومة الصارم.
  2. سياسة تفويض البوابة (authzPolicy): استهداف الموارد الإقليمية لبوابة الوكيل باستخدام policyProfile: REQUEST_AUTHZ وaction: CUSTOM، وتوجيه عمليات التحقّق من التفويض إلى إضافة IAP Authz.
  3. سياسة الوصول الموحّدة في "إدارة الهوية وإمكانية الوصول" والربط (accessPolicy وpolicyBinding): يتم تقييم مورد الإصدار 3 من "إدارة الهوية وإمكانية الوصول" العالمي من خلال خدمة IAP. تتحقّق هذه الخدمة من الإذن العام iap.googleapis.com/resources.egressViaIAP مقارنةً بهويات SPIFFE الخاصة بالمتصل وشروط كتالوج CEL.

الخطوة 1: إنشاء واستيراد إضافة IAP v2 Authz

أنشئ بيان "إضافة الخدمة" باستخدام 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: إنشاء سياسة تفويض البوابة واستيرادها

أنشئ إعدادات "سياسة التفويض" التي يتم إرفاقها ببوابة الوكيل وتفويض عملية التحقّق من الطلب إلى إضافة IAP Authz:

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

أنشئ 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) باتّباع الخطوات التالية:

# 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. إدارة الهوية وإمكانية الوصول على مستوى المشاريع

ضبط أذونات إدارة الهوية وإمكانية الوصول على مستوى المشاريع

في تصميم الأنظمة المتعددة المشاريع هذا، تقيم بيئات تشغيل الوكيل في مشاريع فرعية (PROJECT_CONCIERGE وPROJECT_SELLERS)، بينما يقيم كل من "بوابة الوكيل المركزية" و"سجلّ الوكيل" في PROJECT_GOVERNANCE.

بما أنّ مشاريع Google Cloud هي حدود أمان معزولة، يجب منح إذن الوصول إلى المشاريع بشكل صريح على مستوى طبقتَين تشغيليتَين:

  1. Control Plane (وقت النشر): عند نشر حاوية وكيل تم إعدادها باستخدام --agent-gateway-config، يجب أن يربط وكيل خدمة وقت تشغيل الوكيل (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 لتنفيذ طلبات البحث في محركات الاستدلال الخاصة بالبائع.

إنشاء دور مخصّص لإدارة الهوية وإمكانية الوصول في 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"

منح دور مخصّص لوكلاء خدمة "بيئة تشغيل الوكيل"

# 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

بهذا نكون قد انتهينا من إعداد "إدارة الهوية وإمكانية الوصول" على مستوى المشاريع المختلفة، وسننتقل الآن إلى قسم نشر وكلاء البائعين ووكلاء خدمة العملاء.

7. بيئة تشغيل الوكيل

نشر وكلاء البائعين ووكلاء خدمات الاستقبال والإرشاد

يتم الاحتفاظ بقاعدة رموز تطبيق الوكلاء المتعددين وبرامج النشر المستخدَمة في هذا الدرس التطبيقي حول الترميز في مستودع Google Cloud GitHub بعيد. ستؤدي الخطوات التالية إلى استنساخ المستودع محليًا ونسخ الملفات اللازمة إلى بنية دليل العمل الحالي وتنظيف الملفات المؤقتة وتثبيت التبعيات باستخدام uv.

استرداد البيانات عن بُعد

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

إنشاء حزمة تخزين مركزية مشترَكة

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

طريقة عمل ربط "بوابة الوكيل" بين المشاريع

في هذه الخطوة، ستنشر "وكلاء البائع" في مشروع المنطقة الفرعية (PROJECT_SELLERS) مع ضبط إعداداتهم لتوجيه حركة الخروج من خلال "بوابة الوكيل المركزي" في 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 تم وضعها في وقت سابق في "سياسة الوصول الموحّد"، يُسمح بطلبات تهيئة الحاوية إلى Cloud APIs في Google Cloud من خلال البوابة بدون انقطاع.

نشر وكلاء Burger & Pizza Seller إلى 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

نشر وكيل Purchasing Concierge إلى 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}'

يجب أن يعرض الناتج هوية وقت تشغيل وكيل Concierge والمشروع وعملية الربط ببوابة وكيل مشروع Governance.

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

سجِّل جميع الوكلاء الثلاثة في "سجلّ الوكلاء المركزي" في 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.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
# 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.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
# 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.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

التقاط أرقام تعريف سجلّ الوكيل الأساسي

# 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

ضبط سياسات الخروج من تطبيق إلى تطبيق في "سياسة الوصول الموحّدة"

ضمن بنية الرفض التلقائي في Agent Gateway في وضع فرض صارم:

  1. القاعدة 1 (واجهات برمجة التطبيقات الأساسية في Google Cloud): تسمح لحاويات الوكيل في جميع المشاريع الثلاثة بالوصول إلى core-gapi-services.
  2. القاعدة 2 (وكيل بائع البرغر: السماح): تسمح هذه القاعدة لمثيل وكيل شراء (Concierge) باستدعاء وكيل بائع البرغر على وجه التحديد.
  3. وكيل بائع البيتزا (مرفوض تلقائيًا): تم استبعاده عمدًا من قواعد السياسة. في وضع ENFORCE (failOpen: false)، سيتم على الفور إنهاء أي محاولة من Concierge لاستدعاء Pizza Seller عند محيط البوابة باستخدام HTTP 403 Forbidden.

صياغة هوية وكيل 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

أنشئ cfg/uap-rules-update-2.json جديدًا يتضمّن القاعدة 1 (واجهات برمجة التطبيقات الأساسية) والقاعدة 2 (وكيل بائع البرغر):

# create addendum to update policy manifest with Rule 2 for Burger Agent
cat > cfg/uap-rules-update-2.json << EOF
[
  {
    "description": "Rule 2: Allow Purchasing Concierge to invoke Burger 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/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

تطبيق سياسة الوصول المعدَّلة

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

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

# 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) بين المشاريع في "ملعب الذكاء الاصطناعي لوقت تشغيل الوكيل"، وستراقب الحظر الفعلي HTTP 403 Forbidden على المحيط في الوضع ENFORCE الصارم، وستعدّل "سياسة الوصول الموحّدة" مباشرةً، وستتحقّق من صحة الموافقة الفورية على الطلب.

الخطوة 1: فتح Agent Runtime AI Playground في PROJECT_CONCIERGE

  1. افتح Google Cloud Console.
  2. في شريط اختيار المشروع في أعلى الصفحة، انتقِل إلى PROJECT_CONCIERGE.
  3. في قائمة التنقّل، انتقِل إلى Agent Platform > Agents > Deployments.
  4. انقر على purchasing-concierge-adk.
  5. انقر على ملعب الذكاء الاصطناعي لفتح واجهة المحادثة التفاعلية على يسار الشاشة.

الخطوة 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. الاكتشاف الديناميكي: أثناء بدء الجلسة، استعلمت خدمة Purchasing Concierge من "سجلّ الوكلاء المركزي" في PROJECT_GOVERNANCE (عبر core-gapi-services من خلال Agent Gateway المصرّح به بموجب القاعدة 1) لاكتشاف نقطة نهاية mTLS الإقليمية لـ burger-seller-agent.
  2. حلّ النية واستدعاء A2A: يحلّل Gemini داخل "وكيل الشراء" نية طلب الطعام ويستدعي "وكيل بائع البرغر" من خلال إجراء عن بُعد صادر إلى https://${REGION}-aiplatform.mtls.googleapis.com/.../reasoningEngines/${BURGER_ENGINE_ID}.
  3. اعتراض البوابة ونشر معرّف SPIFFE: يتم تسجيل حركة الخروج من خلال agent_gateway_config وتوجيهها إلى "بوابة الوكيل المركزي" في PROJECT_GOVERNANCE، مع تضمين هوية Concierge المشفّرة لمعرّف SPIFFE (principal://...).
  4. تقييم سياسة IAP v2: تستدعي Central Agent Gateway إضافة تفويض IAP (authzExtension). تقيّم IAP v2 القاعدة 2 في سياسة الوصول الموحّدة لإدارة الهوية وإمكانية الوصول. بما أنّ المتصل يتطابق مع ${CONCIERGE_SPIFFE_PRINCIPAL} والهدف يتطابق مع burger-seller-agent، تعرض واجهة برمجة التطبيقات داخل التطبيق ALLOW (granted: true).
  5. التنفيذ على مستوى مشاريع متعددة: يرسل Agent Gateway الطلب المفوّض على مستوى مشاريع متعددة إلى PROJECT_SELLERS، حيث يعالج Burger Seller Reasoning Engine الطلب ويعرض تأكيدًا.

الردّ المتوقّع:

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 الإصدار 2 (HTTP 200 / ALLOWED)

سجلات طلبات Query 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
  )"

يجب أن تسجّل السجلات حركة البيانات الصادرة من كلا مشروعي Spoke (PROJECT_CONCIERGE وPROJECT_SELLERS) مع حقول الخروج لطلبات الاستدلال من Gemini (generateContent) وقياس استخدام Cloud Trace (/v1/traces) وعمليات البحث عن بيانات اعتماد IAM، والتي يتم اعتراضها والسماح بها بشكل شفاف من خلال القاعدة 1 (core-gapi-services).

استخدِم طلب بحث في سجلّات الوصول إلى البيانات في Cloud Audit Data Access الإصدار 2 للتحقّق من إصدار السياسة 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. الاكتشاف الديناميكي: حلّت خدمة Purchasing Concierge نقطة النهاية pizza-seller-agent من "سجلّ الوكلاء المركزي" أثناء بدء التشغيل.
  2. حلّ النية واستدعاء A2A: يحاول Gemini داخل خدمة Purchasing Concierge إرسال طلب طلب البيتزا إلى نقطة نهاية Pizza Seller في PROJECT_SELLERS.
  3. اعتراض البوابة: يتم اعتراض طلب الإجراء عن بُعد الصادر من خلال agent_gateway_config وتوجيهه إلى "بوابة الوكيل المركزي".
  4. تقييم سياسة IAP v2 (الرفض التلقائي): تستدعي Central Agent Gateway سياسة IAP v2. بما أنّه لا توجد قاعدة في "سياسة الوصول الموحّدة" تطابق pizza-seller-agent، تعرض خدمة IAP الرمز DENY (granted: false).
  5. الحظر الصارم على مستوى المحيط: بما أنّ إضافة Authz في وضع التنفيذ (failOpen: false)، فإنّ بوابة الوكيل المركزي توقف على الفور الاتصال الصادر وتعرض 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

إجراء طلب بحث في سجلّات التدقيق في الوصول إلى البيانات في الإصدار 2 من IAP عن القرار المرفوض:

# 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: منح Pizza Agent إذن الوصول إلى بيانات الخروج بشكلٍ ديناميكي

أنشئ cfg/uap-rules-update-3.json جديدًا يتضمّن القاعدة 1 (واجهات برمجة التطبيقات الأساسية) والقاعدة 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. إعادة تحميل السياسة الديناميكية: يسري تعديل "سياسة الوصول الموحّدة" في "إدارة الهوية وإمكانية الوصول" على الفور في محرك تقييم "سياسة الوصول الموحّدة" في "إدارة الهوية وإمكانية الوصول" بدون أي وقت تعطل وبدون إعادة نشر أي حاويات.
  2. استدعاء A2A: يرسل Concierge الطلب من خلال Central Agent Gateway.
  3. تقييم سياسة الإصدار 2 من IAP (الموافقة): يتطابق الإصدار 2 من IAP مع القاعدة 3، ويتأكّد من هوية المتصل وتعبير CEL المستهدَف، ويعرض ALLOW (granted: true).
  4. التنفيذ على مستوى مشاريع متعددة: تعمل "بوابة الوكيل المركزي" كوكيل للزيارات المسموح بها إلى PROJECT_SELLERS، حيث يعالج "بائع البيتزا" الطلب.

الخطوة 8: فحص سجلّات Agent Gateway لطلبات البيتزا التي تمّت الموافقة عليها

# 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://us-central1-aiplatform.mtls.googleapis.com/v1beta1/projects/${PROJECT_SELLERS}/locations/us-central1/publishers/google/models/gemini-2.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 مقابل الموارد المستخدَمة في هذا الدرس التطبيقي حول الترميز، نفِّذ خطوات الإيقاف بترتيب عكسي صارم للتبعيات:

1. تنظيف عمليات نشر Clean Up Reasoning Engine

نفِّذ النص البرمجي 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- حذف ربط سياسة الوصول الموحّدة وسياسة الوصول في "إدارة الهوية وإمكانية الوصول"

# 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. حذف "بوابة الوكيل" وسياسات الأمان

# 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. حذف حزمة التخزين المؤقت المشتركة في "خدمة التخزين السحابي من Google" والنواتج المحلية

# 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. الخاتمة

تهانينا! لقد نشرت بنية متعددة المشاريع من نوع "وكيل إلى وكيل" (A2A) وأدرتها على Google Cloud باستخدام Vertex AI Agent Runtime وCentral Agent Gateway وAgent Registry و"سياسات الوصول الموحّدة" (UAP) في "إدارة الهوية وإمكانية الوصول" (IAM).

ملخّص المفاهيم الرئيسية

  • محيط الخروج المركزي: تم توجيه حاويات وقت التشغيل الخاصة بالعقدة الفرعية (PROJECT_CONCIERGE وPROJECT_SELLERS) من خلال "بوابة الوكيل" المركزية في PROJECT_GOVERNANCE باستخدام agentGatewayConfig.
  • الحوكمة التعريفية (UAP): تم استبدال عمليات الربط المجزّأة لكل مورد بسياسة وصول واحدة قابلة للتدقيق في "إدارة الهوية وإمكانية الوصول" يتم تقييمها عند البوابة من خلال الإصدار 2 من IAP.
  • الهوية التشفيرية: فرض أقل امتيازات للخروج باستخدام هويات SPIFFE للحاويات (principal://...) بدلاً من المفاتيح الطويلة الأمد
  • اكتشاف الخدمات الديناميكي: يتم حل نقاط نهاية وكيل الأقران في وقت التشغيل من خلال "سجلّ الوكلاء المركزي"، ما يؤدي إلى إلغاء عناوين URL وأرقام تعريف المشاريع المضمّنة.
  • مرونة سياسة وقت التشغيل: تم الانتقال pizza-seller-agent من "الرفض التلقائي" (403 Forbidden) إلى "مسموح به" (200 OK) في الوقت الفعلي من خلال تعديل السياسة، بدون إعادة تشغيل الحاوية.

cosmopup

تقول Cosmopup: "الوكلاء رائعون، فهم يتولّون كل العمل على مستوى المشاريع المختلفة بينما أركّز أنا على هدفي الأساسي: أخذ قيلولة!"

الخطوات التالية والمستندات