การกำกับดูแลแบบรวมศูนย์ของ Agent Gateway ด้วย Agent Registry แบบข้ามโปรเจ็กต์สำหรับ Agent Runtime

1. บทนำ

เมื่อองค์กรต่างๆ นำ Generative AI มาใช้ สถาปัตยกรรมก็พัฒนาอย่างรวดเร็วจากแชทบ็อตแบบโมโนลิธิกสแตนด์อโลนไปเป็นระบบ Multi-Agent แบบกระจาย (Agent-to-Agent/A2A) ในโทโพโลยีสมัยใหม่เหล่านี้ Agent ผู้จัดการระดับสูงจะประสานงานเวิร์กโฟลว์ทางธุรกิจที่ซับซ้อนโดยมอบหมายงานให้กับ Agent ผู้ปฏิบัติงานโดเมนเฉพาะทาง, เซิร์ฟเวอร์เครื่องมือ Model Context Protocol (MCP) และฐานข้อมูลองค์กรแบ็กเอนด์ในโปรเจ็กต์ที่อยู่ในระบบคลาวด์ของ Google ที่เป็นอิสระ

อย่างไรก็ตาม การใช้งานระบบ Multi-Agent ในวงกว้างทำให้เกิดความท้าทายที่สำคัญด้านความปลอดภัย การกำกับดูแล และการดำเนินงาน ดังนี้

  • Shadow Agent และการขยายตัวของเครื่องมือ: เมื่อทีมพัฒนาติดตั้งใช้งาน Agent ในโปรเจ็กต์ที่แยกต่างหากโดยไม่มีแคตตาล็อกแบบรวมศูนย์ องค์กรจะสูญเสียระดับการเข้าถึงเครื่องมือและ Agent ย่อยที่มีอยู่
  • การส่งข้อมูลขาออกข้ามโปรเจ็กต์ที่ไม่มีการตรวจสอบ: การอนุญาตให้ Agent ใช้เส้นทางเครือข่ายโดยตรงและไม่มีการตรวจสอบจะสร้างความเสี่ยงในการขโมยข้อมูลและข้ามขอบเขตการรักษาความปลอดภัย
  • การผสานรวมแบบฮาร์ดโค้ดที่เปราะบาง: การฮาร์ดโค้ด URL ของ Agent ปลายทางและรหัส Reasoning Engine จะสร้างทรัพยากร Dependency ที่เปราะบางซึ่งจะใช้งานไม่ได้ระหว่างการอัปเกรดหรือการติดตั้งใช้งานใหม่
  • การขาดข้อมูลประจำตัวที่มีสิทธิ์ขั้นต่ำที่สุด: บัญชีบริการที่ใช้ร่วมกันไม่สามารถให้การไม่ปฏิเสธความรับผิดในการเข้ารหัสที่ระดับอินสแตนซ์ของ Agent แต่ละรายการ

แพลตฟอร์ม Agent ของ Gemini Enterprise มีระนาบการควบคุมการกำกับดูแลและการเชื่อมต่อแบบรวมซึ่งประกอบด้วย 4 เสาหลักเพื่อแก้ปัญหาเหล่านี้ ดังนี้

  1. Agent Gateway (networkservices.googleapis.com): พร็อกซีการบังคับใช้นโยบายและเครือข่ายระดับภูมิภาคที่มีการจัดการ เมื่อทำงานในโหมดขาออก AGENT_TO_ANYWHERE จะสกัดกั้นการรับส่งข้อมูลขาออกของ Agent, มอบสิทธิ์การประเมินการให้สิทธิ์แก่ส่วนขยายความปลอดภัย และกำหนดเส้นทางคำขอข้ามขอบเขตโปรเจ็กต์
  2. Agent Registry (agentregistry.googleapis.com): แคตตาล็อกบริการระดับองค์กรแบบรวมศูนย์ โดยมีไดเรกทอรีแบบรวมศูนย์ที่ผ่านการตรวจสอบแล้วสำหรับเครื่องมือ, เซิร์ฟเวอร์ MCP และ Agent เพียร์ทั้งหมดที่มีอยู่ในองค์กร ซึ่งช่วยให้ค้นพบอัตโนมัติแบบรันไทม์แบบไดนามิกโดยไม่มีปลายทางที่ฮาร์ดโค้ด
  3. Agent Identity & IAP v2 Governance (iap.googleapis.com และ iam.googleapis.com): เฟรมเวิร์กข้อมูลประจำตัวและการเข้าถึงแบบเข้ารหัส เอเจนต์ที่ดำเนินการจะได้รับ URN ของเครื่อง SPIFFE ที่ได้รับการรับรองและไม่ซ้ำกัน (principal://...) ระบบจะประเมินการส่งข้อมูลขาออกเทียบกับนโยบายการเข้าถึงแบบรวมของ IAM (UAP / IAP v2) แบบรวมศูนย์ ซึ่งจะยืนยันสิทธิ์สากล iap.googleapis.com/resources.egressViaIAP โดยใช้เงื่อนไขแคตตาล็อก Common Expression Language (CEL) ที่สมบูรณ์ (destination.agent_registry.*)
  4. Agent Runtime (Reasoning Engine): แพลตฟอร์มการดำเนินการแบบ Serverless ที่มีการจัดการครบวงจรสำหรับแอปพลิเคชัน Agentic ที่ใช้ Python ซึ่งมีการเชื่อมโยงการกำหนดค่าแบบเนทีฟ (agent_gateway_config) กับเกตเวย์ส่วนกลาง

สถานการณ์ทางธุรกิจของ Codelab: การจัดซื้ออาหารและเครื่องดื่มแบบหลายโปรเจ็กต์

ใน Codelab นี้ คุณจะสร้างและควบคุมระบบนิเวศการจัดซื้อแบบหลายโปรเจ็กต์ในชีวิตจริงซึ่งครอบคลุมโปรเจ็กต์ที่อยู่ในระบบคลาวด์ Google Cloud 3 โปรเจ็กต์ที่แตกต่างกัน ดังนี้

  • โปรเจ็กต์การกำกับดูแลส่วนกลาง (PROJECT_GOVERNANCE): เป็นของฝ่ายไอทีส่วนกลางและ SecOps ซึ่งโฮสต์เกตเวย์ Agent ส่วนกลาง, Agent Registry ส่วนกลาง และนโยบายการเข้าถึงแบบรวมของ IAM
  • โปรเจ็กต์ Consumer Orchestrator (PROJECT_CONCIERGE): ทีมจัดซื้อเป็นเจ้าของโปรเจ็กต์นี้ ซึ่งโฮสต์ตัวแทนบริการด้านการซื้อที่ค้นหาผู้ให้บริการและกำหนดเส้นทางคำสั่งซื้อของลูกค้าแบบไดนามิก
  • โปรเจ็กต์ของผู้ให้บริการโดเมน (PROJECT_SELLERS): เป็นของบุคคลภายนอกหรือผู้ให้บริการของแผนก ซึ่งโฮสต์ Burger Seller Agent และ Pizza Seller Agent

figure1

รูปที่ 1 สถาปัตยกรรมการกำกับดูแลแบบรวมศูนย์หลายโปรเจ็กต์

เหตุใดจึงต้องมีการกำกับดูแลแบบรวมศูนย์ข้ามโปรเจ็กต์

ในองค์กรขนาดใหญ่ ทีมผลิตภัณฑ์และกลุ่มวิทยาศาสตร์ข้อมูลจะสร้าง AI Agent ในโปรเจ็กต์ Google Cloud ที่เป็นอิสระหลายสิบโปรเจ็กต์ การให้แต่ละทีมควบคุมการลงทะเบียนเครื่องมือ เส้นทางเครือข่ายขาออก และมาตรการป้องกันด้านความปลอดภัยโดยตรงจะทำให้เกิดการใช้เครื่องมือที่ยังไม่ผ่านการตรวจสอบอย่างไม่เป็นระเบียบ นโยบาย DLP ที่ไม่สอดคล้องกัน ขาออกของ VPC ที่ไม่มีการตรวจสอบ และบันทึกการตรวจสอบที่กระจัดกระจาย

การกำกับดูแลแบบรวมศูนย์ข้ามโปรเจ็กต์จะแยกการเขียนนโยบายออกจากการดำเนินการของ Agent ดังนี้

  • ทีมไอทีส่วนกลางและ SecOps จะเขียนนโยบายความปลอดภัย ตรวจสอบเครื่องมือ และตรวจสอบข้อมูลขาออกภายในโปรเจ็กต์การกำกับดูแลแบบรวมศูนย์เดียว
  • ทีมผลิตภัณฑ์และแอปพลิเคชันจะมุ่งเน้นที่ตรรกะทางธุรกิจเท่านั้นในโปรเจ็กต์รันไทม์ของ Agent ที่เป็นอิสระ โดยเชื่อมโยงกับเกตเวย์ส่วนกลางโดยตรงโดยไม่มีภาระงานด้านการดำเนินงานในการจัดการ VPC ในเครื่อง, Interconnect หรือเครื่องมือนโยบายที่กระจัดกระจาย

figure2

รูปที่ 2 สถาปัตยกรรมและขอบเขตการกำกับดูแลข้ามโปรเจ็กต์แบบ 3 ระดับ

โมเดลการกำหนดขอบเขตข้อมูลประจำตัวแบบ 2 ระดับในนโยบายการเข้าถึงแบบรวม

เมื่อ Agent สื่อสารผ่าน Central Agent Gateway แล้ว Identity-Aware Proxy (IAP v2) จะประเมินการเข้าถึงตามข้อมูลประจำตัวของ Agent ของผู้โทร ซึ่งเป็นข้อมูลประจำตัวที่อิงตาม SPIFFE และได้รับการรับรองด้วยการเข้ารหัสลับที่ออกให้กับคอนเทนเนอร์รันไทม์โดยอัตโนมัติ โดยเทียบกับนโยบายการเข้าถึง IAM ทั่วโลก ดังนี้

  • ระดับที่ 1: Google Cloud API พื้นฐาน (แบบหยาบผ่าน principalSet:// ในกฎที่ 1): การให้สิทธิ์ขาออกทั่วทั้งโปรเจ็กต์ที่อนุญาตให้รันไทม์ของ Agent ทั้งหมดในโปรเจ็กต์ Spoke เข้าถึง Google API มาตรฐาน (aiplatform, iamcredentials, telemetry, agentregistry) เพื่อการค้นพบ การสร้างโทเค็น และการอนุมาน
  • ระดับที่ 2: เครื่องมือทางธุรกิจและบริการ A2A (แบบละเอียดผ่าน principal:// ในกฎที่ 2 และ 3): การเข้าถึงแบบให้สิทธิ์ขั้นต่ำที่สุดที่เข้มงวดซึ่งเชื่อมโยงกับอินสแตนซ์ Reasoning Engine แต่ละรายการ โดยบังคับใช้ด้วยเงื่อนไข Common Expression Language (CEL) ที่กำหนดเป้าหมายไปยังบริการ Agent Registry ที่ลงทะเบียนไว้โดยเฉพาะ (destination.agent_registry.agent.name)

สิ่งที่คุณสร้าง

  • Centralized Agent Gateway (centralized-agw) ใน PROJECT_GOVERNANCE
  • ส่วนขยายบริการให้สิทธิ์และนโยบาย Authz ของ IAP v2 ในโหมดบังคับใช้ที่เข้มงวด (failOpen: false)
  • นโยบายการเข้าถึงแบบรวม IAM พื้นฐาน (uap-rules.json) และการเชื่อมโยงนโยบายโปรเจ็กต์
  • สิทธิ์ IAM ของตัวแทนบริการข้ามโปรเจ็กต์ (ar_agw_cross_project_sa)
  • Bucket การทดลองใช้ของ Google Cloud Storage (GCS) ส่วนกลางที่ใช้ร่วมกัน
  • ตัวแทนผู้ขายเบอร์เกอร์และพิซซ่าที่แยกกันใน PROJECT_SELLERS
  • ตัวแทนบริการด้านการซื้อที่มีการค้นหา REST อัตโนมัติแบบไดนามิกใน PROJECT_CONCIERGE
  • การลงทะเบียนบริการใน Central Agent Registry ด้วย URL ของ mTLS ข้ามโปรเจ็กต์
  • การอัปเดตนโยบายขาออกของ IAP v2 แบบไดนามิกพร้อมการยืนยันแบบเรียลไทม์และการตรวจสอบ Cloud Logging

figure3

รูปที่ 3 ลำดับการติดตั้งใช้งานแบบทีละขั้นตอน

สิ่งที่คุณจะได้เรียนรู้

  • วิธีกำหนดค่าสิทธิ์ IAM ของ Service Agent ข้ามโปรเจ็กต์สำหรับเกตเวย์แบบรวมศูนย์
  • วิธีกำหนดเส้นทางขาออกของ Agent Runtime ผ่าน Agent Gateway ส่วนกลางในสภาพแวดล้อมแบบหลายโปรเจ็กต์
  • วิธีมอบสิทธิ์การให้สิทธิ์ Agent Gateway แก่ Identity-Aware Proxy (IAP v2) โดยใช้ส่วนขยายบริการ (iapPolicyVersion: "V2")
  • วิธีเขียนและเชื่อมโยงนโยบายการเข้าถึงแบบรวม (UAP) ของ IAM กับกฎ Common Expression Language (CEL) ที่ควบคุมปลายทาง Agent Registry ที่ลงทะเบียนไว้ (destination.agent_registry.*)
  • วิธีกำจัดรหัสและ URL ของ Agent ที่ฮาร์ดโค้ดโดยใช้การค้นหาอัตโนมัติขณะรันไทม์กับ Agent Registry
  • วิธีทดสอบการบล็อกแบบ Zero Trust ในขอบเขตจริง (HTTP 403 Forbidden) และยืนยันการอัปเดตนโยบายแบบเรียลไทม์ใน Cloud Logging

สิ่งที่ต้องดำเนินการ

  • โปรเจ็กต์ Google Cloud 3 โปรเจ็กต์ที่เปิดใช้การเรียกเก็บเงิน:
    • PROJECT_GOVERNANCE: การกำกับดูแลแบบรวมศูนย์, เกตเวย์, รีจิสทรี และนโยบายการเข้าถึง IAM
    • PROJECT_CONCIERGE: Agent ผู้จัดระเบียบ Concierge การจัดซื้อ
    • PROJECT_SELLERS: ตัวแทนผู้ขายที่เชี่ยวชาญด้านเบอร์เกอร์และพิซซ่า
  • ผู้ใช้ IAM หรือบัญชีบริการที่มีสิทธิ์ roles/owner หรือสิทธิ์ระดับผู้ดูแลระบบในทั้ง 3 โปรเจ็กต์
  • องค์กร Google Cloud (สำหรับการแมปโดเมนที่เชื่อถือได้ของ SPIFFE)
  • Google Cloud Shell หรือเครื่องภายในที่มี gcloud CLI, python (3.11 ขึ้นไป) และ uv ติดตั้งอยู่

ส่วนเกริ่นนำก็มีเพียงเท่านี้... ต่อไปจะเป็นส่วนการตั้งค่าและสภาพแวดล้อม

2. ตั้งค่า

แม้ว่าสถาปัตยกรรมนี้จะครอบคลุมโปรเจ็กต์ที่อยู่ในระบบคลาวด์ Google Cloud ที่แตกต่างกัน 3 โปรเจ็กต์ แต่คุณสามารถดำเนินการคำสั่งการทำให้ใช้งานได้ของเทอร์มินัล การดาวน์โหลดที่เก็บ และการดำเนินการเก็บพักไว้ได้ 100% จากเทอร์มินัล Cloud Shell เดียวที่ตั้งค่าเป็น PROJECT_GOVERNANCE สคริปต์การติดตั้งใช้งานและคำสั่ง gcloud ทุกรายการจะกำหนดเป้าหมายไปยังโปรเจ็กต์ปลายทางที่เหมาะสมอย่างชัดเจนผ่านแฟล็ก CLI (--project)

เริ่มต้นด้วยการเข้าถึงบรรทัดคำสั่งของโปรเจ็กต์ที่อยู่ในระบบคลาวด์ของ Google โดยทำดังนี้

กำหนดบริบทของโปรเจ็กต์

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

ระบบจะดึงตัวแปรเชลล์เหล่านี้มาโดยอัตโนมัติ

# 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

เปิดใช้บันทึกการเข้าถึงข้อมูลการตรวจสอบระบบคลาวด์สำหรับ IAP v2

โดยค่าเริ่มต้น Google Cloud จะปิดใช้บันทึกการตรวจสอบการเข้าถึงข้อมูลเพื่อป้องกันค่าใช้จ่ายในการจัดเก็บข้อมูลที่ไม่ได้ตั้งใจ เนื่องจาก IAP v2 จะส่งการตัดสินใจเกี่ยวกับการให้สิทธิ์ (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 API ที่จำเป็น

# 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 ในทุกโปรเจ็กต์

การตรวจสอบว่าทั้ง 3 โปรเจ็กต์ (PROJECT_GOVERNANCE, PROJECT_CONCIERGE และ PROJECT_SELLERS) เปิดใช้ API เดียวกันทุกประการจะช่วยสร้างความสอดคล้องในการทำงาน และป้องกันความล้มเหลวในการสร้างโทเค็นรันไทม์ ข้อผิดพลาดในการจัดทำแคตตาล็อกสคีมา หรือการสูญหายของข้อมูลการตรวจวัดระยะไกล

เรียกใช้สคริปต์การตรวจสอบต่อไปนี้ใน Cloud Shell เพื่อยืนยันความเท่าเทียมกันของ API ในทั้ง 3 โปรเจ็กต์

# 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 เป็นอนุญาตอย่างชัดเจน

# 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

ส่วนการตั้งค่าก็มีเพียงเท่านี้... ต่อไปจะเป็นส่วนลงทะเบียน Core Google APIs

3. Agent Registry

ลงทะเบียนบริการปลายทาง Core Google APIs

Agent Gateway กำหนดให้ต้องลงทะเบียน URL ของ Google API ใน Central Agent Registry เพื่อให้ Agent ที่กำหนดค่าด้วย agent_gateway_config สามารถกำหนดเส้นทางการรับส่งข้อมูลขาออกไปยังบริการแบ็กเอนด์หลักของ Google Cloud (เช่น aiplatform, ข้อมูลเข้าสู่ระบบ IAM และการตรวจวัดและส่งข้อมูลทางไกล) ได้อย่างปลอดภัย

สร้าง 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

รหัสทรัพยากรปลายทางของ Capture Core API

# 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

ใน Google Cloud IAM และ Gemini Enterprise Agent Platform ข้อมูลประจำตัวของเครื่องที่ออกให้กับคอนเทนเนอร์ Agent ที่ดำเนินการจะใช้ SPIFFE URN ที่ได้รับการรับรองด้วยการเข้ารหัส ซึ่งประเมินโดย Identity-Aware Proxy (IAP v2) เมื่อกำหนดค่านโยบายการเข้าถึงแบบรวมของ IAM คุณสามารถกำหนดเป้าหมายเป็น 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}

กรณีการใช้งานในแพลตฟอร์ม Agent

ระดับ 2 (เครื่องมือทางธุรกิจและ A2A): การให้สิทธิ์ Agent ผู้จัดการเฉพาะในการเรียกใช้เครื่องมือโดเมนเป้าหมาย (เช่น Purchasing Concierge $ ightarrow$ ผู้ขายเบอร์เกอร์)

ระดับ 1 (โครงสร้างพื้นฐานพื้นฐาน): ให้สิทธิ์ Agent ทั้งหมดในโปรเจ็กต์เข้าถึงขาออกไปยัง Google Cloud API (core-gapi-services)

ผลกระทบตลอดวงจรชีวิต

หากมีการลบและสร้าง Agent ขึ้นมาใหม่ รหัสเครื่องมือใหม่จะต้องมีการเชื่อมโยงนโยบาย IAM ที่อัปเดตแล้ว

มีผลกับ Agent ที่ติดตั้งใช้งานใหม่ในโปรเจ็กต์นั้นโดยอัตโนมัติโดยไม่ต้องอัปเดต IAM เพิ่มเติม

การกำกับดูแลแบบประกาศด้วยนโยบายการเข้าถึงแบบรวม (UAP/IAP v2)

ใน IAP v1 เดิม นโยบายขาออกจะแนบกับทรัพยากร Agent Registry แต่ละรายการโดยตรงโดยใช้ gcloud beta iap web add-iam-policy-binding ใน IAP v2 และนโยบายการเข้าถึงแบบรวม ระบบจะยกเลิกการเชื่อมโยงต่อทรัพยากรเพื่อใช้นโยบายการเข้าถึง IAM แบบรวมศูนย์รายการเดียว (cfg/uap-rules.json)

การให้สิทธิ์ขาออกพื้นฐานสำหรับ core-gapi-services จะได้รับการกำหนดค่าเป็นกฎข้อที่ 1 ในนโยบายการเข้าถึงแบบรวมในส่วนที่ 5 เพื่อให้มั่นใจว่าคอนเทนเนอร์ Agent ทั้งหมดมีเส้นทางขาออกพื้นฐานที่สร้างขึ้นก่อนการติดตั้งใช้งาน

ดูรายละเอียดทางเทคนิคเพิ่มเติมเกี่ยวกับตัวระบุหลักและกลไก Workload Identity ได้ที่หัวข้อต่อไปนี้

การลงทะเบียนปลายทาง API หลักเสร็จสิ้นแล้ว... ต่อไปจะเป็นส่วนติดตั้งใช้งาน Agent Gateway แบบรวมศูนย์

4. Agent Gateway

ติดตั้งใช้งาน Centralized Agent Gateway

ทำให้ Agent Gateway (centralized-agw) แบบรวมศูนย์ใช้งานได้ในโหมดขาออก AGENT_TO_ANYWHERE ภายในโปรเจ็กต์ $PROJECT_GOVERNANCE

กำหนดไฟล์ Manifest ของการกำหนดค่าเกตเวย์

สร้าง 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

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

ยืนยันรายละเอียดเกตเวย์ของ Agent

# 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 จะรักษาความปลอดภัยและควบคุมการรับส่งข้อมูลขาออกของเครื่องมือและ Agent โดยใช้นโยบายการให้สิทธิ์ (networksecurity.authzPolicies) ที่ผสานรวมกับนโยบายการเข้าถึงแบบรวม (UAP) ของ Identity-Aware Proxy (IAP v2)

ภาพรวมสถาปัตยกรรมการให้สิทธิ์

figure4

รูปที่ 4 ภาพรวมสถาปัตยกรรมการให้สิทธิ์

สถาปัตยกรรมการให้สิทธิ์ประกอบด้วย 3 เลเยอร์ที่เชื่อมต่อกัน ดังนี้

  1. ส่วนขยายบริการ IAP (authzExtension): ทรัพยากรระดับภูมิภาคที่กำหนดค่าด้วย service: iap.googleapis.com, metadata: iapPolicyVersion: "V2" และ failOpen: false เพื่อการบังคับใช้ Zero Trust ในขอบเขตที่เข้มงวด
  2. นโยบายการให้สิทธิ์เกตเวย์ (authzPolicy): ทรัพยากรระดับภูมิภาคที่กำหนดเป้าหมาย Agent Gateway ด้วย policyProfile: REQUEST_AUTHZ และ action: CUSTOM ซึ่งกำหนดเส้นทางการตรวจสอบการให้สิทธิ์ไปยังส่วนขยาย Authz ของ IAP
  3. นโยบายการเข้าถึงและการเชื่อมโยงแบบรวมของ IAM (accessPolicy และ policyBinding): ทรัพยากร IAM v3 ทั่วโลกที่ประเมินโดย IAP โดยจะยืนยันสิทธิ์สากล iap.googleapis.com/resources.egressViaIAP กับข้อมูลประจำตัว SPIFFE ของผู้โทรและเงื่อนไขแคตตาล็อก CEL

ขั้นตอนที่ 1: สร้างและนำเข้าส่วนขยาย Authz ของ IAP v2

สร้างไฟล์ Manifest ของส่วนขยายบริการด้วย 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 Extension โดยทำดังนี้

# 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: สร้างและนำเข้านโยบายการให้สิทธิ์เกตเวย์

สร้างการกำหนดค่านโยบายการให้สิทธิ์ที่แนบกับ Agent Gateway และมอบสิทธิ์การยืนยันคำขอให้กับส่วนขยาย 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 APIs หลัก)

สร้าง cfg/uap-rules.json โดยมีกฎข้อที่ 1 ซึ่งให้สิทธิ์ principalSet ของโปรเจ็กต์ทั้ง 3 รายการเข้าถึง 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 พื้นฐานได้รับสิทธิ์อย่างปลอดภัยในทั้ง 3 โปรเจ็กต์ในโหมด ENFORCE ที่เข้มงวด

การตั้งค่าการให้สิทธิ์เกตเวย์เสร็จสิ้นแล้ว... ต่อไปจะเป็นส่วนกำหนดค่าสิทธิ์ IAM ข้ามโปรเจ็กต์

6. IAM ข้ามโปรเจ็กต์

กำหนดค่าสิทธิ์ IAM ข้ามโปรเจ็กต์

ในโทโพโลยีแบบหลายโปรเจ็กต์นี้ รันไทม์ของ Agent จะอยู่ในโปรเจ็กต์ Spoke (PROJECT_CONCIERGE และ PROJECT_SELLERS) ส่วนเกตเวย์ Agent ส่วนกลางและรีจิสทรี Agent จะอยู่ใน PROJECT_GOVERNANCE

เนื่องจากโปรเจ็กต์ Google Cloud เป็นขอบเขตการรักษาความปลอดภัยที่แยกต่างหาก คุณจึงต้องให้สิทธิ์เข้าถึงข้ามโปรเจ็กต์อย่างชัดเจนใน 2 เลเยอร์การทำงานต่อไปนี้

  1. ระนาบควบคุม (เวลาในการติดตั้งใช้งาน): เมื่อติดตั้งใช้งานคอนเทนเนอร์ Agent ที่กำหนดค่าด้วย --agent-gateway-config Agent บริการรันไทม์ของ 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 เพื่อแก้ไขปลายทางของ Agent เป้าหมายแบบไดนามิก
    • การเรียกใช้เป้าหมาย: ตัวแทน 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 บริการ 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 ข้ามโปรเจ็กต์ก็มีเพียงเท่านี้... ต่อไปจะเป็นส่วนติดตั้งใช้งานตัวแทนผู้ขายและ Concierge

7. Agent Runtime

ติดตั้งใช้งาน Seller Agent และ Concierge Agent

ฐานของโค้ดแอปพลิเคชันแบบหลาย Agent และสคริปต์การติดตั้งใช้งานที่ใช้สำหรับ Codelab นี้จะได้รับการดูแลรักษาในที่เก็บ GitHub ระยะไกลของ Google Cloud ขั้นตอนต่อไปนี้จะโคลนที่เก็บในเครื่อง คัดลอกไฟล์ที่จำเป็นไปยังโครงสร้างไดเรกทอรีการทำงานปัจจุบัน ล้างไฟล์ชั่วคราว และติดตั้งทรัพยากร Dependency ด้วย 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

สร้าง Bucket การเก็บพักไว้ส่วนกลางที่แชร์ร่วมกัน

# 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 ข้ามโปรเจ็กต์

ในขั้นตอนนี้ คุณจะติดตั้งใช้งาน Seller Agent ในโปรเจ็กต์ Spoke (PROJECT_SELLERS) พร้อมกับกำหนดค่าให้กำหนดเส้นทางขาออกผ่านเกตเวย์ Agent ส่วนกลางใน 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 จึงได้รับอนุญาตผ่านเกตเวย์โดยไม่มีการหยุดชะงัก

ติดตั้งใช้งานตัวแทนผู้ขายเบอร์เกอร์และพิซซ่าใน 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

ติดตั้งใช้งาน Agent บริการด้านการซื้อใน 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 ของ 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"
    }
  }
}

การติดตั้งใช้งาน Agent เสร็จสิ้นแล้ว... ต่อไปจะเป็นส่วนลงทะเบียน Agent ใน Central Agent Registry

8. รีจิสทรีข้ามโปรเจ็กต์

ลงทะเบียน Agent ใน Central Agent Registry

ลงทะเบียน Agent ทั้ง 3 รายใน Central Agent Registry ใน PROJECT_GOVERNANCE โดยใช้ปลายทาง mTLS ระดับภูมิภาคข้ามโปรเจ็กต์และหมายเลขโปรเจ็กต์ที่เป็นตัวเลข

ลงทะเบียนบริการเป็น Agent ที่ไม่ใช่ 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

กำหนดค่านโยบายขาออก A2A ในนโยบายการเข้าถึงแบบรวม

ภายใต้สถาปัตยกรรม Default Deny ของ Agent Gateway ในโหมด ENFORCE ที่เข้มงวด

  1. กฎที่ 1 (Cloud APIs พื้นฐานของ Google): อนุญาตให้คอนเทนเนอร์ Agent ในทั้ง 3 โปรเจ็กต์เข้าถึง core-gapi-services ได้
  2. กฎข้อที่ 2 (ตัวแทนขายเบอร์เกอร์: อนุญาต): อนุญาตให้อินสแตนซ์ตัวแทนบริการด้านการซื้อเรียกใช้ตัวแทนขายเบอร์เกอร์โดยเฉพาะ
  3. ตัวแทนผู้ขายพิซซ่า (ถูกปฏิเสธโดยค่าเริ่มต้น): ถูกละเว้นจากกฎนโยบายโดยเจตนา ในโหมด ENFORCE (failOpen: false) ความพยายามใดๆ ของ Concierge ในการเรียกใช้ Pizza Seller จะสิ้นสุดลงทันทีที่ขอบเขตเกตเวย์ด้วย HTTP 403 Forbidden

กำหนดข้อมูลระบุตัวตนของ Agent ของ 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}"

อัปเดตไฟล์ Manifest ด้วยกฎ 1 และ 2

หากต้องการอัปเดตนโยบายการเข้าถึงอย่างปลอดภัยโดยไม่ลบล้างกฎที่มีอยู่ ให้กำหนดไฟล์ Manifest แบบรวมทั้งหมดที่มีกฎที่ 1 (Core Google APIs) และกฎที่ 2 (Burger Seller Agent) ดังนี้

# 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

ใช้นโยบายการเข้าถึงที่อัปเดตแล้ว

ใช้ไฟล์ Manifest ของกฎที่รวมกันในเชิงประกาศโดยใช้ --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

ในส่วนนี้ คุณจะได้ทดสอบการโต้ตอบระหว่าง Agent กับ Agent (A2A) ข้ามโปรเจ็กต์ใน Agent Runtime AI Playground, สังเกตการบล็อก HTTP 403 Forbidden ของขอบเขตจริงในโหมด ENFORCE ที่เข้มงวด, แก้ไขนโยบายการเข้าถึงแบบรวมขณะใช้งาน และตรวจสอบการอนุมัติคำสั่งซื้อทันที

ขั้นตอนที่ 1: เปิด Agent Runtime AI Playground ใน PROJECT_CONCIERGE

  1. เปิดคอนโซล Google Cloud
  2. ในแถบตัวเลือกโปรเจ็กต์ด้านบน ให้เปลี่ยนเป็น PROJECT_CONCIERGE
  3. ในเมนูการนำทาง ให้ไปที่แพลตฟอร์ม Agent > Agent > การติดตั้งใช้งาน
  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. การค้นพบแบบไดนามิก: ในระหว่างการเริ่มต้นเซสชัน Purchasing Concierge ได้ค้นหา Central Agent Registry ใน PROJECT_GOVERNANCE (ผ่าน core-gapi-services ผ่าน Agent Gateway ที่ได้รับอนุญาตตามกฎข้อที่ 1) เพื่อค้นหาปลายทาง mTLS ระดับภูมิภาคสำหรับ burger-seller-agent
  2. การจำแนกความตั้งใจและการเรียกใช้ A2A: Gemini ภายในเจ้าหน้าที่บริการด้านการซื้อจะแยกวิเคราะห์ความตั้งใจในการสั่งอาหารและเรียกใช้ตัวแทนขายเบอร์เกอร์ผ่าน RPC ขาออกไปยัง https://${REGION}-aiplatform.mtls.googleapis.com/.../reasoningEngines/${BURGER_ENGINE_ID}
  3. การสกัดกั้นเกตเวย์และการเผยแพร่ SPIFFE: agent_gateway_config จะบันทึกการรับส่งข้อมูลขาออกและส่งไปยังเกตเวย์ Agent ส่วนกลางใน PROJECT_GOVERNANCE โดยมีข้อมูลระบุตัวตน SPIFFE แบบเข้ารหัสของ Concierge (principal://...)
  4. การประเมินนโยบาย IAP v2: Central Agent Gateway จะเรียกใช้ส่วนขยายการให้สิทธิ์ IAP (authzExtension) โดย IAP v2 จะประเมินกฎข้อที่ 2 ในนโยบายการเข้าถึงแบบรวมของ IAM เนื่องจากผู้โทรตรงกับ ${CONCIERGE_SPIFFE_PRINCIPAL} และเป้าหมายตรงกับ burger-seller-agent, IAP จะแสดงผล ALLOW (granted: true)
  5. การดำเนินการข้ามโปรเจ็กต์: Agent Gateway จะส่งคำขอที่ได้รับอนุญาตข้ามโปรเจ็กต์ไปยัง PROJECT_SELLERS ซึ่งเครื่องมือการให้เหตุผลของผู้ขายเบอร์เกอร์จะประมวลผลคำสั่งซื้อและส่งคืนการยืนยัน

การตอบกลับที่คาดหวัง:

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

บันทึกควรบันทึกการรับส่งข้อมูลขาออกที่มาจากทั้งโปรเจ็กต์ Spoke (PROJECT_CONCIERGE และ PROJECT_SELLERS) โดยมีช่องขาออกสำหรับการเรียกใช้การให้เหตุผลของ Gemini (generateContent), การวัดและส่งข้อมูลทางไกลของ Cloud Trace (/v1/traces) และการค้นหาข้อมูลเข้าสู่ระบบ IAM ซึ่งถูกสกัดกั้นและได้รับอนุญาตอย่างโปร่งใสโดยกฎ 1 (core-gapi-services)

ค้นหาบันทึกการเข้าถึงข้อมูลการตรวจสอบระบบคลาวด์ของ 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)

ในหน้าต่างแชท 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. การค้นพบแบบไดนามิก: Concierge ด้านการซื้อแก้ไขปลายทาง pizza-seller-agent จาก Central Agent Registry ระหว่างการเริ่มต้นระบบ
  2. การแก้ไขความตั้งใจและการเรียกใช้ A2A: Gemini ภายใน Concierge ด้านการซื้อจะพยายามส่งคำขอสั่งพิซซ่าไปยังปลายทางของผู้ขายพิซซ่าใน PROJECT_SELLERS
  3. การสกัดกั้นเกตเวย์: agent_gateway_config จะบันทึก RPC ขาออกและส่งไปยัง Central Agent Gateway
  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 เพื่อหาคำขอที่ถูกบล็อก (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

ค้นหาบันทึกการตรวจสอบการเข้าถึงข้อมูล 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: ให้สิทธิ์การเข้าถึงขาออกแก่ Pizza Agent แบบไดนามิก

สร้าง cfg/uap-rules-update-3.json ใหม่เพื่อรวมกฎข้อที่ 1 (Core 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: ค้นหา Pizza Agent อีกครั้ง (สำเร็จทันทีด้วย 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: Concierge จะส่งคำขอผ่าน Central Agent Gateway
  3. การประเมินนโยบาย IAP v2 (การอนุมัติ): IAP v2 ตรงกับกฎข้อที่ 3, ยืนยันตัวตนของผู้โทรและนิพจน์ CEL เป้าหมาย และแสดงผล ALLOW (granted: true)
  4. การดำเนินการข้ามโปรเจ็กต์: Central Agent Gateway จะส่งต่อการเข้าชมที่ได้รับอนุญาตไปยัง PROJECT_SELLERS ซึ่งเป็นที่ที่ Pizza Seller ประมวลผลคำสั่งซื้อ

ขั้นตอนที่ 8: ตรวจสอบบันทึก Agent Gateway เพื่อหาคำขอ 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. ล้างการติดตั้งใช้งาน Reasoning Engine

เรียกใช้สคริปต์ cleanup_old_deployments.py ที่รวมไว้ในโปรเจ็กต์รันไทม์ทั้ง 2 โปรเจ็กต์เพื่อลบเครื่องมือการให้เหตุผลและรอการดำเนินการที่ใช้เวลานาน

# 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. ลบบริการรีจิสทรีของ Agent

# 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. ลบการเชื่อมโยงนโยบายการเข้าถึงแบบรวมและนโยบายการเข้าถึงของ 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. ลบที่เก็บข้อมูลชั่วคราว 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. บทสรุป

ยินดีด้วย คุณได้ติดตั้งใช้งานและควบคุมสถาปัตยกรรม Agent-to-Agent (A2A) แบบหลายโปรเจ็กต์ใน Google Cloud โดยใช้รันไทม์ของ Vertex AI Agent, Central Agent Gateway, Agent Registry และ IAM Unified Access Policies (UAP) แล้ว

สรุปแนวคิดหลัก

  • ขอบเขตขาออกแบบรวมศูนย์: กำหนดเส้นทางคอนเทนเนอร์รันไทม์ของ Spoke (PROJECT_CONCIERGE, PROJECT_SELLERS) ผ่าน Agent Gateway ส่วนกลางใน PROJECT_GOVERNANCE โดยใช้ agentGatewayConfig
  • การกำกับดูแลแบบประกาศ (UAP): แทนที่การเชื่อมโยงแบบแยกส่วนต่อทรัพยากรด้วยนโยบายการเข้าถึง IAM ที่ตรวจสอบได้รายการเดียว ซึ่งประเมินที่เกตเวย์โดย IAP v2
  • ข้อมูลระบุตัวตนแบบเข้ารหัส: บังคับใช้การส่งออกข้อมูลที่มีสิทธิ์ขั้นต่ำที่สุดโดยใช้ข้อมูลระบุตัวตน SPIFFE ของคอนเทนเนอร์ (principal://...) แทนคีย์ที่มีอายุการใช้งานยาวนาน
  • Dynamic Service Discovery: แก้ไขปลายทางของ Agent เพียร์ที่รันไทม์ผ่าน Central Agent Registry ซึ่งช่วยลด URL และรหัสโปรเจ็กต์ที่ฮาร์ดโค้ด
  • ความคล่องตัวของนโยบายรันไทม์: เปลี่ยน pizza-seller-agent จากปฏิเสธโดยค่าเริ่มต้น (403 Forbidden) เป็นอนุญาต (200 OK) แบบเรียลไทม์ผ่านการอัปเดตนโยบาย โดยไม่ต้องรีสตาร์ทคอนเทนเนอร์เลย

cosmopup

Cosmopup กล่าวว่า "Agent มีประโยชน์มาก เพราะช่วยทำงานข้ามโปรเจ็กต์ทั้งหมดได้ในขณะที่ฉันมุ่งเน้นไปที่วัตถุประสงค์หลัก นั่นคือการงีบหลับ"

ขั้นตอนถัดไปและเอกสารประกอบ