Utilisez SPIFFE comme fournisseur d’identités de charge de travail en échangeant un JWT-SVID SPIFFE contre un jeton d’accès OpenAI de courte durée. Les charges de travail authentifiées par SPIRE ou un autre fournisseur d’identités compatible avec SPIFFE peuvent ainsi appeler l’API OpenAI sans stocker de clés API de longue durée.
Pour Codex, suivez les instructions de cette page afin d’obtenir et d’inspecter le JWT-SVID. Ensuite, configurez l’identité de charge de travail de Codex pour écrire ce jeton dans un fichier et indiquer ce fichier à Codex. Le mappage de compte de service et les exemples de SDK présentés sur cette page s’appliquent à l’API OpenAI.
OpenAI prend en charge les JWT-SVID SPIFFE qui peuvent être validés comme jetons de sujet JWT avec un émetteur, une audience, une date d’expiration, un horodatage d’émission et une signature vérifiable à l’aide d’un JWKS. OpenAI ne prend pas en charge les X.509-SVID SPIFFE comme jetons de sujet pour la fédération d’identités de charge de travail.
La spécification JWT-SVID exige les revendications sub, aud et exp. Pour utiliser un JWT-SVID avec OpenAI, le jeton doit également inclure les revendications iss et iat, ainsi qu’un en-tête kid, afin qu’OpenAI puisse le valider à partir de la configuration du fournisseur d’identités de charge de travail.
Un JWT-SVID n’est pas un jeton d’identité OpenID Connect. Le SPIRE OIDC Discovery Provider fournit les métadonnées de découverte et les clés JWKS qui permettent à OpenAI de valider le JWT-SVID ; il ne modifie pas la sémantique SPIFFE du jeton et n’exige pas de flux de connexion OIDC.
Pour connaître la terminologie SPIFFE et les exigences relatives aux jetons, consultez la spécification JWT-SVID et la spécification Workload API de SPIFFE.
Configuration de SPIFFE
Configurez votre fournisseur SPIFFE pour qu’il émette des JWT-SVID destinés aux charges de travail qui doivent appeler l’API OpenAI. Ces instructions utilisent la terminologie SPIRE, mais la même configuration OpenAI s’applique à tout fournisseur compatible avec SPIFFE qui émet des JWT-SVID dont l’émetteur et les éléments de signature JWKS peuvent être validés par OpenAI.
Votre installation SPIFFE doit fournir les éléments suivants :
- Un identifiant SPIFFE stable pour la charge de travail, par exemple
spiffe://example.org/ns/production/sa/openai-wif. - Une seule audience JWT-SVID dédiée à l’accès à OpenAI, par exemple
https://api.openai.com/v1ou une autre valeur opaque de votre choix. - Une URL d’émetteur JWT présente dans la revendication
issdu JWT-SVID pour permettre la validation par OpenAI. - Un JWKS public pour les clés de signature JWT-SVID, disponible via la découverte OIDC ou sous forme de JWKS importé.
- Un moyen, côté charge de travail, de récupérer de nouveaux JWT-SVID auprès de la SPIFFE Workload API.
L’audience est un identifiant qui doit correspondre exactement à la valeur configurée, et pas nécessairement un point de terminaison qui reçoit le JWT-SVID. Vous pouvez utiliser https://api.openai.com/v1 ou une autre valeur propre au service, à condition que la requête à la SPIFFE Workload API et la configuration du fournisseur dans OpenAI utilisent la même valeur.
Dans la mesure du possible, exposez l’émetteur SPIFFE via votre SPIRE OIDC Discovery Provider. Définissez jwt_issuer dans SPIRE Server et jwt_issuer dans OIDC Discovery Provider sur la même URL d’émetteur HTTPS que celle que vous configurerez dans OpenAI.
Dans la configuration de SPIRE Server :
server {
trust_domain = "example.org"
jwt_issuer = "https://spire-oidc.example.org"
}
Dans la configuration distincte du SPIRE OIDC Discovery Provider :
# Relevant issuer fields only
domains = ["spire-oidc.example.org"]
jwt_issuer = "https://spire-oidc.example.org"
La configuration d’OIDC Discovery Provider nécessite également une source de clés, telle que server_api, workload_api ou file, et un mécanisme pour servir les données, tel qu’ACME, un certificat TLS ou un socket Unix. Consultez la documentation du SPIRE OIDC Discovery Provider pour connaître toutes les options de configuration.
Le domaine de confiance SPIFFE et l’émetteur JWT sont deux concepts distincts. Dans cet exemple, le sujet du JWT-SVID est un identifiant SPIFFE appartenant au domaine de confiance example.org, tandis que l’émetteur est l’URL d’émetteur HTTPS :
{
"sub": "spiffe://example.org/ns/production/sa/openai-wif",
"iss": "https://spire-oidc.example.org"
}
Le SPIRE OIDC Discovery Provider expose un document de découverte OIDC et un point de terminaison JWKS qu’OpenAI peut utiliser lorsque l’option Utiliser un JWKS importé pour vérifier les jetons est désactivée.
Si OpenAI ne peut pas accéder au point de terminaison de découverte de votre émetteur, utilisez le mode JWKS importé. Dans ce mode, OpenAI compare toujours l’émetteur du fournisseur d’identités de charge de travail à la revendication iss du JWT-SVID, mais vérifie les signatures à l’aide du JSON JWKS que vous enregistrez dans la configuration du fournisseur d’identités de charge de travail.
Remarque : La spécification JWT-SVID de SPIFFE rend l’en-tête JWT
kidfacultatif, mais OpenAI exige que les jetons de sujet JWT incluent un en-têtekidpour pouvoir sélectionner la clé de signature dans le JWKS configuré. Si votre fournisseur SPIFFE peut omettrekid, configurez-le pour qu’il l’inclue pour la fédération d’identités de charge de travail OpenAI.
Pour inspecter un JWT-SVID depuis une charge de travail qui peut appeler la SPIFFE Workload API, demandez-en un pour l’audience que vous configurerez dans OpenAI. Exécutez cette commande dans le même contexte de charge de travail que l’application, car l’autorisation d’accès à la Workload API dépend de l’identité du processus appelant.
TOKEN=$(spire-agent api fetch jwt \
-socketPath /run/spire/sockets/agent.sock \
-audience "https://api.openai.com/v1" | sed -n '2p')
export TOKEN
Si votre charge de travail possède plusieurs identifiants SPIFFE, demandez explicitement l’identité souhaitée :
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
Vérifiez le jeton
Avant de configurer la fédération d’identités de charge de travail, exportez le JWT-SVID dans la variable TOKEN, puis exécutez l’un de ces exemples localement pour inspecter son en-tête et ses revendications :
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]));Chaque exemple décode le JWT sans vérifier sa signature. Utilisez un décodeur local pour les jetons de production et évitez de les coller dans des outils tiers.
Un JWT-SVID SPIFFE décodé ressemble à ceci :
{
"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
}
Avant d’échanger le jeton reçu, utilisez sa version décodée pour le comparer à la configuration OpenAI. Vérifiez alg et kid dans l’en-tête, ainsi que iss, aud, sub, iat et exp dans la charge utile. La valeur exacte de alg dépend de la configuration des clés de signature JWT de votre SPIRE Server.
Configuration de la fédération d’identités de charge de travail
Créez un fournisseur d’identités de charge de travail dans OpenAI pour l’émetteur des JWT-SVID SPIFFE, puis ajoutez un mappage de compte de service qui correspond aux identifiants SPIFFE auxquels vous faites confiance.
Configurez le fournisseur d’identités de charge de travail
-
Créez le fournisseur d’identités de charge de travail. Définissez Nom sur une valeur unique, par exemple
spiffe-prod. Renseignez le champ Description, par exemple avecProduction SPIFFE workloads, pour aider les administrateurs à identifier le fournisseur. -
Définissez l’émetteur et l’audience. Définissez URL de l’émetteur OIDC sur la valeur exacte de la revendication
issdu JWT-SVID, par exemplehttps://spire-oidc.example.org. Définissez Audience sur la valeur d’audience demandée à la SPIFFE Workload API. Dans cet exemple, cette valeur esthttps://api.openai.com/v1. -
Choisissez la source du JWKS. Laissez l’option Utiliser un JWKS importé pour vérifier les jetons désactivée lorsqu’OpenAI peut accéder à votre SPIRE OIDC Discovery Provider. OpenAI utilise la découverte OIDC et le JWKS ainsi obtenu pour vérifier les signatures des JWT-SVID.
Si l’émetteur n’est pas accessible depuis OpenAI, activez l’option Utiliser un JWKS importé pour vérifier les jetons, puis renseignez JSON JWKS avec l’ensemble des clés publiques correspondant aux clés de signature JWT-SVID. Importez l’objet JWKS public complet, y compris le tableau
keysqui contient les clés. N’incluez aucun élément de clé privée. -
Ajoutez des transformations d’attributs uniquement si vous avez besoin d’attributs dérivés pour le mappage. Les transformations d’attributs ne sont pas nécessaires lorsque le mappage utilise directement
sub. Utilisez-les uniquement si vous devez dériver une valeur de mappage d’une ou de plusieurs revendications du jeton. Consultez le guide principal sur la fédération d’identités de charge de travail pour comprendre le fonctionnement des transformations.
Configurez le mappage de compte de service
-
Créez un mappage de compte de service. Définissez Nom sur une valeur unique au sein du fournisseur d’identités de charge de travail, par exemple
production-openai-wif. Renseignez le champ Description, par exemple avecProduction SPIFFE workload for OpenAI API access, pour préciser quelle charge de travail peut utiliser ce mappage. -
Définissez la correspondance avec l’identifiant SPIFFE. Définissez Clé sur
subet Valeur sur l’identifiant SPIFFE de la charge de travail, par exemplespiffe://example.org/ns/production/sa/openai-wif.Privilégiez une correspondance exacte des identifiants SPIFFE pour les charges de travail disposant de privilèges élevés. Utilisez un caractère générique final uniquement si tous les identifiants SPIFFE commençant par ce préfixe doivent pouvoir obtenir des jetons d’accès OpenAI. Par exemple,
spiffe://example.org/ns/production/sa/*autorise tout chemin de compte de service de production correspondant. -
Choisissez la cible OpenAI. Définissez Projet sur le projet OpenAI auquel appartient le compte de service cible. Définissez Compte de service sur le compte de service OpenAI que la charge de travail SPIFFE peut utiliser, par exemple
spiffe-prod-openai-wif. CochezCreate a new service account in this projectsi vous souhaitez créer un compte de service pour ce mappage plutôt que d’en réutiliser un existant. -
Limitez les autorisations API si nécessaire. Sélectionnez les Autorisations appropriées, telles que
api.model.requestetapi.vector_store.read, pour restreindre davantage la portée des jetons d’accès émis à partir de ce mappage. Laissez ce champ vide pour ne pas ajouter de restriction de portée propre à la WIF ; le jeton continue d’autoriser les accès au nom du compte de service associé.
Utilisation du jeton dans le code
Configurez votre client du SDK OpenAI pour échanger un nouveau JWT-SVID SPIFFE contre un jeton d’accès émis par OpenAI.
Les exemples de SDK ci-dessous supposent que votre intégration SPIFFE renouvelle un JWT-SVID et l’écrit dans /var/run/spiffe/openai.jwt. Réservez l’accès en lecture à ce fichier à la seule charge de travail. Les JWT-SVID ayant une courte durée de validité, actualisez le fichier avant l’expiration du jeton. Vous pouvez aussi, lorsque c’est possible, utiliser une bibliothèque SPIFFE propre à votre langage dans le fournisseur de jetons de sujet pour récupérer le JWT-SVID directement auprès de la SPIFFE Workload API et éviter ainsi les fichiers de jetons périmés.
Définissez OPENAI_IDENTITY_PROVIDER_ID et OPENAI_SERVICE_ACCOUNT_ID dans l’environnement de la charge de travail. Le fichier de jeton contient le jeton de sujet externe. OPENAI_IDENTITY_PROVIDER_ID identifie le fournisseur d’identités de charge de travail OpenAI, et OPENAI_SERVICE_ACCOUNT_ID identifie le compte de service OpenAI cible. OpenAI recherche ensuite un mappage correspondant à ce fournisseur et à ce compte de service à partir des revendications du jeton.
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);Bonnes pratiques SPIFFE
- Utilisez des JWT-SVID pour la fédération d’identités de charge de travail OpenAI. Les X.509-SVID sont utiles pour le TLS mutuel, mais ne sont pas acceptés par le point de terminaison d’échange de jetons OpenAI.
- Utilisez une seule audience dédiée à l’accès à OpenAI. Évitez les audiences trop larges, telles qu’un domaine de confiance entier ou un nom d’environnement.
- Privilégiez une correspondance exacte des identifiants SPIFFE lorsque c’est possible. Utilisez des mappages avec caractères génériques uniquement pour des périmètres de confiance volontairement partagés.
- Limitez la durée de validité des JWT-SVID pour réduire le risque de rejeu des jetons au porteur. Les jetons d’accès OpenAI n’expirent jamais après le jeton de sujet externe utilisé pour l’échange.
- Effectuez la rotation des clés de signature avec précaution. Publiez les anciennes et les nouvelles clés publiques via la découverte OIDC pendant la période de rotation, ou mettez à jour le JWKS public importé avant d’émettre des JWT-SVID avec un nouveau
kid. - Maintenez les horloges de SPIRE Server et des charges de travail synchronisées. Un décalage d’horloge important peut entraîner le rejet de JWT-SVID par ailleurs valides, considérés comme pas encore valides, trop anciens ou expirés.
- Protégez le socket de la SPIFFE Workload API. Un processus capable de récupérer le JWT-SVID d’une charge de travail peut tenter de l’échanger contre un accès à OpenAI.
- Alignez les périmètres des comptes de service OpenAI sur les périmètres d’autorisation de vos applications et environnements. Ne partagez pas un compte de service disposant de privilèges élevés entre des charges de travail SPIFFE sans lien entre elles.
- Surveillez les échecs d’échange de tokens liés à des discordances d’émetteur, d’audience, de clé de signature ou de mappage.