Kubernetes pods run with a namespace identity, and that identity controls what the workload can request from the API server. Assigning a specific ServiceAccount keeps one application pod from inheriting the namespace default account and gives RBAC bindings a precise subject to target.
The pod spec selects the account with serviceAccountName. Kubernetes records that name on the pod and, unless token mounting is disabled, mounts API credentials through the normal service-account volume path for code that talks to the Kubernetes API.
Create the ServiceAccount in the same namespace as the pod before the pod is created. Add only the RBAC permissions that the workload needs, then verify both the saved pod spec and an in-pod API call before moving the same field into a Deployment, Job, or other pod template.
$ kubectl create namespace app-identity namespace/app-identity created
Use the application namespace instead of app-identity when assigning an account to a real workload.
Related: How to create a Kubernetes namespace
$ kubectl create serviceaccount api-reader --namespace app-identity serviceaccount/api-reader created
$ kubectl create role pod-reader --namespace app-identity --verb=get --verb=list --resource=pods role.rbac.authorization.k8s.io/pod-reader created
The sample role allows only Pod reads in app-identity. Replace it with the smallest verb and resource set the workload actually needs.
Related: How to grant Kubernetes namespace access with RBAC
$ kubectl create rolebinding api-reader-pod-reader --namespace app-identity --role=pod-reader --serviceaccount=app-identity:api-reader rolebinding.rbac.authorization.k8s.io/api-reader-pod-reader created
$ kubectl auth can-i list pods --namespace app-identity --as=system:serviceaccount:app-identity:api-reader yes
--as asks the API server to evaluate the request as the service-account identity. Run it from an administrator identity that can impersonate service accounts, or run a matching check from inside the pod after it starts.
apiVersion: v1 kind: Pod metadata: name: identity-check namespace: app-identity spec: serviceAccountName: api-reader restartPolicy: Never containers: - name: identity-check image: curlimages/curl:8.10.1 command: - sh - -c - | TOKEN="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" NAMESPACE="$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)" HTTP_CODE="$( curl --silent --output /tmp/pod.json --write-out '%{http_code}' \ --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt \ --header "Authorization: Bearer ${TOKEN}" \ "https://kubernetes.default.svc/api/v1/namespaces/${NAMESPACE}/pods/identity-check" )" echo "namespace=${NAMESPACE}" echo "serviceAccountName=api-reader" echo "api_status=${HTTP_CODE}" sleep 300
serviceAccountName is set when the pod is created. For a controller-managed workload, place the same field under the controller's pod template and let the controller create replacement pods.
$ kubectl apply -f serviceaccount-pod.yaml pod/identity-check created
$ kubectl wait --for=condition=Ready pod/identity-check --namespace app-identity --timeout=120s pod/identity-check condition met
$ kubectl get pod identity-check --namespace app-identity -o custom-columns=NAME:.metadata.name,SERVICEACCOUNT:.spec.serviceAccountName NAME SERVICEACCOUNT identity-check api-reader
$ kubectl logs identity-check --namespace app-identity namespace=app-identity serviceAccountName=api-reader api_status=200
api_status=200 means the mounted service-account token authenticated to the API server and the pod-reader Role allowed the request.
$ kubectl delete namespace app-identity namespace "app-identity" deleted
Skip this command for a real application namespace. Delete only the test pod, test Role, or test RoleBinding when the namespace contains other workloads.