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    
 
 

References

All systems normal

© 2025 2023 Sanjeeb KC. All rights reserved.