使用代理程式本身的身分驗證外部服務

在 Google Cloud 上代管的代理程式可以透過 Agent Identity 要求 OpenID Connect (OIDC) ID 權杖,使用自己的身分驗證 Google Cloud 執行階段 (例如 Cloud Run 或 Google Kubernetes Engine (GKE)) 代管的工具和服務。代理程式也可以使用這些 ID 權杖,向第三方雲端平台 (例如 Amazon Web Services (AWS) 和 Microsoft Azure)、自訂 API、API 閘道和地端部署後端進行驗證。

當代理自行授權存取外部服務時,AgentIdentity 會核發 OpenID Connect (OIDC) ID 權杖。這個 JSON Web Token (JWT) 會聲明代理程式的 SPIFFE 身分,並由代理程式信任網域 (受管理的工作負載身分集區) 的簽發者金鑰簽署。外部系統可透過 Google Cloud 安全權杖服務代管的公開端點,在沒有 Google Cloud 憑證或 SDK 的情況下驗證這些權杖:

  • OpenID Connect Discovery 1.0 端點 (/.well-known/openid-configuration),用於發布 OpenID 提供者中繼資料和公開金鑰端點 (jwks_uri)。
  • JSON Web Key Set (JWKS) 端點 (/openid/jwks),用於提供驗證代理 ID 權杖簽章的有效公開金鑰。

事前準備

  1. 確認您選擇的驗證方法正確無誤。 請參閱Agent Identity 總覽,瞭解 SPIFFE 身分、信任網域和代理憑證的運作方式。
  2. 建立及部署代理,並啟用代理身分。
  3. 請確認外部服務或身分識別提供者符合下列規定:
  4. 找出代理程式和目標外部服務的下列設定值:
    • 簽發者網址 (iss 聲明):貴機構 (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) 的 Workload Identity Pool 簽發者網址。
    • 允許的目標對象 (aud 聲明):外部服務或身分識別供應器在驗證 ID 權杖時預期的目標對象 URI。
  5. 確認您具備完成這項工作所需的角色。

必要的角色

如要取得使用 Agent Identity 部署代理程式所需的權限,請要求管理員授予您專案的下列 IAM 角色:

如要進一步瞭解如何授予角色,請參閱「管理專案、資料夾和組織的存取權」。

這些預先定義的角色具備使用 Agent Identity 部署代理程式所需的權限。如要查看確切的必要權限,請展開「Required permissions」(必要權限) 部分:

所需權限

如要使用 Agent Identity 部署代理程式,必須具備下列權限:

  • 將代理程式部署至 Gemini Enterprise Agent Platform 的 Agent Runtime:
    • aiplatform.reasoningEngines.create
    • aiplatform.reasoningEngines.update
  • 將代理服務部署至 Cloud Run:
    • run.services.create
    • run.services.update

您或許還可透過自訂角色或其他預先定義的角色取得這些權限。

取得代理的 OIDC ID 權杖

如要設定代理程式,以取得 OIDC ID 權杖並傳送至外部服務,請完成下列工作:

  1. 使用 Agent Identity 設定代理程式
  2. 在應用程式程式碼中要求 OIDC ID 權杖

使用 Agent Identity 設定代理

部署代理時啟用 Agent Identity:

  • 如果將代理部署至 Gemini Enterprise Agent Platform 的 Agent Runtime ,請將 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:代理程式的容器映像檔網址。

在應用程式程式碼中要求 OIDC ID 權杖

在代理程式的應用程式程式碼中,使用 Google Auth 用戶端程式庫,為目標外部目標對象要求 OIDC ID 權杖。用戶端程式庫會處理權杖產生、本機快取,以及從中繼資料伺服器自動更新。

根據預設,為外部目標對象核發的 OIDC ID 權杖不會繫結至執行階段憑證。

以下範例使用 google-auth 程式庫要求 OIDC ID 權杖,並將其附加為外送要求中的 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:代理程式呼叫的外部 API 或後端端點網址。

如需其他程式設計語言 (包括 Go、Node.js 和 Java) 的用戶端程式庫操作說明和範例,請參閱「取得 ID 權杖」。這些語言的目前用戶端程式庫版本支援 --identity-type=agent-identity,但預設不會使用繫結權杖。

驗證 Agent Identity ID 權杖

當外部服務從代理程式收到 OIDC ID 權杖時,請根據目標服務,使用下列任一方法驗證權杖:

使用內建的 workload identity federation

如果接收服務在支援內建 IAM 驗證或 OIDC 工作負載身分聯盟的雲端平台執行,則不需要編寫自訂權杖驗證碼:

透過程式驗證權杖

如果代理程式將要求傳送至自訂 API、微服務、API 閘道或內部部署工作負載,接收服務必須先驗證傳入的 OIDC ID 權杖,才能授予存取權。您的代理程式通常會在 Authorization: Bearer TOKEN HTTP 標頭中傳遞這個權杖。

如要以程式輔助方式驗證傳入的 ID 權杖,請完成下列工作:

  1. 擷取並驗證權杖核發者網址
  2. 探索並快取公開簽署金鑰
  3. 驗證權杖簽章和聲明
  4. 授權代理的 SPIFFE 身分

擷取並驗證權杖核發者網址

收到要求時,請讀取未驗證的 JWT 酬載,擷取iss (簽發者) 聲明。這項聲明包含代理程式信任網域的 workload identity pool 網址。這個網址是導覽文件和公開簽署金鑰的基準網址。

發出任何網路要求前,請先確認 iss 聲明是否與貴機構或專案的預期 Google Cloud 安全權杖服務工作負載身分集區網址相符:

  • 機構層級信任網域:

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

    舉例來說,如果組織 ID 為 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。

探索並快取公開簽署金鑰

驗證簽發者網址後,請從 Google Cloud 安全權杖服務擷取並快取公開簽署金鑰:

  1. 查詢 OpenID Connect 探索端點:將 /.well-known/openid-configuration 附加至基本簽發者網址,然後傳送未經驗證的 HTTP GET 要求:

    使用任何要求資料之前,請先修改下列項目的值:

    • ORGANIZATION_ID:您的 Google Cloud 組織 ID。如果專案沒有所屬機構,請將 organizations/ORGANIZATION_ID 替換為 projects/PROJECT_NUMBER。
    • TRUST_DOMAIN:代理程式信任網域的 Workload Identity Pool ID (例如 agents.global.org-123456789012.system.id.goog)。

    HTTP 方法和網址:

    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 要求傳送至 OpenID 提供者中繼資料傳回的 jwks_uri 網址:

    使用任何要求資料之前,請先修改下列項目的值:

    • ORGANIZATION_ID:您的 Google Cloud 組織 ID。如果專案沒有所屬機構,請將 organizations/ORGANIZATION_ID 替換為 projects/PROJECT_NUMBER。
    • TRUST_DOMAIN:代理程式信任網域的 Workload Identity Pool ID (例如 agents.global.org-123456789012.system.id.goog)。

    HTTP 方法和網址:

    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. 快取導覽文件和金鑰:OpenID Connect 探索端點和 JWKS 端點的回應都包含下列 HTTP 快取標頭:

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

    快取探索文件和 JWKS 最多 24 小時 (86400 秒),以提升驗證效能並避免速率限制。

    Google Cloud 會定期輪替工作負載身分集區的私密和公開簽署金鑰。如果驗證者收到含有 kid (金鑰 ID) 的傳入權杖,但該 ID 不在驗證者的本機金鑰快取中,請先從 /openid/jwks 端點擷取新的 JWKS,再拒絕權杖。

    如果在查詢探索或 JWKS 端點時發生 HTTP 錯誤,請參閱「排解 Agent Identity 驗證問題」。

驗證權杖簽章和聲明

如要以密碼編譯方式驗證權杖簽章及 JWT 聲明,請使用標準 OIDC 或 JWT 驗證程式庫 (例如 Google Tink),並執行下列操作:

  1. 簽章:在快取 JWKS 中找出與 JWT 標頭中的 kid (金鑰 ID) 相符的公開金鑰。使用 alg 欄位 (RS256) 中指定的演算法驗證簽章。為確保向前相容性,請動態檢查 JWKS 中的 alg 和 kty 欄位,而非硬式編碼演算法類型。
  2. 簽發者 (iss):確認 iss 聲明與信任網域的受信任 Workload Identity Pool 簽發者網址相符。Google Cloud
  3. 目標對象 (aud):確認 aud 聲明與服務設定的目標對象 ID 相符。
  4. 簽發時間 (iat) 和到期時間 (exp):確認 iat 聲明是過去的時間,且目前時間早於 exp 聲明 (允許少許時鐘偏差容差,例如 1 到 2 分鐘)。

下列範例使用 Google Tink (tink.jwt) 針對 JWKS JSON 酬載驗證 Agent Identity ID 權杖:

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 ID,例如:

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

在服務的授權邏輯中,請先比對已驗證的 sub 聲明與信任的代理程式 SPIFFE ID (或信任網域前置字元) 的允許清單,再授予受保護資源的存取權。

後續步驟