As the name suggests, the service accounts are for the services or the non-human users in Kubernetes. It can perform all the tasks that the K8s API allows like human users. Kubernetes by default creates a service account in each namespace of a cluster and call it a default service account. These default service accounts are mounted to every pod launched.
However, the default service account has no attached permissions, and due to this, it is not of much use until we bind the service account with a role in the K8s RBAC.
In addition to the default service accounts, K8s allows us to create as many user-defined service accounts as we want. We can use the below command to create a service account.
kubectl create serviceaccount my-service-account
# Describing service account
me@mycomp ~ % kubectl describe sa my-service-account
Name: my-service-account
Namespace: default
Labels: <none>
Annotations: <none>
Image pull secrets: <none>
Mountable secrets: <none>
Tokens: <none>
Events: <none>
In the K8s version before 1.24, every time we would create a service account, a non-expiring secret token (Mountable secrets & Tokens) was created by default. However, from version 1.24 onwards, it was disbanded and no secret token is created by default when we create a service account. However, we can create it when need be. Now let us take a look at the service account token in a bit more depth.
Service Account Token
Kubernetes supports two types of tokens from version 1.22 onwards.
- Long-Lived Token
- Time Bound Token
Long-Lived Token
As its name indicates, a long-lived token is one that never expires. Hence, it is less secure and discouraged to use.
Creating Long-Lived Token
Before K8s version 1.24, whenever a service account was created, a secret object was also created that contains the secret token. These token would be long-lived token, which means it has no expiry. However, In Kubernetes version 1.24, it was disbanded due to security and scalability concerns.
Although not recommended, K8s allows us to create a long-lived token. It is achieved in two different steps:
- Create a service account
kubect create serviceaccount my-service-account
- Create a secret and specify the name of the service account as annotations within the metadata section.
kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
name: my-long-lived-secret
annotations:
kubernetes.io/service-account.name: my-service-account
type: kubernetes.io/service-account-token
EOF
Time Bound Token
From version 1.22 onwards, Kubernetes introduced TokenRequest
API. A token generated through this API is a time-bound token that expires after a time. It applies to both — the default service account and the custom-defined service accounts.
Creating a time-bound token
We can create a time-bound token using the below command:
kubectl create token my-time-bound-token
However, it is not required to create a token manually. Taking an example of the default service account — when a pod is launched with automountServiceAccountToken
set to True
, K8s control plane mounts a project volume to the pod. The kubelet agent running on the node provisions the token on this volume.
kubectl get pod nginx -o yaml
[truncated]
spec:
containers:
- image: nginx
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: kube-api-access-cqslr
readOnly: true
serviceAccount: default
serviceAccountName: default
[truncated]
Token Expiration
Kubernetes is designed to expire the token in one hour, but there are many legacy applications running with the non-expiring token. To allow gradual adoption of the time-bound token, Kubernetes has allowed cluster admins to specify --service-account-extend-token-expiration=true
to Kube API Server. When specified, it will allow tokens to have longer expiration (365 days) temporarily and record the usage of legacy tokens.
Click here to learn more about the token expiry.
Even if the token-expiration
flag is set to true
, Kubernetes allows us to create a token or mount a token that expires in one hour or whatever time we want. We can use the below definitions to achieve it.
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- mountPath: /var/run/secrets/tokens
name: my-proj-vol
serviceAccountName: my-service-account #service acount
volumes:
- name: my-proj-vol
projected:
sources:
- serviceAccountToken:
path: my-proj-vol
expirationSeconds: 3600 #specify the desired epiration time in seconds
Configuring a Service Account for a Pod
Unlike the default service accounts, custom service accounts are not configured for a pod automatically. If we want to configure my-service-account
for a pod, the following are the conditions:
- A service account cannot be mounted to a running pod.
To configure a service account for a pod, we can use below pod definition file:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
serviceAccountName: my-service-account
automountServiceAccountToken: true
Using the service account in a pod
The service account that we create above, does not contain any permission. Once we have created a role and role binding, we can use the service account to perform the specified task.
[For role & role binding examples — please click here]
- Exec into the pod using the below command
kubectl exec -it my-pod-with-service-account
- Store the secret token in a variable
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
- Send curl request to the Kubernetes API.
curl -H "Authorization: Bearer $TOKEN" https://kubernetes/api/v1/namespaces/default/pods/ --insecure
The above curl command will list down all the pods and their configuration in the default namespaces.
me@mycom % kubectl exec -it my-pod-with-service-account -- bash
root@my-pod-with-service-account:/# TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
root@my-pod-with-service-account:/# curl -H "Authorization: Bearer $TOKEN" https://kubernetes/api/v1/namespaces/default/pods/ --insecure
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"resourceVersion": "46252191"
},
"items":[truncated]