For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
メインナビゲーション
Theme

SPIFFE 向けワークロード ID フェデレーションの設定

SPIFFE JWT-SVID を有効期間の短い OpenAI アクセストークンに交換することで、SPIFFE をワークロード ID プロバイダーとして利用できます。これにより、SPIRE または他の SPIFFE 互換 ID プロバイダーで認証されたワークロードは、長期間有効な API キーを保存せずに OpenAI API を呼び出せます。

Idira Secure Workload Access を使用する場合は、Idira セットアップガイドに従ってエージェントとトークン配信を設定してください。

OpenAI は、発行者、オーディエンス、有効期限、発行日時が含まれ、JWKS の公開鍵で署名を検証できる SPIFFE JWT-SVID を JWT サブジェクトトークンとしてサポートしています。SPIFFE X.509-SVID は、OpenAI のワークロード ID フェデレーションのサブジェクトトークンとしては使用できません。

JWT-SVID 仕様では、sub、aud、exp の各クレームが必須です。OpenAI で JWT-SVID を使用するには、さらに iss と iat の各クレーム、および kid ヘッダーが必要です。OpenAI はこれらを使って、ワークロード ID プロバイダーの設定に照らしてトークンを検証します。

JWT-SVID は OpenID Connect の ID トークンではありません。SPIRE OIDC Discovery Provider は、OpenAI が JWT-SVID を検証するためのディスカバリメタデータと JWKS の公開鍵を提供します。トークンは引き続き SPIFFE 仕様に従って解釈され、OIDC のログインフローは不要です。

SPIFFE の用語とトークンの要件については、SPIFFE の JWT-SVID 仕様と Workload API 仕様を参照してください。

SPIFFE の設定

OpenAI API を呼び出すワークロードに JWT-SVID を発行するように、SPIFFE プロバイダーを設定します。ここでは SPIRE の用語を使用しますが、他の SPIFFE 互換プロバイダーでも OpenAI 側の設定は同じです。プロバイダーが発行する JWT-SVID には、OpenAI が検証できる発行者情報と、JWKS の公開鍵で検証できる署名が必要です。

SPIFFE 側では次のものを用意してください。

  • spiffe://example.org/ns/production/sa/openai-wif など、ワークロードに割り当てる固定の SPIFFE ID
  • https://api.openai.com/v1 など、OpenAI へのアクセス専用の単一の JWT-SVID オーディエンス(任意の不透明な識別子も使用可能)
  • OpenAI での検証に使用する JWT 発行者 URL(JWT-SVID の iss クレームに含める値)
  • JWT-SVID の署名鍵に対応する公開 JWKS(OIDC ディスカバリまたは JWKS のアップロードで提供)
  • ワークロード側で SPIFFE Workload API から新しい JWT-SVID を取得する仕組み

オーディエンスは完全一致で照合する識別子です。JWT-SVID を受け取るエンドポイントを指す必要はありません。SPIFFE Workload API へのリクエストと OpenAI のプロバイダー設定で値が一致していれば、https://api.openai.com/v1 やサービス固有の別の値を使用できます。

可能であれば、SPIRE OIDC Discovery Provider を通じて SPIFFE の発行者情報を公開してください。SPIRE Server の jwt_issuer と OIDC Discovery Provider の jwt_issuer の両方に、OpenAI で設定するものと同じ HTTPS 発行者 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_api、workload_api、file などを設定する必要があります。また、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 をトークン検証に使用が無効の場合にこれらを使用できます。

OpenAI から発行者のディスカバリエンドポイントにアクセスできない場合は、JWKS をアップロードして使用してください。この場合も、OpenAI はワークロード ID プロバイダーに設定された発行者と JWT-SVID の iss クレームを照合します。署名の検証には、ワークロード ID プロバイダーに保存した JWKS JSON を使用します。

注: SPIFFE の JWT-SVID 仕様では、JWT ヘッダーの kid は任意です。一方、OpenAI は設定済みの JWKS から署名鍵を選択するため、JWT サブジェクトトークンに kid ヘッダーが必要です。SPIFFE プロバイダーが kid を省略することがある場合は、OpenAI のワークロード ID フェデレーション用のトークンには必ず含めるように設定してください。

SPIFFE Workload API を呼び出せるワークロードで JWT-SVID の内容を確認するには、OpenAI に設定するものと同じオーディエンスを指定してトークンをリクエストします。Workload API は呼び出し元プロセスの ID に基づいてアクセスを許可するため、次のコマンドはアプリケーションと同じワークロードコンテキストで実行してください。

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 がある場合は、使用する 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

トークンの確認

ワークロード ID フェデレーションを設定する前に、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 をデコードするだけで、トークンの署名は検証しません。本番環境のトークンはローカルのデコーダーで確認し、サードパーティのツールには貼り付けないでください。

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
}

受け取ったトークンを交換する前に、デコードした内容を OpenAI の設定と照合してください。ヘッダーでは alg と kid を、ペイロードでは iss、aud、sub、iat、exp を確認します。alg の値は SPIRE Server の JWT 署名鍵の設定によって異なります。

ワークロード ID フェデレーションの設定

SPIFFE JWT-SVID の発行者に対応するワークロード ID プロバイダーを OpenAI で作成し、信頼する SPIFFE ID に一致するサービスアカウントのマッピングを追加します。

ワークロード ID プロバイダーの設定

  1. ワークロード ID プロバイダーを作成します。 名前には 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 をトークン検証に使用を無効のままにします。OpenAI は OIDC ディスカバリで JWKS を取得し、その公開鍵で JWT-SVID の署名を検証します。

    OpenAI から発行者にアクセスできない場合は、アップロードした JWKS をトークン検証に使用を有効にし、JWKS JSON に JWT-SVID の署名鍵に対応する公開鍵セットを設定します。各鍵を格納する keys 配列を含め、公開 JWKS オブジェクト全体をアップロードしてください。秘密鍵の情報は含めないでください。

  4. クレームからマッピング用の属性を導出する場合のみ、属性変換を追加します。 sub を直接マッピングする場合、属性変換は不要です。1 つ以上のトークンクレームからマッピングに使用する値を導出する必要がある場合にのみ使用してください。変換の仕組みについては、ワークロード ID フェデレーションのメインガイドを参照してください。

サービスアカウントのマッピング設定

  1. サービスアカウントのマッピングを作成します。 名前には、production-openai-wif など、ワークロード ID プロバイダー内で一意の値を設定します。説明には 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-prod-openai-wif など、SPIFFE ワークロードが使用できる OpenAI サービスアカウントを設定します。既存のサービスアカウントを再利用せず、このマッピング用に新規作成する場合は、Create a new service account in this project にチェックを入れます。

  4. 必要に応じて API 権限を絞り込みます。 権限で api.model.request や api.vector_store.read などの適切な権限を選択すると、このマッピングで発行されるアクセストークンの権限をさらに制限できます。WIF 固有のスコープ制限を追加しない場合は、権限を空欄にしてください。その場合も、トークンにはマッピング先のサービスアカウントの権限が適用されます。

コードでのトークンの使用

新しく取得した SPIFFE JWT-SVID を OpenAI が発行するアクセストークンに交換するように、OpenAI SDK クライアントを設定します。

以下の SDK サンプルでは、SPIFFE との連携処理で JWT-SVID を更新し、/var/run/spiffe/openai.jwt に書き込むことを前提としています。ファイルの読み取り権限はワークロードだけに付与してください。JWT-SVID の有効期間は短いため、トークンの有効期限が切れる前にファイルを更新してください。使用する言語の SPIFFE ライブラリが対応していれば、サブジェクトトークンプロバイダー内で SPIFFE Workload API から JWT-SVID を直接取得する方法もあります。これにより、期限切れのトークンファイルを使用せずに済みます。

ワークロードの環境変数 OPENAI_IDENTITY_PROVIDER_ID と OPENAI_SERVICE_ACCOUNT_ID を設定します。トークンファイルには外部サブジェクトトークンが格納されています。OPENAI_IDENTITY_PROVIDER_ID は OpenAI のワークロード ID プロバイダーを、OPENAI_SERVICE_ACCOUNT_ID は対象の OpenAI サービスアカウントを識別します。OpenAI はトークンのクレームに基づいて、そのプロバイダーとサービスアカウントに一致するマッピングを検索します。

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 のベストプラクティス

  • OpenAI のワークロード ID フェデレーションには JWT-SVID を使用してください。X.509-SVID は相互 TLS に利用できますが、OpenAI のトークン交換エンドポイントでは受け付けません。
  • OpenAI へのアクセス専用のオーディエンスを 1 つ使用してください。トラストドメイン全体や環境名など、対象範囲の広いオーディエンスは避けてください。
  • 可能な限り SPIFFE ID を完全一致で照合してください。ワイルドカードによるマッピングは、複数のワークロードで意図的に信頼境界を共有する場合にのみ使用してください。
  • ベアラートークンを使ったリプレイ攻撃のリスクを抑えるため、JWT-SVID の有効期間は短く設定してください。OpenAI アクセストークンの有効期限が、交換に使用した外部サブジェクトトークンの有効期限を超えることはありません。
  • 署名鍵は慎重にローテーションしてください。切り替え期間中は OIDC ディスカバリで新旧両方の公開鍵を公開してください。公開 JWKS をアップロードしている場合は、新しい kid を持つ JWT-SVID を発行する前に JWKS を更新してください。
  • SPIRE Server とワークロードの時計を同期してください。時刻に大きなずれがあると、本来は有効な JWT-SVID でも、有効期間の開始前、発行からの時間超過、または有効期限切れと判定され、拒否されることがあります。
  • SPIFFE Workload API のソケットを保護してください。ワークロードの JWT-SVID を取得できるプロセスは、そのトークンを使って OpenAI アクセストークンへの交換を試みることができます。
  • アプリケーションや環境ごとの権限の境界に合わせて、OpenAI サービスアカウントを分けてください。互いに無関係な SPIFFE ワークロード間で、強い権限を持つサービスアカウントを共有しないでください。
  • トークン交換の失敗を監視し、発行者、オーディエンス、署名鍵、マッピングの不一致を検出してください。