Nais Workload Identity¶
Workloads in Nais Kubernetes clusters are automatically mounted with a Projected Service Account Token (PSAT) that can be used to authenticate with Nais components.
See the implementation in Naiserator for details.
Usage for Nais components¶
Nais components that require authentication must validate the incoming PSAT as a JWT.
OIDC Metadata Document¶
The token is a standard JWT that can be validated using the OIDC Metadata Document for a given cluster.
The metadata document is available in Fasit as an environment variable for each environment under the key apiserver_oidc_well_known_url.
Example:
{
"issuer": "https://container.googleapis.com/v1/projects/nais-dev-2e7b/locations/europe-north1/clusters/nais-dev",
"jwks_uri": "https://container.googleapis.com/v1/projects/nais-dev-2e7b/locations/europe-north1/clusters/nais-dev/jwks",
"response_types_supported": ["id_token"],
"subject_types_supported": ["public"],
"id_token_signing_alg_values_supported": ["RS256"],
"claims_supported": ["iss", "sub", "kubernetes.io"],
"grant_types": ["urn:kubernetes:grant_type:programmatic_authorization"]
}
JWT Claims¶
The JWT always includes nais in its aud (audience) claim, which prevents the token from being reused against non-Nais audiences. Per RFC 7519, validators must accept aud either as a string or as an array of strings.
It otherwise contains standard claims such as iss (issuer) and sub (subject), exp (expiration time), iat (issued at), as well as a custom claim kubernetes.io that contains additional metadata such as the Kubernetes Service Account name and namespace.
Example:
{
"aud": ["nais"],
"exp": 1729605240,
"iat": 1729601640,
"iss": "https://container.googleapis.com/v1/projects/nais-dev-2e7b/locations/europe-north1/clusters/nais-dev",
"jti": "aed34954-b33a-4142-b1ec-389d6bbb4936",
"kubernetes.io": {
"namespace": "my-namespace",
"node": {
"name": "my-node",
"uid": "646e7c5e-32d6-4d42-9dbd-e504e6cbe6b1"
},
"pod": {
"name": "my-pod",
"uid": "5e0bd49b-f040-43b0-99b7-22765a53f7f3"
},
"serviceaccount": {
"name": "my-serviceaccount",
"uid": "14ee3fa4-a7e2-420f-9f9a-dbc4507c3798"
}
},
"nbf": 1729601640,
"sub": "system:serviceaccount:my-namespace:my-serviceaccount"
}
Note that the kubernetes.io.pod and kubernetes.io.node claims may be omitted if the token was minted from the API-server instead of the kubelet, for example when running kubectl create token.
JWT Validation¶
Standard claims should be validated in accordance with RFC 7519.
Other claims such as sub or kubernetes.io should be validated according to the needs of the component. For example, a component may require that the sub claim starts with system:serviceaccount:, or that the kubernetes.io claim contains a specific service account name or namespace.
JWKS caching¶
Cache the JWKS document (e.g. for 5–15 minutes) rather than fetching it on every request. Refresh on signature verification failure to handle key rotation.
Usage for consumer workloads¶
The PSAT is mounted in the workload's filesystem at the path given by the NAIS_SERVICE_ACCOUNT_TOKEN_PATH environment variable.
The token is periodically rotated; re-read the file before use rather than caching its contents.
The PSAT should be considered an opaque token for the consumer. The workload should not attempt to parse or validate the token itself, but rather use it as a bearer token when making requests to Nais components: