How to assign a Kubernetes ServiceAccount to a pod

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.

Steps to assign a Kubernetes ServiceAccount to a pod:

  1. Create a namespace for the identity test.
    $ 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

  2. Create the ServiceAccount in that namespace.
    $ kubectl create serviceaccount api-reader --namespace app-identity
    serviceaccount/api-reader created
  3. Create a namespace Role for the API smoke test.
    $ 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

  4. Bind the Role to the ServiceAccount.
    $ 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
  5. Check the permission as the ServiceAccount subject.
    $ 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.

  6. Create a pod manifest that uses the ServiceAccount.
    serviceaccount-pod.yaml
    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.

  7. Apply the pod manifest.
    $ kubectl apply -f serviceaccount-pod.yaml
    pod/identity-check created
  8. Wait for the pod to become ready.
    $ kubectl wait --for=condition=Ready pod/identity-check --namespace app-identity --timeout=120s
    pod/identity-check condition met
  9. Confirm the saved pod spec uses the custom ServiceAccount.
    $ kubectl get pod identity-check --namespace app-identity -o custom-columns=NAME:.metadata.name,SERVICEACCOUNT:.spec.serviceAccountName
    NAME             SERVICEACCOUNT
    identity-check   api-reader
  10. Read the pod log from the in-cluster API request.
    $ 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.

  11. Delete the test namespace when the identity check is finished.
    $ 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.