Lab 28 - Service accounts

Lab 28 - Service accounts

Goal: see the token every Pod carries, call the API with it, and give an application exactly the rights it needs. Chapter: Service accounts

# 1 - a Pod with curl, running as the default ServiceAccount
kubectl run api-client -n dev --image curlimages/curl:8.10.1 --command -- sleep 3600
kubectl get pod api-client -n dev -o jsonpath='{.spec.serviceAccountName}{"\n"}'   # default
kubectl exec -n dev api-client -- ls /var/run/secrets/kubernetes.io/serviceaccount
# 2 - what is in the token? (a JWT: header.payload.signature)
kubectl exec -n dev api-client -- cat /var/run/secrets/kubernetes.io/serviceaccount/token \
  | cut -d. -f2 | base64 -d 2>/dev/null; echo

Find sub (system:serviceaccount:dev:default), aud, exp (about 1 hour) and the Pod name - the token is bound to this Pod.

# 3 - call the API from inside the Pod
kubectl exec -n dev api-client -- sh -c '
  SA=/var/run/secrets/kubernetes.io/serviceaccount
  curl -s --cacert $SA/ca.crt -H "Authorization: Bearer $(cat $SA/token)" \
    https://kubernetes.default.svc/api/v1/namespaces/dev/pods | head -20'

403 Forbidden ... "system:serviceaccount:dev:default" cannot list pods. Authenticated, not authorized - exactly like Jane.

A dedicated ServiceAccount

# 4 -
kubectl create sa pod-lister -n dev
kubectl create role list-pods -n dev --verb=get,list --resource=pods
kubectl create rolebinding pod-lister -n dev --role=list-pods --serviceaccount=dev:pod-lister
kubectl auth can-i list pods -n dev --as system:serviceaccount:dev:pod-lister
# 5 - the serviceAccountName of a Pod cannot be changed - create a new one
kubectl delete pod api-client -n dev
kubectl run api-client -n dev --image curlimages/curl:8.10.1 \
  --overrides='{"spec":{"serviceAccountName":"pod-lister"}}' --command -- sleep 3600
kubectl exec -n dev api-client -- sh -c '
  SA=/var/run/secrets/kubernetes.io/serviceaccount
  curl -s --cacert $SA/ca.crt -H "Authorization: Bearer $(cat $SA/token)" \
    https://kubernetes.default.svc/api/v1/namespaces/dev/pods | grep "\"name\": \"web" | head -3'

No token where none is needed

# 6 -
kubectl patch sa default -n dev -p '{"automountServiceAccountToken":false}'
kubectl run no-token -n dev --image nginx:1.27
kubectl exec -n dev no-token -- ls /var/run/secrets/kubernetes.io/serviceaccount   # no such directory

Most applications never call the API. Without a token, a compromised container has nothing to steal.

Discovery

Infodiscover

Task A. A CI pipeline needs a token for pod-lister, valid 10 minutes. Create it and use it with kubectl from support01.

TOKEN=$(kubectl create token pod-lister -n dev --duration=10m)
kubectl --token "$TOKEN" get pods -n dev
kubectl --token "$TOKEN" get pods -n default      # Forbidden

--token overrides the credentials of the current kubeconfig user.

Task B. Which ServiceAccounts in the cluster are bound to cluster-admin?

kubectl get clusterrolebindings -o json | \
  grep -B2 -A12 '"name": "cluster-admin"' | grep -A2 ServiceAccount
kubectl get clusterrolebindings -o wide | grep cluster-admin

Clean up

kubectl delete pod api-client no-token -n dev
kubectl patch sa default -n dev -p '{"automountServiceAccountToken":null}'