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

Kubernetes 向けワークロード ID フェデレーションの構成

射影された Kubernetes サービスアカウントトークンを有効期間の短い OpenAI アクセストークンと交換することで、Kubernetes をワークロード ID プロバイダーとして使用できます。

Codex を使用する場合は、このページの手順で射影されたトークンを取得し、内容を確認します。その後、Codex のワークロード ID を構成し、マウントされたトークンファイルを Codex の参照先に指定します。このページのサービスアカウントマッピングと SDK の例は、OpenAI API 向けのものです。

Kubernetes のセットアップ

このガイドでは、Kubernetes のサービスアカウントトークンの射影が有効になっていることを前提としています。この機能は、最近の Kubernetes リリースではデフォルトで利用できます。OpenAI のワークロード ID フェデレーションには、OIDC に準拠した射影サービスアカウントトークンが必要です。Secret に保存される従来の Kubernetes サービスアカウントトークンはサポートされていません。

OpenAI API を呼び出す必要があるワークロードには、Kubernetes の ServiceAccount を使用します。まだない場合は、次のように作成します。

kubectl create serviceaccount openai-wif --namespace default

Kubernetes クラスターの OIDC 発行者を取得します。

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

JWKS をアップロードし、OpenAI が OIDC 発行者に対して JWKS ディスカバリーを行わない場合でも、この発行者はワークロード ID プロバイダーに設定された発行者と一致する必要があります。

クラスターの JWKS を取得し、返された鍵セットを保存します。ワークロード ID プロバイダーの構成時に必要になります。

kubectl get --raw /openid/v1/jwks

射影されるサービスアカウントトークンに、OpenAI が想定するオーディエンスと、ワークロードに適した有効期限を設定します。OpenAI はトークンの発行者、署名、オーディエンス、有効期限を検証します。この例では、トークンファイルを /var/run/secrets/tokens/token にマウントし、オーディエンスに https://api.openai.com/v1 を使用し、有効期限を 3600 秒に設定しています。射影されたトークンのオーディエンスと OpenAI のワークロード ID プロバイダーのオーディエンスが一致していれば、別のオーディエンスを使用することもできます。

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

トークンの確認

ワークロード ID フェデレーションを構成する前に、射影されたサービスアカウントトークンのサンプルをローカルでデコードし、クレームを確認します。射影されたトークンがマウントされている実行中の Pod からトークンを取得し、TOKEN という環境変数としてエクスポートします。

TOKEN=$(kubectl exec -n default openai-wif-app -- cat /var/run/secrets/tokens/token)
export TOKEN

次に、以下のスクリプトを実行します。

const parts = process.env.TOKEN?.split(".") ?? [];
if (parts.length !== 3) {
  throw new Error("Expected a compact JWT with three segments");
}
if (!/^[A-Za-z0-9_-]+$/.test(parts[1]) || parts[1].length % 4 === 1) {
  throw new Error("JWT payload is not valid Base64URL");
}

const bytes = Buffer.from(parts[1], "base64url");
if (bytes.toString("base64url") !== parts[1]) {
  throw new Error("JWT payload is not valid Base64URL");
}
const decoded = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
const claims = JSON.parse(decoded);
if (claims === null || Array.isArray(claims) || typeof claims !== "object") {
  throw new Error("JWT payload is not a JSON object");
}
console.log(decoded);

このコマンドは、トークンの署名を検証せずに JWT ペイロードをデコードします。本番環境のトークンにはローカルのデコーダーを使用し、サードパーティーのツールに貼り付けないでください。

射影された Kubernetes サービスアカウントトークンをデコードすると、次のような内容になります。

{
  "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"
    }
  }
}

デコードしたペイロードを使って、取得したトークンを、OpenAI に設定した発行者、オーディエンス、マッピングの値と比較します。構成に関する問題の多くは、トークンを交換する前に issaudsub クレームで確認できます。

ワークロード ID フェデレーションのセットアップ

Kubernetes の発行者に対応するワークロード ID プロバイダーを OpenAI で作成し、射影されたトークンの属性に一致するサービスアカウントマッピングを追加します。

まずワークロード ID プロバイダーを構成し、その後でサービスアカウントマッピングを作成します。

ワークロード ID プロバイダーのセットアップ

  1. ワークロード ID プロバイダーを作成します。 名前 には、kubernetes-prod などの一意の値を設定します。管理者がクラスターを識別しやすいように、 説明には Production Kubernetes cluster などを入力します。

  2. 発行者とオーディエンスを設定します。 OIDC 発行者 URL には、kubectl get --raw /.well-known/openid-configuration | jq -r .issuer で返された発行者を設定します。この値は、射影されたトークンの iss クレームと一致する必要があります。 オーディエンス には、射影サービスアカウントトークンのボリュームに設定したものと同じ、不透明なオーディエンス文字列を設定します。この例では、その値は https://api.openai.com/v1 です。

  3. Kubernetes の JWKS をアップロードします。 アップロードした JWKS をトークンの検証に使用を有効にし、 JWKS JSONkubectl get --raw /openid/v1/jwks の出力を設定します。OpenAI はこの公開鍵セットを使用して、射影された Kubernetes サービスアカウントトークンを検証します。鍵セットを格納する keys も含めて、鍵セット全体をアップロードしてください。

    注: セルフホスト型の Kubernetes クラスターでは、OpenAI はローカル JWKS モードのみをサポートしています。クラスターが返す JWKS をアップロードしてください。OpenAI は、設定された発行者に対して OIDC ディスカバリーを行いません。ただし、設定された発行者とトークンの iss フィールドの比較は行います。

    クラスターでサービスアカウントの署名鍵をローテーションする場合は、ワークロード ID プロバイダーの構成で、アップロード済みの JWKS を更新してください。設定された JWKS に存在しない鍵で署名されたトークンは拒否されます。JWKS に有効な公開鍵が複数含まれている場合は、keys 配列全体を含めてください。

  4. マッピング用の派生属性が必要な場合にのみ、属性変換を追加します。 subaudiss など、トークンの元のクレームは、マッピングのアサーションでそのまま使用できます。元のクレームではなく変換後の属性を照合に使う場合、ダッシュボードが openai. プレフィックスを自動的に付加します。たとえば、属性名に workload_subject、式に assertion.sub を入力すると、openai.workload_subject が作成されます。もともと openai. で始まるトークンのクレームは、対応する変換が設定されていない限り、openai. で始まるマッピングキーでは無視されます。

サービスアカウントマッピングのセットアップ

  1. サービスアカウントマッピングを作成します。 名前 には、openai-mapping-kubernetes など、ワークロード ID プロバイダー内で一意の値を設定します。 説明には Workload Identity Provider Mapping for Kubernetes Workloads などを入力し、どのワークロードがこのマッピングを使用できるかを記述します。

  2. Kubernetes サービスアカウントのサブジェクトを照合します。 キーsubsystem:serviceaccount:default:openai-wif に設定します。Kubernetes サービスアカウントのサブジェクトの形式は system:serviceaccount:<namespace>:<service-account-name> です。

  3. OpenAI 側の対象を選択します。 プロジェクト には、対象のサービスアカウントが属する OpenAI プロジェクトを設定します。 サービスアカウント には、kubernetes-prod-openai-wif など、Kubernetes ワークロードが使用できる OpenAI サービスアカウントを設定します。既存のサービスアカウントを再利用せず、このマッピング用に新しく作成する場合は、Create a new service account in this project にチェックを入れます。

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

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

射影された Kubernetes トークンを読み取り、OpenAI が発行するアクセストークンと交換するように、OpenAI SDK クライアントを構成します。

SDK のワークロード ID フェデレーションプロバイダーでは、/var/run/secrets/tokens/token などのマウントされたトークンのパスを、サブジェクトトークンの取得元として使用します。SDK はその Kubernetes トークンを OpenAI が発行するアクセストークンと交換し、OpenAI のトークンで API リクエストを認証します。

次の例では、カスタムのサブジェクトトークンプロバイダーを使用して OpenAI クライアントを初期化します。このプロバイダーは、マウントされたファイルのパスから射影された Kubernetes サービスアカウントトークンを読み取り、ワークロード ID フェデレーションのサブジェクトトークンとして使用します。

射影された Kubernetes サービスアカウントトークンによる認証
import { readFile } from "node:fs/promises";
import OpenAI from "openai";

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) {
  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-5.6-terra",
  input: "Say hello from Kubernetes workload identity federation.",
});

console.log(response.output_text);

Kubernetes のベストプラクティス

  • 安定した OIDC 発行者を使用してください。発行者 URL は、射影されたサービスアカウントトークンの iss クレームと一致する必要があります。また、クラスターのアップグレードやメンテナンスの際にも変更されないことが望まれます。
  • 署名鍵を厳重に保護してください。クラスターのサービスアカウント署名鍵にアクセスできる人は誰でも、OpenAI が受け入れる可能性のあるトークンを発行できます。
  • OpenAI との連携には専用のサービスアカウントを使用してください。無関係なインフラストラクチャーやアプリケーションへのアクセスにも使われているサービスアカウントの再利用は避けてください。
  • アップロード済みの JWKS を最新の状態に保ってください。ローカル JWKS モードでは、OpenAI は設定された JWKS を使用してワークロード ID トークンを検証します。そのため、新しい署名鍵にローテーションする前に、ワークロード ID プロバイダーを更新してください。
  • カスタムクレームはできるだけシンプルにしてください。照合には、subaud などの標準クレーム、またはそれらのクレームから直接変換した属性を優先して使用してください。
  • 名前空間の所有権もセキュリティモデルの一部として扱ってください。名前空間の管理者がサービスアカウントを作成できる場合は、意図しない権限昇格を防ぐため、マッピングのスコープが適切に設定されていることを確認してください。
  • 発行者と署名鍵の変更を監視してください。ワークロード ID プロバイダーの JWKS を更新せずに署名鍵をローテーションすると、トークンの交換に失敗する可能性があります。