English
主导航

旧版 API

为 Google Cloud 配置工作负载身份联合

在以下任一场景中,将 Google Cloud 用作工作负载身份提供方:

  • Google 工作负载身份: 将向已挂载的 Google 服务账号签发的、经 Google 签名的 OIDC 令牌,换取短期有效的 OpenAI 访问令牌。
  • Google Kubernetes Engine: 将投影的 GKE 服务账号令牌换取短期有效的 OpenAI 访问令牌。

Google 工作负载身份

Google Cloud 工作负载可以从 Google 元数据服务器请求签名的 OIDC 身份令牌,而无需存储长期的服务账号密钥。在 OpenAI 工作负载身份联合中,Google 身份令牌是 OpenAI 在签发 OpenAI 访问令牌之前验证的主体令牌。此流程适用于使用挂载的 Google 服务账号的 Compute Engine、Cloud Run、GKE 工作负载,以及其他公开元数据服务器身份端点的 Google 托管运行时环境。

设置 Google 工作负载身份

为需要调用 OpenAI API 的工作负载创建一个 Google 服务账号。有关完整的设置流程,请参阅 Google 指南: 创建服务账号.

例如,使用 Google Cloud CLI 创建服务账号:

1
2
3
gcloud iam service-accounts create openai-wif \
  --description="Service account for OpenAI workload identity federation" \
  --display-name="OpenAI workload identity federation"

创建 Compute Engine 虚拟机并挂载该服务账号,或者将服务账号挂载到运行您应用程序的 Google Cloud 资源上。该资源必须在运行时能够调用 Google 元数据服务器。有关虚拟机设置的详细信息,请参阅 Google 指南: 创建使用用户管理的服务账号的虚拟机.

请勿为此流程创建或下载服务账号密钥。工作负载使用挂载的服务账号和元数据服务器来请求短期有效的 OIDC 令牌。

获取 Google 身份令牌

从挂载了服务账号的 Google Cloud 资源中,向元数据服务器请求包含已配置受众的 OIDC 身份令牌。此令牌是 OpenAI 用于换取 OpenAI 签发的访问令牌的主体令牌。

1
2
3
4
5
AUDIENCE="https://api.openai.com/v1"

TOKEN=$(curl -sS -G -H "Metadata-Flavor: Google" \
  "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity" \
  --data-urlencode "audience=${AUDIENCE}")

元数据服务器将返回一个经 Google 签名的 JWT。有关元数据服务器身份端点的更多信息,请参阅 Google 指南: 验证虚拟机身份.

验证令牌

在配置工作负载身份联合之前,请在本地解码一个 Google 身份令牌样本并检查其声明:

1
2
3
4
5
6
7
8
9
TOKEN="$TOKEN" python3 - <<'PY'
import base64
import json
import os

payload = os.environ["TOKEN"].split(".")[1]
payload += "=" * (-len(payload) % 4)
print(json.dumps(json.loads(base64.urlsafe_b64decode(payload)), indent=2))
PY

解码后的 AWS 颁发 OIDC 令牌类似于:

解码后的 Google 元数据服务器身份令牌类似于如下格式:

1
2
3
4
5
6
7
8
9
10
{
  "iss": "https://accounts.google.com",
  "aud": "https://api.openai.com/v1",
  "azp": "110123456789012345678",
  "sub": "110123456789012345678",
  "email": "openai-wif@my-project.iam.gserviceaccount.com",
  "email_verified": true,
  "iat": 1716235422,
  "exp": 1716239022
}

声明中显现。 iss, aud, email,且 sub 设置工作负载身份联合

在 OpenAI 中为 AWS 账户颁发者创建工作负载身份提供商,然后添加与 AWS 颁发令牌中的稳定声明相匹配的服务账户映射。

在 OpenAI 中为 Google 签发的身份令牌创建工作负载身份提供方,然后添加一个与令牌中的稳定声明相匹配的服务账号映射。

设置工作负载身份提供商

创建工作负载身份提供商。

  1. 为一个唯一的值,例如 设置 名称 设置颁发者和受众。 google-workload-identity-prod值。使用 描述,例如 Production Google Cloud workloads,以帮助管理员识别该提供商。

  2. OIDC 颁发者 URL 设置 设置为启用出站身份联合时返回的 AWS 特定于账户的颁发者 URL。此值必须与令牌的 to https://accounts.google.com。将 为传递给 至您的工作负载从 Google 元数据服务器请求的自定义受众,例如 https://api.openai.com/v1。此值必须与令牌的 aud claim.

  3. 使用 Google OIDC 发现。 保持禁用 使用上传的 JWKS 进行令牌验证 已禁用。OpenAI 使用 Google 的 OIDC 发现元数据和 JWKS 来验证 Google 签名的身份令牌。

  4. 如果需要派生映射属性,请添加属性转换。 For example, enter subject with expression assertion.sub to create openai.subject 来自主题声明。仪表板会自动应用 openai. 前缀。对于已经以以下内容开头的原始令牌声明: openai. 映射键,已以 openai. 开头的原始令牌声明将被忽略,除非配置了匹配的转换。

设置服务账户映射

  1. 创建服务账户映射。 设置 名称 为 Workload Identity Provider 中的唯一值,例如 compute-openai-wif值。使用 描述,例如 Production Compute Engine OpenAI API workload,以说明哪个工作负载可以使用此映射。

  2. 匹配稳定的 Google 服务账号声明。 为每个必须匹配的 GitHub 声明添加一行 and 每一项需要匹配的声明对应一行。使用 sub 作为主要身份绑定,因为它既稳定又唯一。您还可以额外匹配 email for readability.

  3. 选择 OpenAI 目标。 设置 项目 指向拥有目标服务账户的 OpenAI 项目。将 服务账户 Google Cloud 工作负载可以使用的 OpenAI 服务账号,例如 google-workload-identity-prod-openai-wif.

  4. 根据需要缩小 API 权限范围。 选择适当的 权限 例如 api.model.request and api.vector_store.read 以进一步限制从此映射生成的访问令牌。将权限留空可避免添加特定于 WIF 的范围限制;该令牌仍会以映射的服务账户身份进行授权。

在代码中使用令牌

配置您的 OpenAI SDK 客户端,使其从元数据服务器请求 Google 身份令牌,并将其换取 OpenAI 颁发的访问令牌。

设置 OPENAI_WIF_AUDIENCE 配置为 Workload Identity Provider 受众的自定义受众。SDK 会请求该受众的 Google 身份令牌,将其换取 OpenAI 颁发的访问令牌,并使用 OpenAI 令牌来验证 API 请求。

使用 Google 元数据服务器身份令牌进行身份验证
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import OpenAI from "openai";
import type { SubjectTokenProvider } from "openai/auth";

const metadataEndpoint =
  "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity";

const identityProviderId = process.env.OPENAI_IDENTITY_PROVIDER_ID;
const serviceAccountId = process.env.OPENAI_SERVICE_ACCOUNT_ID;
const audience = process.env.OPENAI_WIF_AUDIENCE;

if (!identityProviderId || !serviceAccountId || !audience) {
  throw new Error(
    "Set OPENAI_IDENTITY_PROVIDER_ID, OPENAI_SERVICE_ACCOUNT_ID, and OPENAI_WIF_AUDIENCE"
  );
}

function googleMetadataIdentityTokenProvider(audience: string): SubjectTokenProvider {
  return {
    tokenType: "jwt",
    getToken: async () => {
      const url = new URL(metadataEndpoint);
      url.searchParams.set("audience", audience);
      url.searchParams.set("format", "full");

      const response = await fetch(url, {
        headers: { "Metadata-Flavor": "Google" },
      });

      if (!response.ok) {
        throw new Error(
          `Google metadata token request failed with status ${response.status}.`
        );
      }

      const token = (await response.text()).trim();
      if (!token) {
        throw new Error("Google metadata server did not return an identity token.");
      }

      return token;
    },
  };
}

const client = new OpenAI({
  workloadIdentity: {
    identityProviderId,
    serviceAccountId,
    provider: googleMetadataIdentityTokenProvider(audience),
  },
});

const response = await client.responses.create({
  model: "gpt-4.1-mini",
  input: "Say hello from Google Cloud workload identity federation.",
});

console.log(response.output_text);

Google Cloud 最佳实践

  • 为每个工作负载使用专用的 Google 服务账号。避免在无关的服务或环境之间共享服务账号。
  • 使用工作负载身份流程,而不是长期有效的服务账号密钥。对于可以使用元数据服务器身份令牌或 GKE 工作负载身份的工作负载,避免分发和轮替 JSON 密钥文件。
  • 将身份范围限制在最小实用工作负载边界内。为单个应用程序提供独立的服务账号可以实现更清晰的审计和最小权限访问。
  • 谨慎使用基于属性的映射。尽可能优先使用稳定的标识符(例如服务账号主体声明),而不是可变的元数据。
  • 将生产环境与非生产环境的项目分开。独立的项目可降低意外共享权限的风险,并简化审计。
  • 仅授予所需的 IAM 权限。将 Google 身份限制为工作负载所需的最低权限。
  • 监控服务账号的使用情况。异常的令牌交换可能表明配置发生偏移或工作负载已遭到破坏。