Utilisez SPIFFE comme fournisseur d’identités de charges 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 par 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.
Si vous utilisez Idira Secure Workload Access, suivez le guide de configuration d’Idira pour configurer l’agent et la distribution des jetons.
OpenAI accepte les JWT-SVID SPIFFE qu’il peut valider comme jetons de sujet JWT. Ils doivent comporter un émetteur, une audience, une date d’expiration, un horodatage d’émission et une signature vérifiable à l’aide d’un jeu de clés JWKS. OpenAI n’accepte pas les X.509-SVID SPIFFE comme jetons de sujet pour la fédération d’identités de charges de travail.
La spécification JWT-SVID exige les revendications sub, aud et exp. Pour utiliser un JWT-SVID avec OpenAI, le jeton doit aussi comporter les revendications iss et iat ainsi qu’un champ d’en-tête kid. OpenAI peut ainsi valider le jeton à partir de la configuration du fournisseur d’identités de charges 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’impose 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 de la Workload API de SPIFFE.
Configuration de SPIFFE
Configurez votre fournisseur SPIFFE pour qu’il émette des JWT-SVID pour les charges de travail qui doivent appeler l’API OpenAI. Ces instructions emploient la terminologie de SPIRE. La même configuration côté OpenAI s’applique à tout fournisseur compatible avec SPIFFE qui émet des JWT-SVID, à condition qu’OpenAI puisse en valider l’émetteur et en vérifier la signature à l’aide des clés JWKS fournies.
Votre configuration 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 qui figure dans la revendication
issdu JWT-SVID pour permettre sa validation par OpenAI. - Un jeu public de clés JWKS pour vérifier les signatures des JWT-SVID, accessible via la découverte OIDC ou importé dans OpenAI.
- Un moyen pour la 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. Elle ne correspond 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 d’utiliser la même valeur dans la requête adressée à la SPIFFE Workload API et dans la configuration du fournisseur côté OpenAI.
Dans la mesure du possible, rendez l’émetteur SPIFFE accessible via votre SPIRE OIDC Discovery Provider. Attribuez au paramètre jwt_issuer du SPIRE Server et au paramètre jwt_issuer de l’OIDC Discovery Provider la même URL HTTPS d’émetteur que celle que vous configurerez dans OpenAI.
Dans la configuration du 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 de l’OIDC Discovery Provider doit aussi préciser une source de clés, telle que server_api, workload_api ou file, et un mécanisme pour exposer le service, par exemple 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 du domaine de confiance example.org, tandis que l’émetteur est identifié par son URL 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 le 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 avec import du JWKS. Dans ce mode, OpenAI compare toujours l’émetteur configuré pour le fournisseur d’identités de charges de travail à la revendication iss du JWT-SVID, mais vérifie les signatures à l’aide du JWKS que vous enregistrez au format JSON dans la configuration du fournisseur.
Remarque : Dans la spécification JWT-SVID de SPIFFE, le champ d’en-tête JWT
kidest facultatif. OpenAI exige toutefois que les jetons de sujet JWT comportent un champ d’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 inclue ce champ pour la fédération d’identités de charges de travail avec OpenAI.
Pour examiner un JWT-SVID depuis une charge de travail qui peut appeler la SPIFFE Workload API, demandez un jeton 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 la Workload API autorise les appels en fonction 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, précisez l’identité souhaitée dans la requête :
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érification du jeton
Avant de configurer la fédération d’identités de charges de travail, exportez le JWT-SVID dans la variable TOKEN, puis exécutez l’un de ces exemples localement pour examiner 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.
Voici un exemple de JWT-SVID SPIFFE décodé :
{
"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, comparez son contenu décodé à la configuration OpenAI. Vérifiez alg et kid dans l’en-tête, puis iss, aud, sub, iat et exp dans la charge utile. La valeur exacte de alg dépend de la configuration de la clé de signature JWT de votre SPIRE Server.
Configuration de la fédération d’identités de charges de travail
Dans OpenAI, créez un fournisseur d’identités de charges de travail pour l’émetteur des JWT-SVID SPIFFE, puis ajoutez une règle qui associe les identifiants SPIFFE de confiance à un compte de service.
Configuration du fournisseur d’identités de charges de travail
-
Créez le fournisseur d’identités de charges de travail. Dans Nom, saisissez une valeur unique, par exemple
spiffe-prod. Dans Description, saisissez un texte qui aidera les administrateurs à identifier le fournisseur, par exempleProduction SPIFFE workloads. -
Définissez l’émetteur et l’audience. Dans URL de l’émetteur OIDC, saisissez la valeur exacte de la revendication
issdu JWT-SVID, par exemplehttps://spire-oidc.example.org. Dans Audience, saisissez la valeur d’audience demandée à la SPIFFE Workload API. Dans cet exemple, il s’agit dehttps://api.openai.com/v1. -
Choisissez la source du JWKS. Laissez l’option Utiliser le JWKS importé pour vérifier les jetons désactivée si 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 OpenAI ne peut pas accéder à l’émetteur, activez l’option Utiliser le JWKS importé pour vérifier les jetons, puis renseignez le champ JWKS au format JSON avec le jeu de clés publiques correspondant aux clés de signature des JWT-SVID. Importez l’objet JWKS public complet, y compris le tableau
keysqui contient les clés. N’incluez aucune donnée de clé privée. -
Ajoutez des transformations d’attributs uniquement si votre règle d’association nécessite des attributs dérivés. Ces transformations sont facultatives si la règle utilise directement
sub. Utilisez-les uniquement si vous devez déduire une valeur d’association d’une ou de plusieurs revendications du jeton. Pour comprendre le fonctionnement des transformations, consultez le guide principal sur la fédération d’identités de charges de travail.
Configuration de l’association à un compte de service
-
Créez une règle d’association à un compte de service. Dans Nom, saisissez une valeur unique pour ce fournisseur d’identités de charges de travail, par exemple
production-openai-wif. Dans Description, indiquez quelle charge de travail peut utiliser cette règle, par exempleProduction SPIFFE workload for OpenAI API access. -
Définissez la correspondance avec l’identifiant SPIFFE. Dans Clé, saisissez
sub. Dans Valeur, saisissez l’identifiant SPIFFE de la charge de travail, par exemplespiffe://example.org/ns/production/sa/openai-wif.Pour les charges de travail privilégiées, préférez une correspondance exacte avec l’identifiant SPIFFE. N’ajoutez un caractère générique à la fin du préfixe que 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 compte de service de production dont le chemin correspond à ce motif. -
Choisissez la cible dans OpenAI. Dans Projet, sélectionnez le projet OpenAI auquel appartient le compte de service cible. Dans Compte de service, sélectionnez 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 cette règle d’association au lieu de réutiliser un compte existant. -
Limitez les autorisations d’accès à l’API si nécessaire. Sélectionnez les Autorisations appropriées, par exemple
api.model.requestetapi.vector_store.read, pour limiter davantage les droits accordés par les jetons d’accès émis via cette règle d’association. Laissez ce champ vide pour éviter d’ajouter une restriction de portée propre à la fédération d’identités de charges de travail. Le jeton donne toujours accès aux ressources avec les droits du compte de service associé.
Utilisation du jeton dans le code
Configurez votre client SDK OpenAI pour qu’il échange un JWT-SVID SPIFFE récent contre un jeton d’accès émis par OpenAI.
Les exemples de SDK ci-dessous supposent que votre intégration SPIFFE renouvelle le JWT-SVID et l’écrit dans /var/run/spiffe/openai.jwt. Accordez l’accès en lecture à ce fichier uniquement à la charge de travail. Les JWT-SVID ont une durée de vie courte : actualisez le fichier avant l’expiration du jeton. Pour éviter d’utiliser un fichier contenant un jeton périmé, vous pouvez aussi, lorsque c’est possible, utiliser une bibliothèque SPIFFE adaptée à votre langage dans le fournisseur de jetons de sujet pour récupérer le JWT-SVID directement auprès de la SPIFFE Workload API.
Définissez OPENAI_IDENTITY_PROVIDER_ID et OPENAI_SERVICE_ACCOUNT_ID dans l’environnement de la charge de travail. Le fichier contient le jeton de sujet externe. OPENAI_IDENTITY_PROVIDER_ID identifie le fournisseur d’identités de charges de travail OpenAI et OPENAI_SERVICE_ACCOUNT_ID identifie le compte de service OpenAI cible. OpenAI recherche ensuite, à partir des revendications du jeton, une règle d’association correspondante pour ce fournisseur et ce compte de service.
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 charges de travail avec OpenAI. Les X.509-SVID sont utiles pour l’authentification TLS mutuelle, mais le point de terminaison d’échange de jetons OpenAI ne les accepte pas.
- Réservez une seule audience à l’accès à OpenAI. Évitez les audiences trop larges, comme un domaine de confiance entier ou un nom d’environnement.
- Dans la mesure du possible, exigez une correspondance exacte avec les identifiants SPIFFE. N’utilisez des règles d’association avec un caractère générique que pour les identités qui doivent partager le même périmètre de confiance.
- Attribuez une courte durée de vie aux JWT-SVID pour réduire le risque de rejeu des jetons au porteur. Un jeton d’accès OpenAI expire au plus tard en même temps que le jeton de sujet externe utilisé pour l’échange.
- Planifiez soigneusement la rotation des clés de signature. Pendant la période de rotation, publiez les anciennes et les nouvelles clés publiques via la découverte OIDC, ou mettez à jour le JWKS public importé avant d’émettre des JWT-SVID avec un nouveau
kid. - Synchronisez les horloges du SPIRE Server et des charges de travail. En cas de décalage important, des JWT-SVID par ailleurs valides peuvent être rejetés parce qu’ils semblent ne pas être encore valides, être trop anciens ou avoir expiré.
- 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 jeton d’accès OpenAI.
- Délimitez les droits de vos comptes de service OpenAI en fonction des autorisations propres à chaque application et à chaque environnement. Ne partagez pas un compte de service doté de privilèges élevés entre des charges de travail SPIFFE sans rapport entre elles.
- Surveillez les échecs d’échange de jetons pour détecter les écarts liés à l’émetteur, à l’audience, à la clé de signature ou à la règle d’association.