אימות לשירותים חיצוניים באמצעות הזהות של הסוכן

סוכנים שמתארחים ב- Google Cloud יכולים להשתמש בזהות שלהם כדי לבצע אימות לכלים ולשירותים שמתארחים בסביבות זמן ריצה של Google Cloud , כמו Cloud Run או Google Kubernetes Engine ‏ (GKE), על ידי שליחת בקשה לטוקן של מזהה מסוג OpenID Connect ‏ (OIDC) מ-Agent Identity. סוכנים יכולים גם להשתמש באסימוני המזהה האלה כדי לבצע אימות בפלטפורמות ענן של צד שלישי (כמו Amazon Web Services‏ (AWS) ו-Microsoft Azure), בממשקי API בהתאמה אישית, בשערי API ובשרתי קצה עורפיים מקומיים.

כשסוכן פועל על סמך ההרשאה שלו כדי לגשת לשירות חיצוני, Agent Identity מנפיק טוקן של מזהה של OpenID Connect ‏ (OIDC). אסימון ה-JWT הזה מאשר את זהות ה-SPIFFE של הסוכן, והוא חתום על ידי מפתחות ההנפקה של מתחם האמון (trust domain) של הסוכן (מאגר זהויות מנוהל של עומס עבודה). מערכות חיצוניות יכולות לאמת את האסימונים האלה בלי Google Cloud פרטי כניסה או ערכות SDK, באמצעות נקודות קצה ציבוריות שמתארחות על ידי Google Cloud Security Token Service:

  • נקודת קצה (endpoint) של OpenID Connect Discovery 1.0 (/.well-known/openid-configuration) שמפרסמת את המטא-נתונים של ספק ה-OpenID ואת נקודת הקצה של המפתח הציבורי (jwks_uri).
  • נקודת קצה של JSON Web Key Set‏ (JWKS) (/openid/jwks) שמשמשת לאימות חתימות באסימוני מזהה של סוכנים.

לפני שמתחילים

  1. מוודאים שבחרתם את שיטת האימות הנכונה. במאמר סקירה כללית על זהות הסוכן מוסבר איך פועלים זהויות SPIFFE, דומיינים מהימנים ופרטי הכניסה של הסוכן.
  2. יוצרים ומפעילים סוכן עם Agent Identity.
  3. חשוב לוודא שהשירות החיצוני או ספק הזהויות החיצוני עומדים בדרישות הבאות:
  4. מזהים את ערכי ההגדרה הבאים של הסוכן ושירות היעד החיצוני:
    • כתובת ה-URL של המנפיק (טענת iss): כתובת ה-URL של המנפיק של מאגר הזהויות של עומסי העבודה בארגון (https://sts.googleapis.com/v1/organizations/ORGANIZATION_ID/locations/global/workloadIdentityPools/TRUST_DOMAIN) או בפרויקט (https://sts.googleapis.com/v1/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/TRUST_DOMAIN).
    • Allowed audience (הצהרת aud): ה-URI של הקהל שהשירות החיצוני או ספק הזהויות מצפים לו כשמאמתים אסימונים מזהים.
  5. מוודאים שיש לכם את התפקידים הנדרשים כדי להשלים את המשימה הזו.

התפקידים הנדרשים

כדי לקבל את ההרשאות שדרושות לפריסת סוכן עם זהות סוכן, צריך לבקש מהאדמין להקצות לכם את תפקידי ה-IAM הבאים בפרויקט:

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

התפקידים המוגדרים מראש האלה כוללים את ההרשאות שנדרשות לפריסת סוכן עם Agent Identity. כדי לראות בדיוק אילו הרשאות נדרשות, אפשר להרחיב את הקטע ההרשאות הנדרשות:

ההרשאות הנדרשות

כדי לפרוס סוכן עם Agent Identity, נדרשות ההרשאות הבאות:

  • פריסת סוכן ב-Agent Runtime ב-Gemini Enterprise Agent Platform:
    • aiplatform.reasoningEngines.create
    • aiplatform.reasoningEngines.update
  • פורסים שירות סוכן ב-Cloud Run:
    • run.services.create
    • run.services.update

יכול להיות שתקבלו את ההרשאות האלה באמצעות תפקידים בהתאמה אישית או תפקידים מוגדרים מראש אחרים.

קבלת טוקן של מזהה OIDC לסוכן

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

  1. הגדרת הסוכן באמצעות הזהות של הסוכן
  2. בקשת טוקן של מזהה של OIDC בקוד אפליקציה

הגדרת Agent Identity עבור הסוכן שלך

מפעילים את Agent Identity כשפורסים את הסוכן:

  • אם פורסים את הסוכן ב-Agent Runtime ב-Gemini Enterprise Agent Platform, מגדירים את identity_type ל-AGENT_IDENTITY:

    remote_app = client.agent_engines.create(
        agent=app,
        config={
            "identity_type": types.IdentityType.AGENT_IDENTITY,
            "requirements": ["google-cloud-aiplatform[agent_engines,adk]"],
        },
    )
    
  • אם פורסים שירות סוכן בקונטיינר ב-Cloud Run, מעבירים את הדגל --identity-type=agent-identity:

    gcloud run deploy SERVICE_NAME \
        --image=IMAGE_URL \
        --identity-type=agent-identity \
        --no-allow-unauthenticated

    מחליפים את מה שכתוב בשדות הבאים:

    • ‫SERVICE_NAME: השם של שירות Cloud Run.
    • ‫IMAGE_URL: כתובת ה-URL של קובץ אימג' של קונטיינר של הסוכן.

בקשה של טוקן של מזהה מסוג OIDC בקוד אפליקציה

בקוד האפליקציה של הסוכן, משתמשים בספריית הלקוח של Google Auth כדי לבקש אסימון מזהה OIDC לקהל החיצוני לטירגוט. ספריית הלקוח מטפלת ביצירת טוקנים, בשמירתם במטמון מקומי ובחידוש אוטומטי משרת המטא-נתונים.

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

בדוגמה הבאה נעשה שימוש בספרייה google-auth כדי לבקש אסימון מזהה של OIDC ולצרף אותו כאסימון Bearer לבקשה יוצאת:

Python

from google.auth.transport.requests import AuthorizedSession
from google.oauth2 import id_token

# 1. Specify the audience expected by the external receiver
# (for example, AWS Bedrock AgentCore or your external service URL).
target_audience = "https://EXTERNAL_SERVICE_AUDIENCE"

# 2. Create ID token credentials and an AuthorizedSession, which handles
# local token caching, automatic renewal before expiry, and the Bearer header.
credentials = id_token.fetch_id_token_credentials(audience=target_audience)
authed_session = AuthorizedSession(credentials)

# 3. Send the authenticated request to the external service.
response = authed_session.post(
    "https://EXTERNAL_SERVICE_ENDPOINT",
    json={"prompt": "Hello from Agent"},
)

מחליפים את מה שכתוב בשדות הבאים:

  • ‫EXTERNAL_SERVICE_AUDIENCE: ה-URI של הקהל שצפוי בשירות המקבל (לדוגמה, bedrock.us-east-1.amazonaws.com או api.example.com).
  • ‫EXTERNAL_SERVICE_ENDPOINT: כתובת ה-URL של נקודת הקצה החיצונית של ה-API או של ה-Backend שאליה הסוכן שולח קריאות.

הוראות ודוגמאות לשימוש בספריות לקוח בשפות תכנות אחרות (כולל Go,‏ Node.js ו-Java) אפשר למצוא במאמר קבלת טוקן של מזהה. הגרסאות הנוכחיות של ספריות הלקוח בשפות האלה תומכות ב---identity-type=agent-identity, אבל לא משתמשות באסימונים קשורים כברירת מחדל.

אימות אסימונים מזהים של סוכנים

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

שימוש באיחוד מובנה של שירותי אימות הזהות של עומסי עבודה

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

  • ‫Cloud Run: אם שירות הקבלה פועל ב-Cloud Run עם תעבורת נכנסת מאומתת (--no-allow-unauthenticated), ‏ Cloud Run מאמת את אסימוני Agent Identity בשכבת התעבורה הנכנסת. מקצים לסוכן הקורא את התפקיד Cloud Run Invoker ‏ (roles/run.invoker) בשירות המקבל. מידע נוסף זמין במאמר אימות לשרתי MCP ב-Cloud Run.

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

  • ‫Amazon Bedrock: כדי להגדיר אימות JWT נכנס, צריך לציין אתGoogle Cloud כתובת ה-URL של גילוי שירות אסימוני האבטחה או את כתובת ה-URL של המנפיק, ואת הקהל הצפוי. הוראות מפורטות מופיעות במאמר Configure inbound JWT authorizer (הגדרת אמצעי אימות JWT לנתונים נכנסים) במסמכי AWS.

  • ‫Microsoft Entra ID: מגדירים פרטי כניסה של זהות מאוחדת עם התרחיש Other issuer (מנפיק אחר). מציינים את כתובת ה-URL של המנפיק של Google Cloud Security Token Service, את הקהל הצפוי ואת מזהה הנושא (sub claim). הוראות מפורטות זמינות במאמר בנושא יצירת יחסי אמון בין אפליקציה לבין ספק זהויות חיצוני במסמכי התיעוד של Microsoft Learn.

אימות טוקנים באופן פרוגרמטי

אם הסוכן שולח בקשות ל-API בהתאמה אישית, למיקרו-שירות, לשער API או לעומס עבודה מקומי, השירות המקבל חייב לאמת את אסימון ה-ID הנכנס של OIDC לפני שהוא מעניק גישה. בדרך כלל הסוכן מעביר את האסימון הזה בכותרת ה-HTTP‏ Authorization: Bearer TOKEN.

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

  1. חילוץ ואימות של כתובת ה-URL של מנפיק האסימון
  2. גילוי ושמירה במטמון של מפתחות חתימה ציבוריים
  3. אימות החתימה והטענות של הטוקן
  4. איך מאשרים את זהות ה-SPIFFE של הסוכן

חילוץ ואימות של כתובת ה-URL של מנפיק הטוקן

כשמתקבלת בקשה נכנסת, קוראים את מטען ה-JWT שלא אומת כדי לחלץ את הצהרת iss (המנפיק). ההצהרה הזו מכילה את כתובת ה-URL של מאגר הזהויות של כוח העבודה עבור דומיין האמון של הסוכן. כתובת ה-URL הזו משמשת ככתובת ה-URL הבסיסית של מסמך הגילוי ומפתחות החתימה הציבוריים.

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

  • דומיינים מהימנים ברמת הארגון:

    https://sts.googleapis.com/v1/organizations/ORGANIZATION_ID/locations/global/workloadIdentityPools/TRUST_DOMAIN

    לדוגמה, לארגון עם מזהה 123456789012, הערך של TRUST_DOMAIN הוא agents.global.org-123456789012.system.id.goog.

  • דומיינים מהימנים ברמת הפרויקט (לפרויקטים ללא ארגון):

    https://sts.googleapis.com/v1/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/TRUST_DOMAIN

    לדוגמה, עבור פרויקט עם המספר 9876543210, TRUST_DOMAIN הוא agents.global.proj-9876543210.system.id.goog.

איתור מפתחות החתימה הציבוריים ושמירתם במטמון

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

  1. שליחת שאילתה לנקודת ה-Discovery של OpenID Connect: מוסיפים את /.well-known/openid-configuration לכתובת ה-URL הבסיסית של המנפיק ושולחים בקשת HTTP מסוג GET ללא אימות:

    לפני שמשתמשים בנתוני הבקשה, צריך להחליף את הנתונים הבאים:

    • ‫ORGANIZATION_ID: מזהה הארגון ב- Google Cloud. בפרויקט ללא ארגון, מחליפים את organizations/ORGANIZATION_ID ב-projects/PROJECT_NUMBER.
    • ‫TRUST_DOMAIN: המזהה של מאגר הזהויות של עומסי עבודה עבור מתחם האמון (trust domain) של הסוכן (לדוגמה, agents.global.org-123456789012.system.id.goog).

    ה-method של ה-HTTP וכתובת ה-URL:

    GET https://sts.googleapis.com/v1/organizations/ORGANIZATION_ID/locations/global/workloadIdentityPools/TRUST_DOMAIN/.well-known/openid-configuration

    כדי לשלוח את הבקשה צריך להרחיב אחת מהאפשרויות הבאות:

    בקשה שמתבצעת בהצלחה מחזירה סטטוס HTTP 200 OK ואובייקט JSON שמכיל את המטא-נתונים של ספק OpenID, כולל השדה jwks_uri:

    {
      "issuer": "https://sts.googleapis.com/v1/organizations/123456789012/locations/global/workloadIdentityPools/agents.global.org-123456789012.system.id.goog",
      "jwks_uri": "https://sts.googleapis.com/v1/organizations/123456789012/locations/global/workloadIdentityPools/agents.global.org-123456789012.system.id.goog/openid/jwks",
      "authorization_endpoint": "https://sts.googleapis.com/v1/organizations/123456789012/locations/global/workloadIdentityPools/agents.global.org-123456789012.system.id.goog/authorize",
      "token_endpoint": "https://sts.googleapis.com/v1/organizations/123456789012/locations/global/workloadIdentityPools/agents.global.org-123456789012.system.id.goog/token",
      "response_types_supported": [
        "id_token"
      ],
      "subject_types_supported": [
        "public"
      ],
      "id_token_signing_alg_values_supported": [
        "RS256"
      ]
    }
    
  2. שליחת שאילתה לנקודת הקצה של JSON Web Key Set‏ (JWKS): שולחים בקשת HTTP GET לא מאומתת לכתובת ה-URL‏ jwks_uri שמוחזרת במטא-נתונים של ספק ה-OpenID:

    לפני שמשתמשים בנתוני הבקשה, צריך להחליף את הנתונים הבאים:

    • ‫ORGANIZATION_ID: מזהה הארגון ב- Google Cloud. בפרויקט ללא ארגון, מחליפים את organizations/ORGANIZATION_ID ב-projects/PROJECT_NUMBER.
    • ‫TRUST_DOMAIN: המזהה של מאגר הזהויות של עומסי עבודה עבור מתחם האמון (trust domain) של הסוכן (לדוגמה, agents.global.org-123456789012.system.id.goog).

    ה-method של ה-HTTP וכתובת ה-URL:

    GET https://sts.googleapis.com/v1/organizations/ORGANIZATION_ID/locations/global/workloadIdentityPools/TRUST_DOMAIN/openid/jwks

    כדי לשלוח את הבקשה צריך להרחיב אחת מהאפשרויות הבאות:

    בקשה מוצלחת מחזירה סטטוס HTTP 200 OK ואובייקט JSON שמכיל מערך של מפתחות ציבוריים בפורמט שמוגדר ב-RFC 7517:

    {
      "keys": [
        {
          "kty": "RSA",
          "use": "sig",
          "alg": "RS256",
          "kid": "4d1933f8e6c4e0b512c140989f6655c68997...",
          "n": "uQn4zN_1mQ0VpGv82-Wp3w...",
          "e": "AQAB"
        }
      ]
    }
    
  3. שמירת מסמך Discovery והמפתחות במטמון: התשובות מנקודת הקצה של OpenID Connect Discovery ומנקודת הקצה של JWKS כוללות את כותרת המטמון הבאה של HTTP:

    Cache-Control: public, max-age=86400, must-revalidate
    

    כדי לשפר את ביצועי האימות ולמנוע הגבלת קצב, כדאי לשמור במטמון את מסמך Discovery ואת JWKS למשך עד 24 שעות (86400 שניות).

    Google Cloud מבצע רוטציה תקופתית של מפתחות החתימה הפרטיים והציבוריים של מאגרי הזהויות של כוח העבודה. אם מאמת הטוקן מקבל טוקן נכנס עם kid (מזהה מפתח) שלא נמצא במטמון המפתחות המקומי שלו, הוא צריך לאחזר JWKS חדש מנקודת הקצה /openid/jwks לפני שהוא דוחה את הטוקן.

    אם נתקלתם בשגיאות HTTP כששלחתם שאילתות לנקודות הקצה של הגילוי או של JWKS, כדאי לעיין במאמר בנושא פתרון בעיות שקשורות לאימות Agent Identity.

אימות החתימה והטענות של הטוקן

כדי לאמת באופן קריפטוגרפי את חתימת האסימון ולאמת את הצהרות ה-JWT, צריך להשתמש בספריית אימות סטנדרטית של OIDC או JWT (כמו Google Tink) ולבצע את הפעולות הבאות:

  1. חתימה: מחפשים את המפתח הציבורי ב-JWKS שבמטמון שתואם ל-kid (מזהה המפתח) בכותרת ה-JWT. מאמתים את החתימה באמצעות האלגוריתם שצוין בשדה alg (RS256). כדי לשמור על תאימות קדימה, בודקים את השדות alg ו-kty ב-JWKS באופן דינמי ולא מקודדים באופן קשיח את סוגי האלגוריתמים.
  2. ‫Issuer (iss): מוודאים שהטענה iss תואמת לכתובת ה-URL של ספק הזהויות של מאגר הזהויות של עומסי עבודהGoogle Cloud עבור מתחם האמון (trust domain).
  3. קהל (aud): מוודאים שהתביעה aud תואמת למזהה הקהל שהוגדר בשירות שלכם.
  4. הזמן שבו הונפק (iat) וזמן התפוגה (exp): מוודאים שההצהרה iat היא מהעבר ושהזמן הנוכחי מוקדם יותר מההצהרה exp (עם אפשרות לסטייה קלה בשעון, למשל דקה או שתיים).

בדוגמה הבאה נעשה שימוש ב-Google Tink ‏(tink.jwt) כדי לאמת אסימון מזהה של זהות סוכן מול מטען ייעודי (payload) של JSON מסוג JWKS:

Python

import tink
from tink import jwt

# Initialize Tink JWT signature primitives (call once at application startup).
jwt.register_jwt_signature()


def verify_agent_identity_token(
    token: str,
    jwks_json: str,
    expected_issuer: str,
    expected_audience: str,
) -> jwt.VerifiedJwt:
    """Verifies an Agent Identity JWT against a JWKS JSON string using Tink.

    Args:
        token: The compact serialized JWT string.
        jwks_json: The JWKS JSON string fetched from the STS pool endpoint.
        expected_issuer: The expected token issuer ('iss' claim).
        expected_audience: The expected token audience ('aud' claim).

    Returns:
        jwt.VerifiedJwt: The verified JWT claims object.

    Raises:
        tink.TinkError: If the JWKS cannot be parsed, the key is not found,
            or token validation (signature, issuer, audience, expiration) fails.
    """
    # 1. Convert the JWKS JSON into a Tink public KeysetHandle.
    keyset_handle = jwt.jwk_set_to_public_keyset_handle(jwks_json)

    # 2. Instantiate the Tink JwtPublicKeyVerify primitive.
    jwt_verifier = keyset_handle.primitive(jwt.JwtPublicKeyVerify)

    # 3. Configure expected validation rules (issuer, audience, expiration).
    # Google Cloud STS sets 'typ': 'JWT' in the header, so
    # expected_type_header="JWT" is required.
    validator = jwt.new_validator(
        expected_issuer=expected_issuer,
        expected_audience=expected_audience,
        expected_type_header="JWT",
        allow_missing_expiration=False,
    )

    # 4. Cryptographically verify the signature and standard OIDC claims.
    return jwt_verifier.verify_and_decode(token, validator)

אישור הזהות של הסוכן ב-SPIFFE

אחרי שמאמתים את החתימה של האסימון ואת הטענות הרגילות, בודקים את הטענה המאומתת sub (נושא) כדי לאשר את הבקשה ולתעד את הנציג שביצע את הקריאה ביומני הביקורת.

התלונה sub מכילה את מזהה SPIFFE הייחודי של הסוכן, לדוגמה:

  spiffe://agents.global.org-123456789012.system.id.goog/resources/aiplatform/projects/9876543210/locations/us-central1/reasoningEngines/my-test-agent

בלוגיקת ההרשאה של השירות, משווים את טענת sub המאומתת לרשימת היתרים של מזהי SPIFFE של סוכנים מהימנים (או קידומות של דומיינים מהימנים) לפני שמעניקים גישה למשאבים מוגנים.

המאמרים הבאים