托管在 Google Cloud 上的代理可以使用自己的身份向托管在 Google Cloud 运行时(例如 Cloud Run 或 Google Kubernetes Engine (GKE))上的工具和服务进行身份验证,方法是从代理身份请求 OpenID Connect (OIDC) ID 令牌。代理还可以使用这些 ID 令牌向第三方云平台(例如 Amazon Web Services (AWS) 和 Microsoft Azure)、自定义 API、API 网关和本地后端进行身份验证。
当代理自行授权访问外部服务时,代理身份会签发 OpenID Connect (OIDC) ID 令牌。此 JSON Web 令牌 (JWT) 断言了代理的 SPIFFE 身份,并由代理的信任网域(受管理的工作负载身份池)的签发者密钥签名。外部系统可以通过 Google Cloud Security Token Service 托管的公共端点,在没有 Google Cloud 凭据或 SDK 的情况下验证这些令牌:
- 一个 OpenID Connect Discovery 1.0 端点 (
/.well-known/openid-configuration),用于发布 OpenID 提供方元数据和公钥端点 (jwks_uri)。 - 一个 JSON Web 密钥集 (JWKS) 端点 (
/openid/jwks),用于提供用于验证代理 ID 令牌上签名的有效公钥。
准备工作
- 确认您已选择正确的身份验证方法。 查看代理身份概览,了解 SPIFFE 身份、信任网域和代理凭据如何运作。
- 创建并部署启用了代理身份的代理。
- 确保您的外部服务或身份提供方满足以下要求:
- 支持使用 OpenID Connect Discovery 1.0 和 JSON Web 密钥集 (JWKS) 验证 JSON Web 令牌 (JWT)。
- 可以向
https://sts.googleapis.com发送出站 HTTPS 请求,以检索 OpenID 提供方元数据和公共签名密钥。
- 确定您的代理和目标外部服务的以下配置值:
- 颁发者网址(
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) 的工作负载身份池颁发者网址。 - 允许的受众群体(
aud声明):外部服务或身份提供方在验证 ID 令牌时预期的受众群体 URI。
- 颁发者网址(
- 验证您是否拥有完成此任务所需的角色。
所需的角色
如需获得使用代理身份部署代理所需的权限,请让管理员向您授予项目的以下 IAM 角色:
-
将代理部署到 Gemini Enterprise Agent Platform 上的代理运行时:
Vertex AI User (
roles/aiplatform.user) -
将代理服务部署到 Cloud Run:
Cloud Run Admin (
roles/run.admin)
如需详细了解如何授予角色,请参阅管理对项目、文件夹和组织的访问权限。
这些预定义角色包含使用 Agent Identity 部署代理所需的权限。如需查看所需的确切权限,请展开所需权限部分:
所需权限
如需部署具有 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 令牌并将其发送到外部服务,请完成以下任务:
使用代理身份配置智能体
在部署代理时启用 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 令牌时,请根据目标服务使用以下任一方法验证令牌:
- 受管理的云平台(例如 Cloud Run、AWS 或 Microsoft Azure):使用内置的工作负载身份联合来验证传入的令牌,而无需编写自定义验证代码。
- 自定义后端服务、API 网关和本地工作负载:使用公共 OpenID Connect 发现和 JWKS 端点以编程方式验证令牌。
使用内置的工作负载身份联合
如果您的接收服务在支持内置 IAM 身份验证或 OIDC 工作负载身份联合的云平台上运行,则无需编写自定义令牌验证代码:
Cloud Run:如果接收服务在 Cloud Run 上运行,且入站流量经过身份验证 (
--no-allow-unauthenticated),Cloud Run 会在入站流量层验证传入的 Agent Identity 令牌。向调用代理授予接收服务的 Cloud Run Invoker (roles/run.invoker) 角色。 如需了解详情,请参阅向 Cloud Run 上的 MCP 服务器进行身份验证。如果您的服务允许未经身份验证的入站流量,并在应用代码中验证令牌,请参阅以编程方式验证令牌。
Amazon Bedrock:通过指定Google Cloud 安全令牌服务发现网址或发布者网址以及预期受众群体,配置入站 JWT 身份验证。如需查看相关说明,请参阅 AWS 文档中的配置入站 JWT 授权方。
Microsoft Entra ID:配置其他颁发者场景下的联合身份凭据。指定 Google Cloud Security Token Service 发布者网址、预期受众群体和主体标识符(
sub声明)。 如需了解相关说明,请参阅 Microsoft Learn 文档中的在应用与外部身份提供方之间创建信任关系。
以编程方式验证令牌
如果您的代理向自定义 API、微服务、API 网关或本地工作负载发送请求,则接收服务必须先验证传入的 OIDC ID 令牌,然后才能授予访问权限。您的代理通常会在 Authorization: Bearer TOKEN HTTP 标头中传递此令牌。
如需以编程方式验证传入的 ID 令牌,请完成以下任务:
提取并验证令牌签发者网址
当传入请求到达时,读取未验证的 JWT 载荷以提取 iss(签发者)声明。此声明包含代理的信任域的工作负载身份池的网址。此网址用作发现文档和公开签名密钥的基准网址。
在发出任何出站网络请求之前,请验证 iss 声明是否与组织或项目的预期 Google Cloud Security Token Service 工作负载身份池网址相符:
组织级信任网域:
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 安全令牌服务中检索并缓存公共签名密钥:
-
查询 OpenID Connect 发现端点:将
/.well-known/openid-configuration附加到基础颁发者网址,然后发送未经身份验证的 HTTPGET请求:在使用任何请求数据之前,请先进行以下替换:
ORGANIZATION_ID:您的 Google Cloud组织 ID。对于没有组织的项目,请将organizations/ORGANIZATION_ID替换为projects/PROJECT_NUMBER。TRUST_DOMAIN:代理的信任域的工作负载身份池 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状态和一个包含 OpenID 提供方元数据(包括jwks_uri字段)的 JSON 对象:{ "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" ] } -
查询 JSON Web 密钥集 (JWKS) 端点:向 OpenID 提供方元数据中返回的
jwks_uri网址发送未经身份验证的 HTTPGET请求:在使用任何请求数据之前,请先进行以下替换:
ORGANIZATION_ID:您的 Google Cloud组织 ID。对于没有组织的项目,请将organizations/ORGANIZATION_ID替换为projects/PROJECT_NUMBER。TRUST_DOMAIN:代理的信任域的工作负载身份池 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" } ] } -
缓存发现文档和密钥:来自 OpenID Connect 发现端点和 JWKS 端点的响应均包含以下 HTTP 缓存标头:
Cache-Control: public, max-age=86400, must-revalidate
将发现文档和 JWKS 缓存长达 24 小时(
86400秒),以提高验证性能并避免速率限制。Google Cloud 会定期轮替工作负载身份池的私有和公共签名密钥。如果验证方收到的传入令牌包含不在其本地密钥缓存中的
kid(密钥 ID),请先从/openid/jwks端点提取新的 JWKS,然后再拒绝该令牌。如果您在查询发现或 JWKS 端点时遇到 HTTP 错误,请参阅排查 Agent Identity 身份验证问题。
验证令牌签名和声明
如需以加密方式验证令牌签名并验证 JWT 声明,请使用标准 OIDC 或 JWT 验证库(例如 Google Tink),并执行以下操作:
- 签名:在缓存的 JWKS 中查找与 JWT 标头中的
kid(密钥 ID)匹配的公钥。使用alg字段 (RS256) 中指定的算法验证签名。为了实现向前兼容,请动态检查 JWKS 中的alg和kty字段,而不是对算法类型进行硬编码。 - 颁发者 (
iss):确认iss声明与信任网域的受信任Google Cloud 工作负载身份池颁发者网址一致。 - 目标对象 (
aud):确认aud声明与您服务配置的目标对象标识符一致。 - 签发时间 (
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(或信任域前缀)的许可名单进行比较,然后再授予对受保护资源的访问权限。