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

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

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

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 に設定した発行者、オーディエンス、マッピングの値と照合します。設定上の問題の多くは、トークンを交換する前に iss、aud、sub の各クレームを確認することで見つけられます。

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

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

先にワークロード 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 JSON に kubectl get --raw /openid/v1/jwks の出力を設定します。OpenAI はこの公開鍵セットを使用して、Kubernetes の投影型サービスアカウントトークンを検証します。外側の keys フィールドを含め、鍵セット全体をアップロードしてください。

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

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

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

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

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

  2. Kubernetes サービスアカウントのサブジェクトを照合します。 キーに sub、値に 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 や api.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 クレームと一致している必要があります。クラスターのアップグレードやメンテナンスの際にも、同じ URL を維持してください。
  • 署名鍵は厳重に保護してください。クラスターのサービスアカウント署名鍵にアクセスできる人は誰でも、OpenAI が受け入れる可能性のあるトークンを発行できます。
  • OpenAI との連携には専用のサービスアカウントを使用してください。無関係なインフラやアプリケーションへのアクセスにも使われているサービスアカウントは再利用しないでください。
  • アップロードした JWKS を最新の状態に保ってください。ローカル JWKS モードでは、OpenAI は設定済みの JWKS を使ってワークロード ID トークンを検証します。新しい署名鍵に切り替える前に、ワークロード ID プロバイダーの JWKS を更新してください。
  • カスタムクレームはできるだけ単純にしてください。照合には、sub や aud などの標準クレームか、それらのクレームから直接導出した変換後の属性を優先して使用してください。
  • 名前空間を誰が管理するかをセキュリティモデルに組み込んでください。名前空間の管理者がサービスアカウントを作成できる場合は、意図しない権限昇格を防ぐため、マッピングの適用範囲を適切に制限してください。
  • 発行者と署名鍵の変更を監視してください。ワークロード ID プロバイダーの JWKS を更新せずに署名鍵をローテーションすると、トークンの交換に失敗することがあります。