English
主导航

旧版 API

为 Kubernetes 配置工作负载身份联合

将 Kubernetes 用作工作负载身份提供商,通过交换投影的 Kubernetes 服务账号令牌来获取短期 OpenAI 访问令牌。

设置 Kubernetes

本指南假设已启用 Kubernetes 服务账号令牌投影,这在现代 Kubernetes 版本中默认可用。OpenAI 工作负载身份联合需要兼容 OIDC 的投影服务账号令牌。不支持存储在 Secrets 中的旧版 Kubernetes 服务账号令牌。

为需要调用 OpenAI API 的 EKS 工作负载使用一个 Kubernetes ServiceAccount 针对需要调用 OpenAI API 的工作负载。如果尚未拥有,请创建一个:

kubectl create serviceaccount openai-wif --namespace default

获取 Kubernetes 集群的 OIDC 签发者:

kubectl get --raw /.well-known/openid-configuration | jq -r .issuer

即使您上传了 JWKS,并且 OpenAI 不会针对 OIDC 签发者执行 JWKS 发现,该签发者也必须与工作负载身份提供商中配置的签发者相匹配。

获取集群 JWKS 并保存返回的密钥集。配置工作负载身份提供商时将需要用到它:

kubectl get --raw /openid/v1/jwks

使用 OpenAI 预期的受众和适合您工作负载的过期时间来配置投影服务账号令牌。OpenAI 会验证令牌的颁发者、签名、受众和过期时间。在此示例中,令牌文件挂载于 /var/run/secrets/tokens/token, 使用的受众为 https://api.openai.com/v1, 并在 3600 秒后过期。如果投影令牌的受众与 OpenAI 工作负载身份提供商的受众相匹配,您可以使用不同的受众:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: v1
kind: Pod
metadata:
  name: openai-wif-app
  namespace: default
spec:
  serviceAccountName: openai-wif
  containers:
    - name: app
      image: my-image
      volumeMounts:
        - name: ksa-token
          mountPath: /var/run/secrets/tokens
          readOnly: true
  volumes:
    - name: ksa-token
      projected:
        sources:
          - serviceAccountToken:
              path: token
              audience: "https://api.openai.com/v1"
              expirationSeconds: 3600

验证令牌

在配置工作负载身份联合之前,请在本地解码一个示例投影服务账号令牌并检查其声明。在挂载了投影令牌的运行中的 Pod 上执行:

1
2
3
4
5
6
7
8
9
10
11
TOKEN=$(kubectl exec -n default openai-wif-app -- cat /var/run/secrets/tokens/token)

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 令牌类似于:

解码后的 Kubernetes 投影服务账号令牌类似于:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
  "iss": "https://kubernetes.example.com",
  "aud": ["https://api.openai.com/v1"],
  "sub": "system:serviceaccount:default:openai-wif",
  "iat": 1716235422,
  "exp": 1716239022,
  "kubernetes.io": {
    "namespace": "default",
    "serviceaccount": {
      "name": "openai-wif",
      "uid": "11111111-2222-3333-4444-555555555555"
    }
  }
}

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

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

在 OpenAI 中为 Kubernetes 签发者创建工作负载身份提供商,然后添加与投影令牌中的属性相匹配的服务账号映射。

设置工作负载身份提供商

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

  1. 为一个唯一的值,例如 设置 名称 设置颁发者和受众。 kubernetes-prod值。使用 描述,例如 Production Kubernetes cluster, 以帮助管理员识别集群。

  2. OIDC 颁发者 URL 设置 设置为启用出站身份联合时返回的 AWS 特定于账户的颁发者 URL。此值必须与令牌的 指向由 kubectl get --raw /.well-known/openid-configuration | jq -r .issuer返回的颁发者。此值必须与 iss 投影令牌中的声明。设置 为传递给 为在投影服务账号令牌卷上配置的相同不透明受众(audience)字符串。在此示例中,该值为 https://api.openai.com/v1.

  3. 上传 Kubernetes JWKS。 启用 使用上传的 JWKS 进行令牌验证,然后设置 JWKS JSON to the output from kubectl get --raw /openid/v1/jwks。OpenAI 使用此公钥集来验证投影的 Kubernetes 服务账号令牌。请上传包含周围 keys.

    Note: 对于自托管 Kubernetes 集群,OpenAI 仅支持本地 JWKS 模式。请上传集群返回的 JWKS;OpenAI 不会针对配置的签发者执行 OIDC 发现。OpenAI 仍会将配置的签发者与令牌中的 iss 字段进行比较。

    如果您的集群轮换服务账号签名密钥,请更新工作负载身份提供商配置中上传的 JWKS。由不在已配置 JWKS 中的密钥签名的令牌将被拒绝。如果 JWKS 包含多个活跃公钥,请包含完整的 keys array.

  4. 仅在需要派生映射属性时才添加属性转换。 诸如以下原始令牌声明 sub, aud,且 iss 可直接用于映射断言中。如果您计划基于转换后的属性而非原始令牌声明进行匹配,控制台将应用 openai. 前缀;例如,输入 workload_subject with expression assertion.sub to create openai.workload_subject。对于已经以以下内容开头的原始令牌声明 openai. 映射键,已以 openai. 开头的原始令牌声明将被忽略,除非配置了匹配的转换。

设置服务账户映射

  1. 创建服务账户映射。 设置 名称 为 Workload Identity Provider 中的唯一值,例如 openai-mapping-kubernetes值。使用 描述,例如 Workload Identity Provider Mapping for Kubernetes Workloads,以说明哪个工作负载可以使用此映射。

  2. 匹配 Kubernetes 服务账号主体。 设置 to sub and to system:serviceaccount:default:openai-wif。对于 Kubernetes 服务账号,主体格式为 system:serviceaccount:<namespace>:<service-account-name>.

  3. 选择 OpenAI 目标。 设置 项目 指向拥有目标服务账户的 OpenAI 项目。将 服务账户 为 Kubernetes 工作负载可以使用的 OpenAI 服务账号,例如 kubernetes-prod-openai-wif如果您希望为此映射创建新的服务账号而不是复用现有账号,请选中 Create a new service account in this project 如果您希望为此映射创建新的服务账号,而不是复用现有账号。

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

在代码中使用令牌

配置你的 OpenAI SDK 客户端,以读取投射的 Kubernetes 令牌并将其换取 OpenAI 颁发的访问令牌。

使用已挂载的令牌路径(例如 /var/run/secrets/tokens/token,作为 SDK 工作负载身份联合提供者的主体令牌源。SDK 会将该 Kubernetes 令牌换取为 OpenAI 颁发的访问令牌,并使用该 OpenAI 令牌来验证 API 请求。

以下示例使用自定义主体令牌提供者初始化 OpenAI 客户端。该提供者会从挂载的文件路径中读取投射的 Kubernetes 服务账号令牌,并将其用作工作负载身份联合的主体令牌。

通过 Kubernetes 投射服务账号令牌进行身份验证
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
import { readFile } from "node:fs/promises";
import OpenAI from "openai";
import type { SubjectTokenProvider } from "openai/auth";

const tokenPath = "/var/run/secrets/tokens/token";
const identityProviderId = process.env.OPENAI_IDENTITY_PROVIDER_ID;
const serviceAccountId = process.env.OPENAI_SERVICE_ACCOUNT_ID;

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

function mountedServiceAccountTokenProvider(path: string): SubjectTokenProvider {
  return {
    tokenType: "jwt",
    getToken: async () => {
      const token = (await readFile(path, "utf8")).trim();
      if (!token) {
        throw new Error("The mounted service account token file is empty.");
      }
      return token;
    },
  };
}

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

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

console.log(response.output_text);

Kubernetes 最佳实践

  • 使用稳定的 OIDC 颁发者。颁发者 URL 必须与投射的服务账号令牌 iss 声明相匹配,并且在集群升级和维护操作期间应保持稳定。
  • 妥善保管签名密钥。任何拥有集群服务账号签名密钥访问权限的人都可以伪造令牌,而这些令牌可能会被 OpenAI 接受。
  • 为 OpenAI 集成使用专门的服务账号。避免复用同时也用于不相关基础设施或应用访问的服务账号。
  • 保持上传的 JWKS 处于最新状态。OpenAI 使用配置的 JWKS 在本地 JWKS 模式下验证工作负载身份令牌,因此在轮换到新的签名密钥之前,请先更新工作负载身份提供者。
  • 尽量减少自定义声明的复杂性。建议优先匹配标准声明,例如 sub and aud,或直接从这些声明派生的转换属性。
  • 将命名空间的归属管理视为安全模型的一部分。如果命名空间管理员可以创建服务账号,请确保映射范围已进行适当的限定,以防止意外的权限提升。
  • 监控颁发者和签名密钥的变更。在未更新工作负载身份提供者 JWKS 的情况下轮换签名密钥可能会导致令牌交换失败。