Skip to main content

Kubernetes Workload Identity

Every pod can be given a projected service-account token: a short-lived OIDC token, signed by the cluster, that names the service account it was issued to. KnoxCall accepts it via RFC 8693 token exchange, so a pod authenticates with no stored KnoxCall credential at all. The part that makes Kubernetes different from GitHub Actions or GCP is where your cluster publishes its signing keys.

Which setup do you have?

Most self-managed clusters land in the second row. If you are not sure, run kubectl get --raw /.well-known/openid-configuration and look at the jwks_uri it returns — then ask whether that URL is reachable from the public internet.
https://kubernetes.default.svc is the default issuer string for every cluster, so it is not unique to you. KnoxCall stores your keys against your tenant and your issuer together, and an assertion is only ever verified against your cluster’s keys — a different customer registering the same issuer string cannot mint into your tenant, and you cannot mint into theirs.

1. Get your cluster’s issuer and keys

The second command prints something of the form {"keys":[{...}]}. That whole document is what you paste for Inline. It contains public keys only — there is no private key material in it.

2. Configure the issuer’s JWKS source

For discovery clusters, skip this step.
Changing an issuer’s JWKS source requires a recent step-up verification (passkey, TOTP or emailed code) within the last 5 minutes. Pasting keys is telling KnoxCall which signer to believe for your tenant, so it carries the same bar as creating a binding. A request carrying only a session JWT answers 403 {"requires_step_up": true}.
The request is rejected if the document cannot produce a usable key — KnoxCall parses it before saving rather than letting you discover the problem on your first exchange. For inline this check makes no network call at all.
Inline keys do not refresh. When your cluster rotates its service-account signing keys, exchanges stop verifying until you paste the new document. KnoxCall names that cause specifically rather than reporting a generic signature failure, and the binding’s status in the Dashboard shows it — but nothing rotates them for you. If your cluster rotates on a schedule, put this on the same schedule.

3. Create the workload binding

Bind the service accounts you want to trust. A Kubernetes sub looks like:
You can cover a whole namespace with a trailing *:
On an inline issuer a broad prefix is accepted, because the issuer is already the boundary — only your cluster’s signing key produces a token that verifies at all, so system:serviceaccount:* grants nothing your cluster could not grant itself. On a shared public issuer the same prefix is refused, because there it would match other people’s workloads. A bare "*" is always refused: it names no workload.

4. Project the token into your pod

Set audience: explicitly. A projected token with the cluster’s default audience will not match your binding, and the exchange refuses it — correctly, but the message reads like a credential problem rather than a manifest one.

5. Exchange it

The token file is re-read before every exchange, never once at startup: KnoxCall assertions are single-use, so replaying the same bytes is refused. The SDKs’ WorkloadCredentialProvider does this for you, including refreshing before expiry.
Doing it by hand is one request:

Troubleshooting