Service Account Token: breaking change k8s 1.24
This article aims to help people who did not migrate to kubernetes 1.24 or greater. For others, you might have encounter that change already.
Since Kubernetes version 1.24 , ServiceAccount
don’t generate tokens as secrets by default anymore.
> kubectl create sa example-sa
Before kubernetes 1.24
> kubectl describe sa example-sa
Name: example-sa
Namespace: default
Labels: <none>
Annotations: <none>
Image pull secrets: <none>
Mountable secrets: example-sa-token-rev86
Tokens: example-sa-token-rev86
Events: <none>
After kubernetes 1.24
> kubectl describe sa example-sa
Name: example-sa
Namespace: default
Labels: <none>
Annotations: <none>
Image pull secrets: <none>
Mountable secrets: <none>
Tokens: <none>
Events: <none>
We can see that the token is not generated anymore.
Create a token
Using kubectl
> kubectl create token example-sa
eyJhbGciOiJSU....SLoBbhiafJnw
It’s possible to define an expiration period with --duration=
option.
As of today, the default value is 3600s.
Old behavior
If we need to have a secret with a non-expiring token, we can do so.
We have to create a secret of type kubernetes.io/service-account-token
with an annotation kubernetes.io/sevice-account.name
.
apiVersion: v1
kind: Secret
type: kubernetes.io/service-account-token
metadata:
name: example-sa-token
annotations:
kubernetes.io/service-account.name: "example-sa"
The secret will be populated with the token
and the ca certificates
.
When deploying with Helm, a good practice will be to verify the Kubernetes version and deploy the secret only for version >= 1.24
.
To do so, we can use helm capabilities and helm semverCompare function
apiVersion: v1
kind: ServiceAccount
metadata:
name: example-sa
---
{{- if semverCompare ">=1.24-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: v1
kind: Secret
type: kubernetes.io/service-account-token
metadata:
name: example-sa-token
annotations:
kubernetes.io/service-account.name: "example-ca"
{{- end -}}
Keep in mind that token generation behavior change for security reasons, so avoid as much as possible to create a long live token and prefer generated one with the TokenRequestAPI
.
Mounting token
Automatically
Token are still mounted automatically when ServiceAccountName
property is used in pod spec.
The token will be available under /var/run/secrets/kubernetes.io/serviceaccount/token
, it is valid for 1h and is automatically renewed.
apiVersion: v1
kind: Pod
metadata:
name: example
spec:
containers:
- name: example
image: nginx
ports:
- containerPort: 80
serviceAccountName: example-sa
Unless you specified the SA should not automount the token by setting automountServiceAccountToken
to false.
apiVersion: v1
automountServiceAccountToken: false
kind: ServiceAccount
metadata:
name: example-sa
Manually
For SA auto-mounting in pod, a projected volume
is used under the hood.
We can leverage it by creating one manually. We can then mount it in a different location and even change the expiry.
apiVersion: v1
kind: Pod
metadata:
name: example
spec:
containers:
- name: example
image: nginx
ports:
- containerPort: 80
volumeMounts:
- mountPath: /var/run/secrets/token
name: token
readOnly: true
serviceAccountName: example-sa
volumes:
- name: token
projected:
defaultMode: 420
sources:
- serviceAccountToken:
expirationSeconds: 600
path: token
If you need to keep the old behavior using the token store into a secret, you can still mount it into a volume. But once again, keep in mind it should be avoid as possible for security reasons.
apiVersion: v1
kind: Pod
metadata:
name: example
spec:
containers:
- name: example
image: nginx
ports:
- containerPort: 80
volumeMounts:
- mountPath: /var/run/secrets/token
name: token
readOnly: true
volumes:
- name: token
secret:
defaultMode: 420
secretName: example-sa-token