A Kubernetes exec auth plugin that gets a SPIFFE JWT-SVID for authentication, either from the SPIFFE Workload API (default) or by minting one from the SPIRE Server admin API.
go build -o k8s-spiffe-workload-jwt-exec-auth ./cmd
The plugin is configured entirely through environment variables, set via the env: list of the
kubeconfig exec block:
| Variable | Default | Description |
|---|---|---|
SPIFFE_JWT_SOURCE |
workload-api |
Where the JWT-SVID comes from: workload-api or server-admin-api. See below. |
SPIFFE_ENDPOINT_SOCKET |
unix:///tmp/spire-agent/public/api.sock |
Address of the SPIFFE Workload API socket. workload-api source only. |
SPIFFE_JWT_AUDIENCE |
k8s |
Audience requested for the JWT-SVID. Must match an entry in the API server's AuthenticationConfiguration. |
SPIFFE_JWT_HINT |
(unset) | Selects which JWT-SVID to use by hint, when the Workload API returns more than one. workload-api source only. See below. |
EXEC_CREDENTIAL_VERSION |
v1 |
The client.authentication.k8s.io version emitted. Use v1beta1 for older clients. Must match the apiVersion in the exec block. |
SPIRE_SERVER_SOCKET |
unix:///tmp/spire-server/private/api.sock |
Address of the SPIRE Server admin API socket. server-admin-api source only. |
SPIFFE_ID |
(unset) | The SPIFFE ID to mint a JWT-SVID for. Required for the server-admin-api source. |
There is also one flag, passed via args: rather than env::
| Flag | Default | Description |
|---|---|---|
-timeout |
0 |
Max time to wait for the JWT-SVID, e.g. -timeout=5s. 0 waits forever. |
By default the plugin fetches the JWT-SVID of the calling workload from the SPIFFE Workload API. Set
SPIFFE_JWT_SOURCE to server-admin-api to instead mint a JWT-SVID for SPIFFE_ID directly from the
SPIRE Server admin API socket (SPIRE_SERVER_SOCKET).
The server-admin-api source is useful where the Workload API is not reachable but the server admin
socket is — for example an exec consumer co-located with spire-server — and where the credential
should not depend on agent attestation. That consumer must have access to the server admin socket.
Hints are operator-set strings on SPIRE registration entries, used "to provide guidance on how this identity should be used by a workload when more than one SVID is returned". If the Workload API returns several JWT-SVIDs — for example a SPIRE HA broker fronting multiple entry-scoped SVIDs — then which one comes first is arbitrary, and the plugin may authenticate to the cluster as an identity you did not intend.
Set SPIFFE_JWT_HINT to pin a specific one:
- Unset or empty: use the first JWT-SVID returned. This is the original behavior.
- Set and matched: use the JWT-SVID with that hint.
- Set and unmatched: exit non-zero with an error on stderr listing the hints that were available, rather than silently authenticating as a different identity.
Matching is exact — no case folding or whitespace trimming. SPIRE keeps only the first SVID for each non-empty hint, so hints are effectively unique.
We recommend using the Structured Authentication mechanism, as documented here: https://kubernetes.io/blog/2024/04/25/structured-authentication-moves-to-beta/
As an example:
apiVersion: apiserver.config.k8s.io/v1beta1
kind: AuthenticationConfiguration
jwt:
- issuer:
# Update to point at your spiffe-oidc-discovery-provider
url: https://oidc-discovery.example.org
audiences:
- k8s
claimMappings:
username:
claim: "sub"
prefix: ""Start with a copy of your Kubernetes clusters /etc/kubernetes/admin.conf file.
Remove the "user" block from the "users" section and replace it with:
user:
exec:
apiVersion: "client.authentication.k8s.io/v1"
command: "k8s-spiffe-workload-jwt-exec-auth"
interactiveMode: Never
# To customize, uncomment and change the settings below
#env:
# - name: SPIFFE_ENDPOINT_SOCKET
# value: "unix:///var/run/spire/agent/sockets/main/public/api.sock"
# - name: SPIFFE_JWT_AUDIENCE
# value: "k8s-one"
# - name: SPIFFE_JWT_HINT
# value: "k8s-one"
#args:
# - "-timeout=5s"Modify /etc/kubernetes/kubelet.conf, and remove client-certificate and client-key settings. Then add the following exec block to user:
user:
exec:
apiVersion: "client.authentication.k8s.io/v1"
command: "k8s-spiffe-workload-jwt-exec-auth"
interactiveMode: Never
# To customize, uncomment and change the settings below
#env:
# - name: SPIFFE_ENDPOINT_SOCKET
# value: "unix:///var/run/spire/agent/sockets/main/public/api.sock"
# - name: SPIFFE_JWT_AUDIENCE
# value: "k8s-one"
# - name: SPIFFE_JWT_HINT
# value: "k8s-one"
#args:
# - "-timeout=5s"