Use o SPIFFE como provedor de identidade de cargas de trabalho para trocar um JWT-SVID do SPIFFE por um token de acesso de curta duração da OpenAI. Assim, cargas de trabalho autenticadas pelo SPIRE ou por outro provedor de identidade compatível com SPIFFE podem chamar a API da OpenAI sem armazenar chaves de API de longa duração.
Se você usa o Idira Secure Workload Access, siga o guia de configuração do Idira para configurar o agente e a entrega de tokens.
A OpenAI aceita JWT-SVIDs do SPIFFE que possam ser validados como tokens de sujeito JWT, com emissor, público-alvo, data e hora de expiração, data e hora de emissão e assinatura verificável por meio de um JWKS. A OpenAI não aceita X.509-SVIDs do SPIFFE como tokens de sujeito na federação de identidades de cargas de trabalho.
A especificação JWT-SVID exige as declarações sub, aud e exp. Para usar um JWT-SVID com a OpenAI, o token também deve incluir as declarações iss e iat e o campo kid no cabeçalho. Assim, a OpenAI pode validar o token com base na configuração do provedor de identidade de cargas de trabalho.
Um JWT-SVID não é um token de ID do OpenID Connect. O SPIRE OIDC Discovery Provider fornece os metadados de descoberta e as chaves do JWKS para que a OpenAI possa validar o JWT-SVID. Isso não altera a semântica do token definida pelo SPIFFE nem exige um fluxo de login OIDC.
Para consultar a terminologia do SPIFFE e os requisitos dos tokens, veja a especificação JWT-SVID e a especificação da Workload API.
Como configurar o SPIFFE
Configure seu provedor SPIFFE para emitir JWT-SVIDs para as cargas de trabalho que precisam chamar a API da OpenAI. Estas instruções usam a terminologia do SPIRE, mas a configuração na OpenAI é a mesma para qualquer provedor compatível com SPIFFE que emita JWT-SVIDs e forneça um emissor e chaves de assinatura em um JWKS que a OpenAI possa usar na validação.
Sua configuração do SPIFFE deve fornecer os seguintes elementos:
- Um ID SPIFFE estável para a carga de trabalho, como
spiffe://example.org/ns/production/sa/openai-wif. - Um único público-alvo de JWT-SVID exclusivo para acesso à OpenAI, como
https://api.openai.com/v1ou outro valor opaco de sua escolha. - Uma URL de emissor JWT que conste na declaração
issdo JWT-SVID para que a OpenAI possa validá-lo. - Um JWKS público com as chaves de assinatura dos JWT-SVIDs, disponibilizado por descoberta OIDC ou por upload.
- Um mecanismo que permita à própria carga de trabalho obter JWT-SVIDs atualizados da SPIFFE Workload API.
O público-alvo é um identificador que exige correspondência exata. Ele não precisa ser um endpoint que receba o JWT-SVID. Você pode usar https://api.openai.com/v1 ou outro valor específico do serviço, desde que o valor na solicitação à SPIFFE Workload API seja idêntico ao da configuração do provedor na OpenAI.
Sempre que possível, disponibilize o emissor SPIFFE por meio do SPIRE OIDC Discovery Provider. Defina jwt_issuer no SPIRE Server e jwt_issuer no OIDC Discovery Provider com a mesma URL HTTPS de emissor que você vai configurar na OpenAI.
Na configuração do SPIRE Server:
server {
trust_domain = "example.org"
jwt_issuer = "https://spire-oidc.example.org"
}
Na configuração separada do SPIRE OIDC Discovery Provider:
# Relevant issuer fields only
domains = ["spire-oidc.example.org"]
jwt_issuer = "https://spire-oidc.example.org"
A configuração do OIDC Discovery Provider também exige uma fonte de material criptográfico, como server_api, workload_api ou file, e um mecanismo para disponibilizar o serviço, como ACME, um certificado TLS ou um socket Unix. Consulte a documentação do SPIRE OIDC Discovery Provider para ver todas as opções de configuração.
O domínio de confiança do SPIFFE e o emissor JWT são conceitos distintos. Neste exemplo, o sujeito do JWT-SVID é um ID SPIFFE no domínio de confiança example.org, enquanto o emissor é identificado pela URL HTTPS:
{
"sub": "spiffe://example.org/ns/production/sa/openai-wif",
"iss": "https://spire-oidc.example.org"
}
O SPIRE OIDC Discovery Provider disponibiliza um documento de descoberta OIDC e um endpoint de JWKS que a OpenAI pode usar quando a opção Usar o JWKS enviado para verificar tokens está desativada.
Se a OpenAI não conseguir acessar o endpoint de descoberta do emissor, use o modo de upload de JWKS. Nesse modo, a OpenAI continua comparando o emissor configurado no provedor de identidade de cargas de trabalho com a declaração iss do JWT-SVID, mas verifica as assinaturas com o JWKS em formato JSON que você salva no provedor.
Observação: A especificação JWT-SVID do SPIFFE torna opcional o campo
kidno cabeçalho JWT, mas a OpenAI exige que os tokens de sujeito JWT incluamkidno cabeçalho para que ela possa selecionar a chave de assinatura no JWKS configurado. Se o seu provedor SPIFFE puder omitirkid, configure-o para incluir esse campo na federação de identidades de cargas de trabalho com a OpenAI.
Para inspecionar um JWT-SVID a partir de uma carga de trabalho que possa chamar a SPIFFE Workload API, solicite um token para o mesmo público-alvo que você vai configurar na OpenAI. Execute o comando no mesmo contexto de carga de trabalho do aplicativo, pois a autorização da Workload API depende da identidade do processo que faz a chamada.
TOKEN=$(spire-agent api fetch jwt \
-socketPath /run/spire/sockets/agent.sock \
-audience "https://api.openai.com/v1" | sed -n '2p')
export TOKEN
Se sua carga de trabalho tiver mais de um ID SPIFFE, especifique a identidade na solicitação:
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
Verifique o token
Antes de configurar a federação de identidades de cargas de trabalho, exporte o JWT-SVID na variável TOKEN e execute um dos exemplos a seguir localmente para inspecionar o cabeçalho e as declarações do token:
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 exemplo decodifica o JWT sem verificar a assinatura do token. Use um decodificador local para tokens de produção e evite colá-los em ferramentas de terceiros.
O cabeçalho e as declarações de um JWT-SVID do SPIFFE, depois de decodificados, terão formato semelhante ao deste exemplo:
{
"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
}
Antes de trocar o token recebido, compare os valores do token decodificado com a configuração na OpenAI. Confira alg e kid no cabeçalho e iss, aud, sub, iat e exp no payload. O valor exato de alg depende da configuração da chave de assinatura de JWTs no SPIRE Server.
Como configurar a federação de identidades de cargas de trabalho
Crie um provedor de identidade de cargas de trabalho na OpenAI para o emissor dos JWT-SVIDs do SPIFFE. Em seguida, adicione um mapeamento de conta de serviço que corresponda aos IDs SPIFFE em que você confia.
Configure o provedor de identidade de cargas de trabalho
-
Crie o provedor de identidade de cargas de trabalho. Em Nome, insira um valor exclusivo, como
spiffe-prod. Em Descrição, insira um texto comoProduction SPIFFE workloadspara ajudar os administradores a identificar o provedor. -
Defina o emissor e o público-alvo. Em URL do emissor OIDC, insira o valor exato da declaração
issdo JWT-SVID, comohttps://spire-oidc.example.org. Em Público-alvo, insira o valor de público-alvo usado na solicitação à SPIFFE Workload API. Neste exemplo, o valor éhttps://api.openai.com/v1. -
Escolha a origem do JWKS. Deixe a opção Usar o JWKS enviado para verificar tokens desativada se a OpenAI conseguir acessar seu SPIRE OIDC Discovery Provider. A OpenAI usa a descoberta OIDC para localizar o JWKS e verificar as assinaturas dos JWT-SVIDs com as chaves desse conjunto.
Se a OpenAI não conseguir acessar o emissor, ative Usar o JWKS enviado para verificar tokens e, em JWKS em JSON, insira o conjunto de chaves públicas correspondente às chaves de assinatura dos JWT-SVIDs. Envie o objeto JWKS público completo, incluindo o array
keysque contém as chaves. Não inclua material de chave privada. -
Adicione transformações de atributos somente se precisar de atributos derivados para o mapeamento. O mapeamento direto a partir de
subdispensa transformações de atributos. Use-as somente quando precisar derivar um valor de mapeamento de uma ou mais declarações do token. Consulte o guia principal de federação de identidades de cargas de trabalho para entender como funcionam as transformações.
Configure o mapeamento da conta de serviço
-
Crie um mapeamento de conta de serviço. Em Nome, insira um valor exclusivo no provedor de identidade de cargas de trabalho, como
production-openai-wif. Em Descrição, insira um texto comoProduction SPIFFE workload for OpenAI API accesspara indicar qual carga de trabalho pode usar o mapeamento. -
Configure a correspondência do ID SPIFFE. Em Chave, insira
sube, em Valor, insira o ID SPIFFE da carga de trabalho, comospiffe://example.org/ns/production/sa/openai-wif.Para cargas de trabalho privilegiadas, prefira a correspondência exata do ID SPIFFE. Use um curinga no final somente se todos os IDs SPIFFE com esse prefixo deverem ter permissão para gerar tokens de acesso da OpenAI. Por exemplo,
spiffe://example.org/ns/production/sa/*permite qualquer caminho de conta de serviço de produção que corresponda a esse padrão. -
Escolha o destino na OpenAI. Em Projeto, selecione o projeto da OpenAI ao qual pertence a conta de serviço de destino. Em Conta de serviço, selecione a conta de serviço da OpenAI que a carga de trabalho SPIFFE pode usar, como
spiffe-prod-openai-wif. MarqueCreate a new service account in this projectse quiser criar uma conta de serviço para esse mapeamento em vez de reutilizar uma conta existente. -
Restrinja as permissões da API, se necessário. Em Permissões, selecione as permissões adequadas, como
api.model.requesteapi.vector_store.read, para restringir ainda mais o acesso concedido pelos tokens gerados com esse mapeamento. Deixe o campo de permissões em branco para evitar uma restrição de escopo específica da federação. O token continua autorizando o acesso com a identidade da conta de serviço mapeada.
Como usar o token no código
Configure o cliente do SDK da OpenAI para trocar um JWT-SVID atualizado do SPIFFE por um token de acesso emitido pela OpenAI.
Os exemplos de uso do SDK a seguir pressupõem que sua integração com o SPIFFE atualize o JWT-SVID e o grave em /var/run/spiffe/openai.jwt. Restrinja a permissão de leitura do arquivo à carga de trabalho. Como os JWT-SVIDs têm validade curta, atualize o arquivo antes que o token expire. Como alternativa, quando possível, use uma biblioteca SPIFFE para a sua linguagem no provedor de tokens de sujeito. Assim, ele pode obter o JWT-SVID diretamente da SPIFFE Workload API e evitar o uso de arquivos de token desatualizados.
Defina OPENAI_IDENTITY_PROVIDER_ID e OPENAI_SERVICE_ACCOUNT_ID no ambiente da carga de trabalho. O arquivo de token contém o token de sujeito externo. OPENAI_IDENTITY_PROVIDER_ID identifica o provedor de identidade de cargas de trabalho na OpenAI, e OPENAI_SERVICE_ACCOUNT_ID identifica a conta de serviço de destino na OpenAI. Com base nas declarações do token, a OpenAI localiza um mapeamento correspondente a esse provedor e a essa conta de serviço.
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);Boas práticas para o SPIFFE
- Use JWT-SVIDs para a federação de identidades de cargas de trabalho com a OpenAI. Os X.509-SVIDs são úteis para TLS mútuo, mas o endpoint de troca de tokens da OpenAI não os aceita.
- Use um único público-alvo exclusivo para acesso à OpenAI. Evite públicos-alvo abrangentes, como um domínio de confiança inteiro ou o nome de um ambiente.
- Sempre que possível, exija correspondência exata dos IDs SPIFFE. Use mapeamentos com curingas somente quando as cargas de trabalho compartilharem intencionalmente o mesmo limite de confiança.
- Use prazos de validade curtos para os JWT-SVIDs a fim de reduzir o risco de ataques de repetição com tokens de portador. Os tokens de acesso da OpenAI nunca permanecem válidos além da expiração do token de sujeito externo usado na troca.
- Faça a rotação das chaves de assinatura com cuidado. Durante o período de rotação, publique as chaves públicas antigas e novas por meio da descoberta OIDC ou atualize o JWKS público enviado antes de emitir JWT-SVIDs com um novo
kid. - Mantenha sincronizados os relógios do SPIRE Server e das cargas de trabalho. Uma diferença significativa entre os relógios pode fazer com que JWT-SVIDs válidos sejam rejeitados por parecerem ter sido emitidos há muito tempo, já ter expirado ou ainda não ter entrado em vigor.
- Proteja o socket da SPIFFE Workload API. Um processo capaz de obter o JWT-SVID de uma carga de trabalho pode tentar trocá-lo por um token de acesso à OpenAI.
- Alinhe os limites de acesso das contas de serviço da OpenAI aos limites de permissão dos seus aplicativos e ambientes. Não compartilhe uma conta de serviço com privilégios elevados entre cargas de trabalho SPIFFE sem relação entre si.
- Monitore as falhas na troca de tokens para identificar divergências de emissor, público-alvo, chave de assinatura ou mapeamento.