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