Skip to main content

Kubernetes Service Account Token

The Kubernetes Service Account Token method authenticates agents running in a Kubernetes cluster by verifying the agent's service account token. The agent sends its token to the Trust Domain Server; the server verifies it against the cluster's OIDC issuer.

This is the simplest agent attestation method for Kubernetes-hosted agents.

Attributes available for SVID issuance

The k8s_token agent attestor does not emit any attributes. Agent identity is established by verifying the service account token, but no token claims are exposed for use in path templates or other SVID customization.

To reference Kubernetes attributes of the workload requesting an SVID (pod name, namespace, service account, labels, annotations, etc.), see the Kubernetes workload attestor. Agent-side attributes such as cluster or node identity can be added by combining k8s_token with another attestor — for example, aws_iid on EKS.

How to Deploy

Step 1 — Update cluster configuration

Create an AgentAttestation policy for the cluster, specifying the OIDC issuer URL for the Kubernetes cluster where agents will run. By default the Trust Domain Server uses issuerURL for OIDC discovery to fetch signing keys, so it must be reachable from the server. If the cluster's issuer is not reachable from the server (for example, an internal hostname like kubernetes.default.svc), supply the signing keys directly via jwksURI or inline jwks instead.

Basic example using OIDC discovery:

section: AgentAttestation
schema: v1
spec:
policies:
- name: k8s_policy
requiredAttestors:
- type: k8s_token
config:
issuerURL: https://oidc.eks.us-east-1.amazonaws.com/id/ABCDEF123456

Example using a JWKS URI:

Use this when the cluster's iss claim is not a resolvable URL but the JWKS is reachable at a separate, server-reachable endpoint. issuerURL is matched literally against the JWT's iss claim; no OIDC discovery is performed against it.

section: AgentAttestation
schema: v1
spec:
policies:
- name: k8s_policy
requiredAttestors:
- type: k8s_token
config:
issuerURL: https://kubernetes.default.svc.cluster.local
jwksURI: https://jwks.internal.example.com/cluster-a/jwks.json

Example using an inline JWKS:

Use this when neither the issuer nor a JWKS endpoint is reachable from the Trust Domain Server. The JWKS must contain only public keys.

section: AgentAttestation
schema: v1
spec:
policies:
- name: k8s_policy
requiredAttestors:
- type: k8s_token
config:
issuerURL: https://kubernetes.default.svc.cluster.local
jwks: '{"keys":[{"kty":"RSA","kid":"abc123","n":"...","e":"AQAB"}]}'

Apply it:

spirlctl config set cluster --id <cluster-id> attestation-policy.yaml

Configuration Reference

FieldRequiredDescription
issuerURLYesExpected iss claim. When no manual JWKS source is supplied, also used as the OIDC discovery base URL to fetch signing keys; the server fetches <issuerURL>/.well-known/openid-configuration.
jwksURINoDirect JWKS endpoint URL. When set, OIDC discovery is skipped and issuerURL is only matched literally against the iss claim. Must use HTTPS. Mutually exclusive with jwks.
jwksNoInline JWKS document (JSON string containing only public keys). When set, no network fetch is performed and issuerURL is only matched literally against the iss claim. Mutually exclusive with jwksURI.
serviceAccountNameNoExpected service account name in the sub claim (system:serviceaccount:<namespace>:<name>). Defaults to spirl-agent.
serviceAccountNamespaceNoExpected service account namespace in the sub claim. Defaults to spirl-system.

Step 2 — Configure the Agent

No additional agent configuration is needed. When k8s_token is listed as an attestation method, the agent automatically requests a service account token from Kubernetes and sends it to the server at login.

In Helm values:

agent:
auth:
clusterId: c-xxxxxx
attestors:
- type: k8s_token

Security Considerations

  • When using OIDC discovery or jwksURI, the endpoint must be accessible from the Trust Domain Server's network. Ensure any firewall or network policy allows outbound HTTPS from the Trust Domain Server to the configured URL.
  • HTTPS enforcement: jwksURI must use HTTPS. URLs that resolve to loopback, private, or link-local IP addresses are rejected to prevent SSRF.
  • No private key material: Inline jwks is validated at configuration time to ensure it contains only public keys.
  • Service account tokens expire. Kubernetes automatically rotates them; agents re-authenticate as needed.
  • Service account tokens alone do not constrain which node or namespace an agent runs in. For finer-grained control — for example, limiting agents to a specific namespace or service account — add a second attestation method (such as aws_iid) that enforces additional constraints.

Troubleshooting

failed to fetch signing key — The Trust Domain Server cannot reach the configured key source. Verify network connectivity from the server to issuerURL (when using OIDC discovery) or jwksURI.

key "<kid>" not found in inline JWKS — The token's kid header does not match any key in the configured inline jwks. Update the cluster configuration to include the new signing key.

JWT verification failed — The token the agent presented was not verifiable. Check the error detail: common causes are an expired token, a mismatched issuer URL, or a token issued by a different cluster than the one configured.