Lesson 7.4: Service Accounts and Authentication
In Kubernetes, a ServiceAccount is an identity used by applications or Pods to interact with the Kubernetes API. Unlike regular users, ServiceAccounts are managed by Kubernetes and are typically used by workloads running in the cluster (e.g., Pods, Deployments).
Key Concepts
- ServiceAccount:
- A ServiceAccount is a Kubernetes resource that provides an identity for workloads (e.g., Pods) to authenticate with the Kubernetes API.
- Each ServiceAccount is associated with a token (stored as a Secret) that is used for authentication.
- Token:
- A ServiceAccount token is a JWT (JSON Web Token) that is automatically mounted into Pods using the ServiceAccount.
- The token is used to authenticate API requests made by the Pod.
- RBAC:
-
- ServiceAccounts can be granted permissions using Roles and RoleBindings (or ClusterRoles and ClusterRoleBindings).
-
- Default ServiceAccount:
- Every namespace has a default ServiceAccount.
- If a Pod does not specify a ServiceAccount, it automatically uses the default ServiceAccount in its namespace.
Viewing default service account
[root@master rbac]# kubectl auth whoami ATTRIBUTE VALUE Username kubernetes-admin Groups [kubeadm:cluster-admins system:authenticated] [root@master rbac]# kubectl get sa NAME SECRETS AGE default 0 6d22h [root@master rbac]# kubectl get sa -A | grep default default default 0 6d23h dev default 0 6d19h kube-node-lease default 0 6d23h kube-public default 0 6d23h kube-system default 0 6d23h local-path-storage default 0 6d23h mem-example default 0 4d1h prod default 0 6d19h [root@master rbac]# kubectl describe sa default Name: default Namespace: default Labels: <none> Annotations: <none> Image pull secrets: <none> Mountable secrets: <none> Tokens: <none> Events: <none> [root@master rbac]# kubectl get sa default -o yaml apiVersion: v1 kind: ServiceAccount metadata: creationTimestamp: "2025-03-01T04:55:57Z" name: default namespace: default resourceVersion: "328" uid: f5faa5b7-70c7-4f27-8b32-03947ec85fda
Creating a Service Account
[root@master services]# cat pod-lister-serviceaccount.yml apiVersion: v1 kind: ServiceAccount metadata: name: pod-lister namespace: default [root@master services]# kubectl apply -f pod-lister-serviceaccount.yml serviceaccount/pod-lister created [root@master services]# kubectl get sa | grep pod-lister pod-lister 0 8s
Bind the Role to the ServiceAccount
Create a RoleBinding
that binds the pod-reader
Role to the pod-lister
ServiceAccount.
[root@master services]# cat pod-lister-binding.yml apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: pod-lister-binding namespace: default subjects: - kind: ServiceAccount name: pod-lister namespace: default roleRef: kind: Role name: pod-reader apiGroup: rbac.authorization.k8s.io [root@master services]# kubectl apply -f pod-lister-binding.yml rolebinding.rbac.authorization.k8s.io/pod-lister-binding created [root@master services]# kubectl get rolebinding pod-lister-binding -n default NAME ROLE AGE pod-lister-binding Role/pod-reader 107s
Use the ServiceAccount in a Pod
Create a Pod that uses the pod-lister
ServiceAccount.
[root@master services]# cat pod-lister-pod.yml apiVersion: v1 kind: Pod metadata: name: pod-lister-pod namespace: default spec: serviceAccountName: pod-lister containers: - name: nginx image: nginx:latest [root@master services]# kubectl apply -f pod-lister-pod.yml pod/pod-lister-pod created [root@master services]# kubectl get pods NAME READY STATUS RESTARTS AGE pod-lister-pod 1/1 Running 0 3s
Verify the ServiceAccount Token
The ServiceAccount token is automatically mounted into the Pod at /var/run/secrets/kubernetes.io/serviceaccount/token
.
[root@master services]# kubectl exec -it pod-lister-pod -- sh # cat /var/run/secrets/kubernetes.io/serviceaccount/token eyJhbGciOiJSUzI1NiIsImtpZCI6ImR0QnQ4QWo4YXRFRm9DbW9MQ1Zad1NJTTJ5anVDYnd3d1BPaHVKRzg1V2cifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNzcyOTU5NzA4LCJpYXQiOjE3NDE0MjM3MDgsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0IiwicG9kIjp7Im5hbWUiOiJwb2QtbGlzdGVyLXBvZCIsInVpZCI6IjZlZmQ0MGI0LTU4OTMtNDBhZi1iNTQ4LTc5MzBmZjdmNDExMyJ9LCJzZXJ2aWNlYWNjb3VudCI6eyJuYW1lIjoicG9kLWxpc3RlciIsInVpZCI6IjYyMTg4Y2JhLWY3MzUtNDg1Ni1hMDFkLWEwZWI4MDVmMjk2ZiJ9LCJ3YXJuYWZ0ZXIiOjE3NDE0MjczMTV9LCJuYmYiOjE3NDE0MjM3MDgsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OnBvZC1saXN0ZXIifQ.CsIvlVbj7tvu62dxt74W--XLlIGpXQzSr_8McC2xI-0BxqKWoErzeB6ERJ6JILg90fo1uhCp7A5Btx_k2pbjl29e4CIo9nlLAhi17OTxuszXnUEUP2T-CMYD4BnX_qvCROoSsXRt5nZjjszi-0TjtDi0yTUscdRF3pUg00WVtbyGxqJ0bbMe0GQj9O1WKJuXjaoLbq1KXBJEwy2aRaT0bBzFSTMcUUWEUaCsDV-VGdWT5tAv_vg_KdPh0fkStSWn0LnKCFS1bpM6jUVcmw471I2xKP8zp62V97Y_-njxpporLSUZDbBk2CVwl9Pe8Q375vzygxM1Nn0-adEbgRFvUA# # curl -k --header "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" https://kubernetes.default.svc/api/v1/namespaces/default/pods
Manually create a long-lived API token for a ServiceAccount
[root@master services]# cat pod-lister-secret.yml apiVersion: v1 kind: Secret metadata: name: pod-lister-token annotations: kubernetes.io/service-account.name: pod-lister type: kubernetes.io/service-account-token [root@master services]# kubectl apply -f pod-lister-secret.yml
The token is automatically generated and stored in the data.token field of the Secret. To retrieve the token:
[root@master services]# kubectl get secret pod-lister-token -n default -o yaml apiVersion: v1 data: ca.crt: LS0tLS1CRU... namespace: ZGVmYXVsdA== token: ZXlKaGJHY2... kind: Secret metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"v1","kind":"Secret","metadata":{"annotations":{"kubernetes.io/service-account.name":"pod-lister"},"name":"pod-lister-token","namespace":"default"},"type":"kubernetes.io/service-account-token"} kubernetes.io/service-account.name: pod-lister kubernetes.io/service-account.uid: 62188cba-f735-4856-a01d-a0eb805f296f creationTimestamp: "2025-03-08T09:02:53Z" name: pod-lister-token namespace: default resourceVersion: "408617" uid: 69072f15-5f7b-4db5-b7b7-b5aa81371c13 type: kubernetes.io/service-account-token # Replace <base64-encoded-token> with the value of data.token from the Secret. [root@master services]# echo ZXlKaGJHY... | base64 --decode eyJhbGci...
Now that you have created a long-lived API token for the pod-lister
ServiceAccount and extracted the token, the next steps involve using the token to authenticate with the Kubernetes API. Here’s what you need to do:
You can use the token to authenticate with the Kubernetes API in several ways. Below are the most common methods:
Option 1: Use the Token Directly in API Requests
Find the API Server URL
[root@master services]# kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}' https://127.0.0.1:35777
Get the token and save into a file, then curl using the token in authorization header
[root@master services]# kubectl get secret pod-lister-token -n default -o yaml [root@master services]# echo ZXlKaGJHY2lPaUpTVXp... | base64 --decode > secret.txt [root@master services]# curl -k --header "Authorization: Bearer $(cat /root/testrbac/services/secret.txt)" https://127.0.0.1:35777/api/v1/namespaces/default/pods
Option 2:
[root@master services]# kubectl config set-credentials pod-lister-user --token=eyJhbG... User "pod-lister-user" set. [root@master services]# kubectl config set-context pod-lister-context --cluster=pod-lister-cluster --user=pod-lister-user Context "pod-lister-context" created. [root@master services]# kubectl config set-cluster pod-lister-cluster --server=https://127.0.0.1:35777 --insecure-skip-tls-verify=true [root@master services]# kubectl config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE adam kind-cka-cluster2 adam kind-cka-cluster1 kind-cka-cluster1 kind-cka-cluster1 * kind-cka-cluster2 kind-cka-cluster2 kind-cka-cluster2 pod-lister-context pod-lister-cluster pod-lister-user sanjeeb kind-cka-cluster2 sanjeeb