Usa SPIFFE como proveedor de identidades de carga de trabajo al intercambiar un JWT-SVID de SPIFFE por un token de acceso de OpenAI de corta duración. Esto permite que las cargas de trabajo autenticadas por SPIRE u otro proveedor de identidades compatible con SPIFFE llamen a la API de OpenAI sin almacenar claves de API de larga duración.
Para Codex, usa esta página para obtener e inspeccionar el JWT-SVID. Luego, configura la identidad de carga de trabajo de Codex para escribir ese token en un archivo e indicarle a Codex dónde encontrarlo. La asignación de cuentas de servicio y los ejemplos del SDK de esta página se aplican a la API de OpenAI.
OpenAI admite los JWT-SVID de SPIFFE que se puedan validar como tokens de sujeto JWT con un emisor, una audiencia, una fecha de vencimiento, una marca de tiempo de emisión y una firma respaldada por un JWKS. OpenAI no admite los X.509-SVID de SPIFFE como tokens de sujeto para la federación de identidades de carga de trabajo.
La especificación JWT-SVID requiere las declaraciones sub, aud y exp. Para usar un JWT-SVID con OpenAI, el token también debe incluir las declaraciones iss y iat y un encabezado kid para que OpenAI pueda validar el token según la configuración del proveedor de identidades de carga de trabajo.
Un JWT-SVID no es un token de ID de OpenID Connect. SPIRE OIDC Discovery Provider proporciona metadatos de descubrimiento y claves JWKS para que OpenAI pueda validar el JWT-SVID; no cambia la semántica SPIFFE del token ni requiere un flujo de inicio de sesión OIDC.
Para conocer la terminología de SPIFFE y los requisitos de los tokens, consulta la especificación JWT-SVID y la especificación de Workload API de SPIFFE.
Configuración de SPIFFE
Configura tu proveedor de SPIFFE para que emita JWT-SVID para las cargas de trabajo que necesiten llamar a la API de OpenAI. Estas instrucciones usan la terminología de SPIRE, pero la misma configuración de OpenAI se aplica a cualquier proveedor compatible con SPIFFE que emita JWT-SVID con un emisor y material de firma JWKS que OpenAI pueda validar.
Tu configuración de SPIFFE debe proporcionar:
- Un ID de SPIFFE estable para la carga de trabajo, como
spiffe://example.org/ns/production/sa/openai-wif. - Una única audiencia de JWT-SVID dedicada al acceso a OpenAI, como
https://api.openai.com/v1u otro valor opaco que elijas. - Una URL del emisor de JWT que aparezca en la declaración
issdel JWT-SVID para que OpenAI pueda validarlo. - Un JWKS público para las claves de firma de JWT-SVID, ya sea mediante el descubrimiento OIDC o un JWKS cargado.
- Un mecanismo para que la carga de trabajo obtenga JWT-SVID nuevos desde SPIFFE Workload API.
La audiencia es un identificador que requiere una coincidencia exacta, no necesariamente un punto de acceso que reciba el JWT-SVID. Puedes usar https://api.openai.com/v1 u otro valor específico del servicio, siempre que coincida en la solicitud a SPIFFE Workload API y en la configuración del proveedor en OpenAI.
Cuando sea posible, expón el emisor de SPIFFE a través de tu SPIRE OIDC Discovery Provider. Configura jwt_issuer de SPIRE Server y jwt_issuer de OIDC Discovery Provider con la misma URL HTTPS del emisor que configurarás en OpenAI.
En la configuración de SPIRE Server:
server {
trust_domain = "example.org"
jwt_issuer = "https://spire-oidc.example.org"
}
En la configuración independiente de SPIRE OIDC Discovery Provider:
# Relevant issuer fields only
domains = ["spire-oidc.example.org"]
jwt_issuer = "https://spire-oidc.example.org"
La configuración de OIDC Discovery Provider también necesita una fuente de material de claves, como server_api, workload_api o file, y un mecanismo para servir el contenido, como ACME, un certificado TLS o un socket Unix. Consulta la documentación de SPIRE OIDC Discovery Provider para ver todas las opciones de configuración.
El dominio de confianza de SPIFFE y el emisor de JWT son conceptos diferentes. En este ejemplo, el sujeto del JWT-SVID es un ID de SPIFFE en el dominio de confianza example.org, mientras que el emisor es la URL HTTPS del emisor:
{
"sub": "spiffe://example.org/ns/production/sa/openai-wif",
"iss": "https://spire-oidc.example.org"
}
SPIRE OIDC Discovery Provider sirve un documento de descubrimiento OIDC y un punto de acceso JWKS que OpenAI puede usar cuando la opción Usar JWKS cargado para verificar tokens está desactivada.
Si OpenAI no puede acceder al punto de acceso de descubrimiento de tu emisor, usa el modo de JWKS cargado. En ese modo, OpenAI sigue comparando el emisor del proveedor de identidades de carga de trabajo con la declaración iss del JWT-SVID, pero verifica las firmas con el JSON del JWKS que guardes en el proveedor de identidades de carga de trabajo.
Nota: la especificación JWT-SVID de SPIFFE establece que el encabezado JWT
kides opcional, pero OpenAI requiere que los tokens de sujeto JWT incluyan un encabezadokidpara poder seleccionar la clave de firma del JWKS configurado. Si tu proveedor de SPIFFE puede omitirkid, configúralo para que lo incluya al usar la federación de identidades de carga de trabajo de OpenAI.
Para inspeccionar un JWT-SVID desde una carga de trabajo que pueda llamar a SPIFFE Workload API, solicita uno para la misma audiencia que configurarás en OpenAI. Ejecuta este comando en el mismo contexto de carga de trabajo que la aplicación, porque la autorización de Workload API depende de la identidad del proceso que realiza la llamada.
TOKEN=$(spire-agent api fetch jwt \
-socketPath /run/spire/sockets/agent.sock \
-audience "https://api.openai.com/v1" | sed -n '2p')
export TOKEN
Si tu carga de trabajo tiene más de un ID de SPIFFE, solicita la identidad específica:
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
Verifica el token
Antes de configurar la federación de identidades de carga de trabajo, exporta el JWT-SVID como TOKEN y luego ejecuta uno de estos ejemplos localmente para inspeccionar su encabezado y sus declaraciones:
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]));Cada ejemplo decodifica el JWT sin verificar la firma del token. Usa un decodificador local para los tokens de producción y evita pegarlos en herramientas de terceros.
Un JWT-SVID de SPIFFE decodificado tendrá un aspecto similar al siguiente:
{
"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
}
Usa el token decodificado para comparar el token que recibiste con la configuración de OpenAI antes de intercambiarlo. Revisa alg y kid en el encabezado, y iss, aud, sub, iat y exp en la carga útil. El valor exacto de alg depende de la configuración de la clave de firma de JWT de tu SPIRE Server.
Configuración de la federación de identidades de carga de trabajo
Crea un proveedor de identidades de carga de trabajo en OpenAI para el emisor de JWT-SVID de SPIFFE y luego agrega una asignación de cuenta de servicio que coincida con los ID de SPIFFE en los que confías.
Configura el proveedor de identidades de carga de trabajo
-
Crea el proveedor de identidades de carga de trabajo. Establece Nombre en un valor único, como
spiffe-prod. Usa Descripción, por ejemplo,Production SPIFFE workloads, para ayudar a los administradores a identificar el proveedor. -
Establece el emisor y la audiencia. Establece URL del emisor OIDC en el valor exacto de la declaración
issdel JWT-SVID, comohttps://spire-oidc.example.org. Establece Audiencia en el valor de audiencia solicitado a SPIFFE Workload API. En este ejemplo, ese valor eshttps://api.openai.com/v1. -
Elige la fuente del JWKS. Deja desactivada la opción Usar JWKS cargado para verificar tokens cuando OpenAI pueda acceder a tu SPIRE OIDC Discovery Provider. OpenAI usa el descubrimiento OIDC y el JWKS descubierto para verificar las firmas de los JWT-SVID.
Si OpenAI no puede acceder al emisor, activa Usar JWKS cargado para verificar tokens y luego establece JSON del JWKS en el conjunto de claves públicas correspondiente a las claves de firma de JWT-SVID. Carga el objeto JWKS público completo, incluido el arreglo
keysque contiene las claves. No incluyas material de claves privadas. -
Agrega transformaciones de atributos solo si necesitas atributos derivados para la asignación. Las transformaciones de atributos no son necesarias al realizar una asignación directamente desde
sub. Úsalas solo cuando necesites derivar un valor de asignación a partir de una o más declaraciones del token. Consulta la guía principal de federación de identidades de carga de trabajo para conocer el funcionamiento de las transformaciones.
Configura la asignación de cuenta de servicio
-
Crea una asignación de cuenta de servicio. Establece Nombre en un valor único dentro del proveedor de identidades de carga de trabajo, como
production-openai-wif. Usa Descripción, por ejemplo,Production SPIFFE workload for OpenAI API access, para explicar qué carga de trabajo puede usar la asignación. -
Configura la coincidencia con el ID de SPIFFE. Establece Clave en
suby Valor en el ID de SPIFFE de la carga de trabajo, comospiffe://example.org/ns/production/sa/openai-wif.Prefiere la coincidencia exacta del ID de SPIFFE para las cargas de trabajo con privilegios. Usa un comodín al final solo cuando todos los ID de SPIFFE bajo ese prefijo deban poder generar tokens de acceso de OpenAI. Por ejemplo,
spiffe://example.org/ns/production/sa/*permite cualquier ruta de cuenta de servicio de producción que coincida. -
Elige el destino en OpenAI. Establece Proyecto en el proyecto de OpenAI al que pertenece la cuenta de servicio de destino. Establece Cuenta de servicio en la cuenta de servicio de OpenAI que la carga de trabajo de SPIFFE puede usar, como
spiffe-prod-openai-wif. MarcaCreate a new service account in this projectsi quieres crear una cuenta de servicio nueva para esta asignación en lugar de reutilizar una existente. -
Restringe los permisos de la API si es necesario. Selecciona los Permisos adecuados, como
api.model.requestyapi.vector_store.read, para restringir aún más los tokens de acceso generados a partir de esta asignación. Deja los permisos en blanco para evitar agregar una restricción de alcance específica de WIF; el token seguirá autorizando el acceso como la cuenta de servicio asignada.
Uso del token en el código
Configura tu cliente del SDK de OpenAI para intercambiar un JWT-SVID de SPIFFE nuevo por un token de acceso emitido por OpenAI.
Los ejemplos del SDK que se muestran a continuación suponen que tu integración de SPIFFE renueva un JWT-SVID y lo escribe en /var/run/spiffe/openai.jwt. Asegúrate de que solo la carga de trabajo pueda leer el archivo. Como los JWT-SVID son de corta duración, actualiza el archivo antes de que venza el token. Como alternativa, cuando sea posible, usa una biblioteca de SPIFFE específica del lenguaje en el proveedor de tokens de sujeto para obtener el JWT-SVID directamente de SPIFFE Workload API y evitar archivos de tokens desactualizados.
Establece OPENAI_IDENTITY_PROVIDER_ID y OPENAI_SERVICE_ACCOUNT_ID en el entorno de la carga de trabajo. El archivo del token contiene el token de sujeto externo. OPENAI_IDENTITY_PROVIDER_ID identifica el proveedor de identidades de carga de trabajo de OpenAI y OPENAI_SERVICE_ACCOUNT_ID identifica la cuenta de servicio de destino de OpenAI. Luego, OpenAI busca una asignación coincidente para ese proveedor y esa cuenta de servicio según las declaraciones del token.
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);Prácticas recomendadas de SPIFFE
- Usa JWT-SVID para la federación de identidades de carga de trabajo de OpenAI. Los X.509-SVID son útiles para TLS mutuo, pero el punto de acceso de intercambio de tokens de OpenAI no los acepta.
- Usa una única audiencia dedicada al acceso a OpenAI. Evita audiencias amplias, como un dominio de confianza completo o el nombre de un entorno.
- Usa coincidencias exactas de ID de SPIFFE siempre que sea posible. Usa asignaciones con comodines solo para límites de confianza compartidos intencionalmente.
- Mantén cortos los períodos de validez de los JWT-SVID para reducir el riesgo de ataques de repetición con tokens de portador. Los tokens de acceso de OpenAI nunca permanecen vigentes más allá del vencimiento del token de sujeto externo usado para el intercambio.
- Rota las claves de firma con cuidado. Publica tanto las claves públicas antiguas como las nuevas mediante el descubrimiento OIDC durante el período de rotación, o actualiza el JWKS público cargado antes de emitir JWT-SVID con un nuevo
kid. - Mantén sincronizados los relojes de SPIRE Server y de las cargas de trabajo. Una diferencia significativa entre los relojes puede hacer que se rechacen JWT-SVID que de otro modo serían válidos, por considerarse aún no válidos, demasiado antiguos o vencidos.
- Protege el socket de SPIFFE Workload API. Un proceso que pueda obtener el JWT-SVID de una carga de trabajo puede intentar intercambiarlo por acceso a OpenAI.
- Alinea los límites de las cuentas de servicio de OpenAI con los límites de permisos de tus aplicaciones y entornos. No compartas una cuenta de servicio con privilegios elevados entre cargas de trabajo de SPIFFE no relacionadas.
- Monitorea los fallos de intercambio de tokens por discrepancias en el emisor, la audiencia, la clave de firma y la asignación.