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

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

Idira Secure Workload Access(SWA)を使用すると、OpenAI API キーを保存せずに OpenAI API を呼び出せます。SWA はワークロードに SPIFFE ID を割り当て、その ID を表す署名付きトークンである JWT-SVID を発行します。OpenAI SDK は、このトークンを有効期間の短い OpenAI アクセストークンと交換します。このアクセストークンには、マッピング先のサービスアカウントの権限が適用されます。

このガイドでは OpenAI API の設定手順を説明します。Codex を使用する場合は、このガイドの手順に従ってワークロードにトークンを渡してから、Codex でのワークロード ID の使用に進んでください。

前提条件

以下が必要です。

  • トラストドメインと、ワークロードに所定の SPIFFE ID を割り当てるアテステーションポリシーを設定した SWA 環境
  • ワークロードから SWA Agent の Workload API ソケットにアクセスできること
  • OpenAI 組織でワークロード ID プロバイダー、サービスアカウントのマッピング、プロジェクト、サービスアカウントを管理する権限
  • ワークロード ID の認証情報に対応した OpenAI SDK

Idira の OpenAI 連携ガイドに記載されている前提条件に従って、SWA インフラのセットアップを完了してください。

発行者 URL と署名鍵の取得

トラストドメインの jwt.discovery_endpoints.oidc_discovery_url と jwt.discovery_endpoints.jwks_uri を取得します。これらの値の確認方法は、Idira の OIDC 設定手順を参照してください。

OpenAI が認証情報を使わずに、HTTPS 経由でディスカバリードキュメントと JWKS にアクセスできる必要があります。発行者 URL は、トークンの iss クレームに含まれる HTTPS URL です。sub に含まれる SPIFFE ID はワークロードを識別します。

OpenAI へのアクセス専用のオーディエンスを選びます。たとえば https://api.openai.com/v1 を使用できます。JWT-SVID をリクエストするときと OpenAI プロバイダーを設定するときには、同じ値を使用します。オーディエンスはトークンの受信者を示す値です。トークン交換のエンドポイントを指定するものではありません。

SWA はデフォルトで RS512 と 4096 ビットの RSA 鍵を使用して署名します。OpenAI の JWT 検証機能はこの組み合わせに対応しています。SWA で使用できるその他の署名オプションについては、Idira の JWT 要件を参照してください。

ワークロードへの最新の JWT-SVID の配布

ワークロード環境に spiffe-helper をインストールし、SWA Agent から JWT-SVID を取得して更新できるようにします。以下の設定を helper.conf として保存します。ヘルパーはトークンを /var/run/spiffe/openai.jwt に書き込みます。このパスは SPIFFE 向けの共通 SDK サンプルでも使用します。

agent_address = "/tmp/swa-agent/public/api.sock"
cert_dir      = "/var/run/spiffe"
daemon_mode   = true

jwt_svids = [{
  jwt_audience       = "https://api.openai.com/v1"
  jwt_svid_file_name = "openai.jwt"
}]

Kubernetes では、ワークロードの Pod 内でヘルパーをサイドカーとして実行します。メモリを使用する emptyDir ボリュームを /var/run/spiffe で共有し、SWA ソケットの親ディレクトリ /tmp/swa-agent/public をヘルパーにマウントします。VM では /run/swa-agent/api.sock を agent_address に指定し、トークンディレクトリをメモリ上のストレージに配置します。ソケットへのアクセスとアテステーションの設定は、Idira のデプロイ手順に従ってください。

ヘルパーを起動する前にトークンディレクトリを作成し、ヘルパーに書き込み権限を付与します。サイドカーまたは VM のサービスで、以下のコマンドを実行してこの設定でヘルパーを起動します。

spiffe-helper -config helper.conf

トークンファイルとエージェントソケットへのアクセスは、それぞれを必要とするプロセスに限定してください。トークンの有効期限が切れる前にヘルパーが新しいトークンに置き換えられるよう、ヘルパーは稼働させたままにします。

使用する言語に SPIFFE Workload API クライアントがある場合は、ヘルパーを使う代わりに、サブジェクトトークンプロバイダー内で最新の JWT-SVID を取得できます。Idira の連携ガイドで、Workload API を直接使用する方法を参照してください。

トークンの内容の確認

ワークロード内で、ローカルのデコーダーが使用する環境変数にトークンを読み込みます。

export TOKEN="$(cat /var/run/spiffe/openai.jwt)"
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]));

OpenAI プロバイダーを作成する前に、以下のフィールドを確認します。

フィールド 期待する値
ヘッダーの alg 設定した署名アルゴリズム(例:RS512)。
ヘッダーの kid トラストドメインの公開 JWKS に含まれる署名鍵の ID。
iss トラストドメインの HTTPS 発行者 URL。
sub このワークロードに割り当てられた SPIFFE ID。
aud OpenAI へのアクセス用に選んだオーディエンスが含まれていること。
iat と exp トークンの発行時刻と有効期限。有効期限内のトークンを使用してください。

デコーダーは署名を検証せずにクレームを読み取ります。トークンをログに記録したり、ウェブ上のデコーダーに貼り付けたりしないでください。確認後は TOKEN の設定を解除してください。

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

ワークロード ID プロバイダーの作成

組織設定 > セキュリティ > ワークロード ID プロバイダーに移動し、以下の設定でプロバイダーを作成します。

設定項目 値
名前 一意の名前(例:idira-prod)。
説明 このプロバイダーを使用するアプリケーションと環境を記載します。
OIDC 発行者 URL JWT-SVID の iss の値。
オーディエンス ヘルパーがリクエストしたオーディエンス(例:https://api.openai.com/v1)。
アップロードした JWKS をトークンの検証に使用 OIDC ディスカバリーを使用するため、オフのままにします。
属性変換 sub から直接マッピングする場合は空欄にします。

OpenAI API のトークン交換では、発行者 URL を比較する際に末尾のスラッシュを無視します。たとえば、https://issuer.example.com と https://issuer.example.com/ は一致します。スキームやパスを含め、それ以外の文字はすべて一致する必要があります。オーディエンスの値は完全に一致する必要があります。設定に一貫性を持たせるため、発行されたトークンの発行者 URL をそのままコピーしてください。

OpenAI からディスカバリードキュメントまたは JWKS にアクセスできない場合は、プロバイダーの共通設定手順に従って公開 JWKS をアップロードしてください。SWA が署名鍵をローテーションしたら、アップロードした鍵も更新してください。

SPIFFE ID とサービスアカウントのマッピング

  1. プロバイダーでサービスアカウントのマッピングを作成し、idira-production-workload などの名前を付けます。
  2. キーに sub を指定し、値にワークロードのトークンに含まれる SPIFFE ID をそのまま指定します(例:spiffe://prod.example.com/k8s-nodegroup/ns/my-namespace/sa/my-service-account)。
  3. ワークロードが使用できるプロジェクトとサービスアカウントを選択します。
  4. ワークロードに必要な権限を選択します。たとえば、モデルへのリクエストには api.model.request を選択します。ここでサービスアカウントのアクセス範囲を狭めることはできますが、元の範囲を超える権限は付与できません。権限を空欄にすると、WIF 固有の制限は追加されません。

アプリケーションと環境の組み合わせごとに、別のサービスアカウントを使用してください。SPIFFE ID は完全一致で指定することを推奨します。同じプレフィックスを持つすべての ID に同じアクセス権を付与する場合に限り、末尾にワイルドカードを使用してください。マッピングの条件が重複しないようにしてください。詳しくは、SPIFFE のサービスアカウントマッピングを参照してください。

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

OpenAI プロバイダーの ID と選択したサービスアカウントの ID を、ワークロードの環境変数に設定します。

export OPENAI_IDENTITY_PROVIDER_ID="<workload identity provider ID>"
export OPENAI_SERVICE_ACCOUNT_ID="<service account ID>"

以下の SPIFFE 共通サンプルでは /var/run/spiffe/openai.jwt を読み取ります。SDK がトークン交換で OpenAI アクセストークンを取得または更新するたびに、サブジェクトトークンプロバイダーはその時点のトークンを返します。外部の JWT-SVID は SWA とヘルパーが更新し、OpenAI アクセストークンは OpenAI SDK が管理します。

Idira が発行した 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);

動作確認とトラブルシューティング

アテステーション済みのワークロード内で、OPENAI_API_KEY を設定していない状態でサンプルを実行します。リクエストが成功すると、モデルの応答が出力されます。ヘルパーが JWT-SVID を置き換え、SDK が OpenAI アクセストークンを更新した後も、リクエストが引き続き成功することを確認してください。

症状 確認事項
ヘルパーがワークロード ID を取得できない ワークロードが SWA のアテステーションポリシーに適合し、エージェントソケットにアクセスできることを確認します。確認はワークロードの実行コンテキストで行ってください。
トークンファイルが存在しない、空である、またはトークンの有効期限が切れている ヘルパーが稼働していること、ヘルパーとワークロードで共有ボリュームとファイルパスが一致していること、ワークロードがファイルを読み取れることを確認します。各ホストの時計は同期させてください。
トークンの検証に失敗する iss、aud、kid、トークンの有効期限を確認し、ディスカバリードキュメントと JWKS にアクセスできるか確認します。発行者 URL は前述のルールに従って比較してください。
一致するサービスアカウントのマッピングがない プロバイダー ID とサービスアカウント ID が正しいこと、マッピングが有効であること、sub の値が完全に一致することを確認します。
複数のマッピングが一致する 一致する有効なマッピングがちょうど 1 つになるように、重複するマッピングの条件を絞り込むか、該当するマッピングを無効にします。
トークン交換は成功するが、API がリクエストを拒否する マッピング先のサービスアカウントのプロジェクトと権限、および適用される API アクセスポリシーを確認します。

SWA のデプロイ環境で問題を診断する方法は、Idira の連携に関するトラブルシューティングを参照してください。