Use Kubernetes as a Workload Identity Provider by exchanging a projected Kubernetes service account token for a short-lived OpenAI access token.
Setting up Kubernetes
This guide assumes Kubernetes service account token projection is enabled, which is available by default in modern Kubernetes releases. OpenAI workload identity federation requires OIDC-compatible projected service account tokens. Legacy Kubernetes service account tokens stored in Secrets are not supported.
Use a Kubernetes ServiceAccount for the workload that needs to call the OpenAI API. If you do not already have one, create it:
kubectl create serviceaccount openai-wif --namespace defaultGet the OIDC issuer for your Kubernetes cluster:
kubectl get --raw /.well-known/openid-configuration | jq -r .issuerEven if you upload the JWKS and OpenAI does not perform JWKS discovery against the OIDC issuer, this issuer must match the issuer configured in the Workload Identity Provider.
Get the cluster JWKS and save the returned key set. You will need it when configuring the Workload Identity Provider:
kubectl get --raw /openid/v1/jwksConfigure the projected service account token with the audience OpenAI expects and an expiration suitable for your workload. OpenAI validates the token’s issuer, signature, audience, and expiration. In this example, the token file is mounted at /var/run/secrets/tokens/token, uses the audience https://api.openai.com/v1, and expires after 3600 seconds. You may use a different audience if the projected token audience and OpenAI Workload Identity Provider audience match:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: v1
kind: Pod
metadata:
name: openai-wif-app
namespace: default
spec:
serviceAccountName: openai-wif
containers:
- name: app
image: my-image
volumeMounts:
- name: ksa-token
mountPath: /var/run/secrets/tokens
readOnly: true
volumes:
- name: ksa-token
projected:
sources:
- serviceAccountToken:
path: token
audience: "https://api.openai.com/v1"
expirationSeconds: 3600Verify the token
Before configuring workload identity federation, decode a sample projected service account token locally and inspect its claims. From a running pod with the projected token mounted:
1
2
3
4
5
6
7
8
9
10
11
TOKEN=$(kubectl exec -n default openai-wif-app -- cat /var/run/secrets/tokens/token)
TOKEN="$TOKEN" python3 - <<'PY'
import base64
import json
import os
payload = os.environ["TOKEN"].split(".")[1]
payload += "=" * (-len(payload) % 4)
print(json.dumps(json.loads(base64.urlsafe_b64decode(payload)), indent=2))
PYThis command decodes the JWT payload without verifying the token signature. Use a local decoder for production tokens, and avoid pasting production tokens into third-party tools.
A decoded Kubernetes projected service account token will look similar to:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"iss": "https://kubernetes.example.com",
"aud": ["https://api.openai.com/v1"],
"sub": "system:serviceaccount:default:openai-wif",
"iat": 1716235422,
"exp": 1716239022,
"kubernetes.io": {
"namespace": "default",
"serviceaccount": {
"name": "openai-wif",
"uid": "11111111-2222-3333-4444-555555555555"
}
}
}Use the decoded payload to compare the token you received with the issuer, audience, and mapping values configured in OpenAI. Most configuration issues are visible in the iss, aud, and sub claims before you exchange the token.
Setting up workload identity federation
Create a Workload Identity Provider in OpenAI for the Kubernetes issuer, then add a service account mapping that matches attributes from the projected token.
Configure the Workload Identity Provider first, then create the service account mapping.
Set up the Workload Identity Provider
-
Create the Workload Identity Provider. Set Name to a unique value, such as
kubernetes-prod. Use Description, such asProduction Kubernetes cluster, to help admins identify the cluster. -
Set the issuer and audience. Set OIDC Issuer URL to the issuer returned by
kubectl get --raw /.well-known/openid-configuration | jq -r .issuer. This value must match theissclaim in the projected token. Set Audience to the same opaque audience string configured on the projected service account token volume. In this example, that value ishttps://api.openai.com/v1. -
Upload the Kubernetes JWKS. Enable Use uploaded JWKS for token verification, then set JWKS JSON to the output from
kubectl get --raw /openid/v1/jwks. OpenAI uses this public key set to verify projected Kubernetes service account tokens. Upload the full key set including the surroundingkeys.Note: For self-hosted Kubernetes clusters, OpenAI supports only local JWKS mode. Upload the JWKS returned by your cluster; OpenAI does not perform OIDC discovery against the configured issuer. OpenAI still compares the configured issuer with the
issfield in the token.If your cluster rotates service account signing keys, update the uploaded JWKS in the Workload Identity Provider configuration. Tokens signed by keys that are not present in the configured JWKS are rejected. If the JWKS contains multiple active public keys, include the full
keysarray. -
Add attribute transformations only if you need derived mapping attributes. Raw token claims such as
sub,aud, andisscan be used directly in mapping assertions. If you plan to match on transformed attributes rather than raw token claims, the dashboard applies theopenai.prefix automatically; for example, enterworkload_subjectwith expressionassertion.subto createopenai.workload_subject. Raw token claims that already start withopenai.are ignored foropenai.mapping keys unless a matching transformation is configured.
Set up the service account mapping
-
Create a service account mapping. Set Name to a unique value within the Workload Identity Provider, such as
openai-mapping-kubernetes. Use Description, such asWorkload Identity Provider Mapping for Kubernetes Workloads, to explain which workload can use the mapping. -
Match the Kubernetes service account subject. Set Key to
suband Value tosystem:serviceaccount:default:openai-wif. For Kubernetes service accounts, the subject format issystem:serviceaccount:<namespace>:<service-account-name>. -
Choose the OpenAI target. Set Project to the OpenAI project that owns the target service account. Set Service account to the OpenAI service account the Kubernetes workload can use, such as
kubernetes-prod-openai-wif. CheckCreate a new service account in this projectif you wish to create a new service account for this mapping rather than reuse an existing one. -
Narrow API permissions if needed. Select appropriate Permissions such as
api.model.requestandapi.vector_store.readto further narrow access tokens minted from this mapping. Leave permissions blank to avoid adding a WIF-specific scope restriction; the token still authorizes as the mapped service account.
Using the token in code
Configure your OpenAI SDK client to read the projected Kubernetes token and exchange it for an OpenAI-issued access token.
Use the mounted token path, such as /var/run/secrets/tokens/token, as the subject token source for the SDK workload identity federation provider. The SDK exchanges that Kubernetes token for an OpenAI-issued access token and uses the OpenAI token to authenticate API requests.
The following examples initialize an OpenAI client with a custom subject token provider. The provider reads the projected Kubernetes service account token from the mounted file path and uses it as the subject token for workload identity federation.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import { readFile } from "node:fs/promises";
import OpenAI from "openai";
import type { SubjectTokenProvider } from "openai/auth";
const tokenPath = "/var/run/secrets/tokens/token";
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 mountedServiceAccountTokenProvider(path: string): SubjectTokenProvider {
return {
tokenType: "jwt",
getToken: async () => {
const token = (await readFile(path, "utf8")).trim();
if (!token) {
throw new Error("The mounted service account token file is empty.");
}
return token;
},
};
}
const client = new OpenAI({
workloadIdentity: {
identityProviderId,
serviceAccountId,
provider: mountedServiceAccountTokenProvider(tokenPath),
},
});
const response = await client.responses.create({
model: "gpt-4.1-mini",
input: "Say hello from Kubernetes workload identity federation.",
});
console.log(response.output_text);Kubernetes best practices
- Use a stable OIDC issuer. The issuer URL must match the projected service account token
issclaim and should remain stable across cluster upgrades and maintenance operations. - Protect signing keys carefully. Anyone with access to the cluster’s service account signing keys can mint tokens that may be accepted by OpenAI.
- Use dedicated service accounts for OpenAI integrations. Avoid reusing service accounts that are also used for unrelated infrastructure or application access.
- Keep the uploaded JWKS current. OpenAI uses the configured JWKS to validate workload identity tokens in local JWKS mode, so update the Workload Identity Provider before rotating to new signing keys.
- Minimize custom claim complexity. Prefer matching on standard claims such as
subandaud, or transformed attributes derived directly from those claims. - Treat namespace ownership as part of your security model. If namespace administrators can create service accounts, ensure mappings are scoped appropriately to prevent unintended privilege escalation.
- Monitor issuer and signing key changes. Rotating signing keys without updating the Workload Identity Provider JWKS can cause token exchange failures.