For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
主要導覽

為 SPIFFE 設定工作負載身分聯合

將 SPIFFE JWT-SVID 交換為短效的 OpenAI 存取權杖,即可使用 SPIFFE 作為工作負載身分提供者。這讓經由 SPIRE 或其他相容於 SPIFFE 的身分提供者驗證的工作負載,無須儲存長效 API 金鑰就能呼叫 OpenAI API。

若要搭配 Codex 使用,請依照本頁取得並檢查 JWT-SVID。接著設定 Codex 工作負載身分,將該 Token 寫入檔案,並讓 Codex 指向該檔案。本頁的服務帳戶對應與 SDK 範例適用於 OpenAI API。

OpenAI 支援可作為 JWT 主體 Token 驗證的 SPIFFE JWT-SVID,其內容須包含簽發者、對象、到期時間、簽發時間戳記,以及可透過 JWKS 驗證的簽章。OpenAI 不支援將 SPIFFE X.509-SVID 作為工作負載身分聯合的主體 Token。

JWT-SVID 規格要求包含 subaudexp 宣告。若要在 OpenAI 使用 JWT-SVID,Token 還必須包含 issiat 宣告,以及 kid 標頭,讓 OpenAI 能依據工作負載身分提供者的組態驗證 Token。

JWT-SVID 並非 OpenID Connect ID Token。SPIRE OIDC Discovery Provider 提供探索中繼資料與 JWKS 金鑰,讓 OpenAI 能驗證 JWT-SVID;它不會改變 Token 的 SPIFFE 語意,也不需要 OIDC 登入流程。

如需 SPIFFE 術語與 Token 要求的詳細資訊,請參閱 SPIFFE JWT-SVID 規格Workload API 規格

設定 SPIFFE

設定 SPIFFE 提供者,為需要呼叫 OpenAI API 的工作負載簽發 JWT-SVID。以下指示使用 SPIRE 術語,但只要相容於 SPIFFE 的提供者所簽發的 JWT-SVID 包含 OpenAI 可驗證的簽發者資訊與 JWKS 簽章金鑰資料,就能使用相同的 OpenAI 組態。

你的 SPIFFE 設定必須提供:

  • 工作負載的固定 SPIFFE ID,例如 spiffe://example.org/ns/production/sa/openai-wif
  • 專供存取 OpenAI 使用的單一 JWT-SVID 對象,例如 https://api.openai.com/v1,或你自行選擇的其他不透明值。
  • JWT 簽發者 URL,須出現在 JWT-SVID 的 iss 宣告中,供 OpenAI 驗證。
  • JWT-SVID 簽章金鑰的公開 JWKS,可透過 OIDC 探索或上傳 JWKS 提供。
  • 讓工作負載端能從 SPIFFE Workload API 取得最新 JWT-SVID 的方式。

對象是必須完全相符的識別碼,不一定是接收 JWT-SVID 的端點。你可以使用 https://api.openai.com/v1 或其他服務專屬值,只要 SPIFFE Workload API 請求與 OpenAI 提供者組態中的值相符即可。

可行時,請透過 SPIRE OIDC Discovery Provider 提供 SPIFFE 簽發者資訊。將 SPIRE Server 的 jwt_issuer 與 OIDC Discovery Provider 的 jwt_issuer 設定為同一個 HTTPS 簽發者 URL,並在 OpenAI 中設定相同的 URL。

在 SPIRE Server 組態中:

server {
  trust_domain = "example.org"
  jwt_issuer   = "https://spire-oidc.example.org"
}

在獨立的 SPIRE OIDC Discovery Provider 組態中:

# Relevant issuer fields only
domains    = ["spire-oidc.example.org"]
jwt_issuer = "https://spire-oidc.example.org"

OIDC Discovery Provider 組態也需要金鑰資料來源,例如 server_apiworkload_apifile,以及提供服務的機制,例如 ACME、TLS 憑證或 Unix 通訊端。如需完整的組態選項,請參閱 SPIRE OIDC Discovery Provider 文件

SPIFFE 信任網域與 JWT 簽發者是不同的概念。在此範例中,JWT-SVID 的主體是 example.org 信任網域中的 SPIFFE ID,而簽發者則是 HTTPS 簽發者 URL:

{
  "sub": "spiffe://example.org/ns/production/sa/openai-wif",
  "iss": "https://spire-oidc.example.org"
}

SPIRE OIDC Discovery Provider 提供 OIDC 探索文件與 JWKS 端點,供 OpenAI 在停用 使用上傳的 JWKS 驗證 Token 時使用。

如果 OpenAI 無法連線至你的簽發者探索端點,請改用上傳 JWKS 模式。在此模式下,OpenAI 仍會比對工作負載身分提供者的簽發者與 JWT-SVID 的 iss 宣告,但會使用你儲存在工作負載身分提供者中的 JWKS JSON 來驗證簽章。

注意: SPIFFE JWT-SVID 規格將 JWT 標頭 kid 列為選用,但 OpenAI 要求 JWT 主體 Token 必須包含 kid 標頭,以便從設定的 JWKS 中選取簽章金鑰。如果你的 SPIFFE 提供者允許省略 kid,請將它設定為在 OpenAI 工作負載身分聯合使用的 Token 中包含此標頭。

若要從能呼叫 SPIFFE Workload API 的工作負載檢查 JWT-SVID,請以你將在 OpenAI 中設定的相同對象請求一個 JWT-SVID。請在與應用程式相同的工作負載上下文中執行此指令,因為 Workload API 的授權取決於呼叫程序的身分。

TOKEN=$(spire-agent api fetch jwt \
  -socketPath /run/spire/sockets/agent.sock \
  -audience "https://api.openai.com/v1" | sed -n '2p')
export TOKEN

如果你的工作負載有多個 SPIFFE ID,請指定要請求的身分:

TOKEN=$(spire-agent api fetch jwt \
  -socketPath /run/spire/sockets/agent.sock \
  -spiffeID "spiffe://example.org/ns/production/sa/openai-wif" \
  -audience "https://api.openai.com/v1" | sed -n '2p')
export TOKEN

驗證 Token

設定工作負載身分聯合前,請先將 JWT-SVID 匯出為 TOKEN 環境變數,再於本機執行以下任一範例,檢查其標頭與宣告:

const parts = process.env.TOKEN?.split(".") ?? [];
if (parts.length !== 3) {
  throw new Error("Expected a compact JWT with three segments");
}

const decode = (segment) => {
  if (!/^[A-Za-z0-9_-]+$/.test(segment) || segment.length % 4 === 1) {
    throw new Error("JWT segment is not valid Base64URL");
  }
  const bytes = Buffer.from(segment, "base64url");
  if (bytes.toString("base64url") !== segment) {
    throw new Error("JWT segment is not valid Base64URL");
  }
  const decoded = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
  const value = JSON.parse(decoded);
  if (value === null || Array.isArray(value) || typeof value !== "object") {
    throw new Error("JWT segment is not a JSON object");
  }
  return decoded;
};

console.log("Header:");
console.log(decode(parts[0]));
console.log("\nPayload:");
console.log(decode(parts[1]));

每個範例都會解碼 JWT,但不會驗證 Token 簽章。請使用本機解碼器處理正式環境的 Token,並避免將正式環境的 Token 貼入第三方工具。

解碼後的 SPIFFE JWT-SVID 內容會類似以下範例:

{
  "alg": "ES256",
  "kid": "jwt-svid-key-1"
}
{
  "iss": "https://spire-oidc.example.org",
  "aud": ["https://api.openai.com/v1"],
  "sub": "spiffe://example.org/ns/production/sa/openai-wif",
  "iat": 1716235422,
  "exp": 1716235722
}

交換 Token 前,請使用解碼後的內容,比對收到的 Token 與 OpenAI 組態。檢查標頭中的 algkid,以及酬載中的 issaudsubiatexpalg 的實際值取決於你的 SPIRE Server JWT 簽章金鑰組態。

設定工作負載身分聯合

在 OpenAI 中為 SPIFFE JWT-SVID 簽發者建立工作負載身分提供者,再新增與你信任的 SPIFFE ID 相符的服務帳戶對應。

設定工作負載身分提供者

  1. 建立工作負載身分提供者。名稱 設定為唯一值,例如 spiffe-prod。使用 說明欄位協助管理員識別提供者,例如填入 Production SPIFFE workloads

  2. 設定簽發者與對象。OIDC 簽發者 URL 設定為與 JWT-SVID 的 iss 宣告完全相同的值,例如 https://spire-oidc.example.org。將 對象 設定為向 SPIFFE Workload API 發出請求時使用的對象值。在此範例中,該值為 https://api.openai.com/v1

  3. 選擇 JWKS 來源。 如果 OpenAI 能連線至你的 SPIRE OIDC Discovery Provider,請讓 使用上傳的 JWKS 驗證 Token 保持停用。OpenAI 會透過 OIDC 探索及探索到的 JWKS 驗證 JWT-SVID 簽章。

    如果 OpenAI 無法連線至簽發者,請啟用 使用上傳的 JWKS 驗證 Token,再將 JWKS JSON 設定為 JWT-SVID 簽章金鑰的公開金鑰集。請上傳完整的公開 JWKS 物件,包含包覆金鑰的 keys 陣列。請勿包含私密金鑰資料。

  4. 僅在需要衍生對應屬性時新增屬性轉換。 直接從 sub 進行對應時,不需要屬性轉換。只有在需要從一或多個 Token 宣告衍生出對應值時,才使用屬性轉換。如需轉換行為的詳細資訊,請參閱工作負載身分聯合主要指南

設定服務帳戶對應

  1. 建立服務帳戶對應。名稱 設定為在該工作負載身分提供者內唯一的值,例如 production-openai-wif。使用 說明欄位說明哪些工作負載可以使用此對應,例如填入 Production SPIFFE workload for OpenAI API access

  2. 比對 SPIFFE ID。 設定為 sub,並將 設定為工作負載的 SPIFFE ID,例如 spiffe://example.org/ns/production/sa/openai-wif

    對於具特殊權限的工作負載,請優先採用 SPIFFE ID 完全相符的比對方式。只有在該前綴下的每個 SPIFFE ID 都應能取得新簽發的 OpenAI 存取權杖時,才使用結尾萬用字元。例如,spiffe://example.org/ns/production/sa/* 允許任何相符的正式環境服務帳戶路徑。

  3. 選擇 OpenAI 目標。專案 設定為目標服務帳戶所屬的 OpenAI 專案。將 服務帳戶 設定為 SPIFFE 工作負載可使用的 OpenAI 服務帳戶,例如 spiffe-prod-openai-wif。若想為此對應建立新的服務帳戶,而非重用現有帳戶,請勾選 Create a new service account in this project

  4. 視需要縮小 API 權限範圍。 選取適當的 權限 ,例如 api.model.requestapi.vector_store.read,進一步限制透過此對應簽發的存取權杖。將權限留白,即可避免新增 WIF 專屬的範圍限制;Token 仍會以對應的服務帳戶身分進行授權。

在程式碼中使用 Token

設定 OpenAI SDK 用戶端,將最新的 SPIFFE JWT-SVID 交換為 OpenAI 簽發的存取權杖。

以下 SDK 範例假設你的 SPIFFE 整合會更新 JWT-SVID 並將其寫入 /var/run/spiffe/openai.jwt。請確保只有該工作負載能讀取此檔案。由於 JWT-SVID 的有效期很短,請在 Token 到期前更新檔案。另一種做法是在可行時,於主體 Token 提供者中使用對應程式語言的 SPIFFE 程式庫,直接從 SPIFFE Workload API 取得 JWT-SVID,以免 Token 檔案過時。

在工作負載環境中設定 OPENAI_IDENTITY_PROVIDER_IDOPENAI_SERVICE_ACCOUNT_ID。Token 檔案包含外部主體 Token。OPENAI_IDENTITY_PROVIDER_ID 用來識別 OpenAI 工作負載身分提供者,OPENAI_SERVICE_ACCOUNT_ID 則用來識別目標 OpenAI 服務帳戶。接著,OpenAI 會根據 Token 宣告,尋找該提供者與服務帳戶的相符對應。

使用 SPIFFE JWT-SVID 進行身分驗證
import { readFile } from "node:fs/promises";
import OpenAI from "openai";

const tokenPath = "/var/run/spiffe/openai.jwt";
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 spiffeJwtSvidProvider(path) {
  return {
    tokenType: "jwt",
    getToken: async () => {
      const token = (await readFile(path, "utf8")).trim();
      if (!token) {
        throw new Error("The SPIFFE JWT-SVID file is empty.");
      }
      return token;
    },
  };
}

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

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

console.log(response.output_text);

SPIFFE 最佳實務

  • 請使用 JWT-SVID 進行 OpenAI 工作負載身分聯合。X.509-SVID 適用於雙向 TLS,但 OpenAI Token 交換端點不接受此類 SVID。
  • 請使用單一專用對象來存取 OpenAI。避免使用範圍過大的對象,例如整個信任網域或環境名稱。
  • 盡可能採用 SPIFFE ID 完全相符的比對方式。只有在刻意共用信任邊界時,才使用萬用字元對應。
  • 將 JWT-SVID 的有效期設短一些,以降低持有者 Token 遭重放的風險。OpenAI 存取權杖的到期時間絕不會晚於交換時使用的外部主體 Token。
  • 請謹慎輪替簽章金鑰。在輪替期間,透過 OIDC 探索同時發布新舊公開金鑰;或在簽發使用新 kid 的 JWT-SVID 前,更新已上傳的公開 JWKS。
  • 讓 SPIRE Server 與工作負載的時鐘保持同步。時鐘偏差過大,可能導致原本有效的 JWT-SVID 被判定為尚未生效、簽發時間過久或已到期而遭到拒絕。
  • 保護 SPIFFE Workload API 通訊端。能取得工作負載 JWT-SVID 的程序,就能嘗試用它交換 OpenAI 存取權。
  • 讓 OpenAI 服務帳戶的邊界與應用程式和環境的權限邊界保持一致。不要讓互不相關的 SPIFFE 工作負載共用高權限服務帳戶。
  • 監控 Token 交換失敗的情況,檢查是否因簽發者、對象、簽署金鑰或對應不符所致。