Skip to content

kubectl whoami and Service Account Permission Checks

When deploying an application to Kubernetes, the most common failure is a service account that cannot do what it should. Permission denied when creating a secret, rejection on list pods, refusal on update. kubectl whoami and kubectl auth can-i let you quickly identify exactly who cannot do what.

kubectl whoami plugin

Note

kubectl whoami is not a built-in kubectl command. It is a plugin from krew or a standalone binary. Install with kubectl krew install whoami or download from GitHub.

After installation the command shows the current context and associated service account:

kubectl whoami

Output:

system:serviceaccount:default:myapp

Without the plugin, the same information is available via:

kubectl auth can-i --list

The beginning of the output shows User: system:serviceaccount:default:myapp — that is your whoami.

kubectl auth can-i: checking arbitrary subject permissions

The built-in kubectl auth can-i command checks permissions without impersonating the target subject. Syntax:

kubectl auth can-i <verb> <resource> --as=<subject>

The --as format for a service account:

# Within a namespace
kubectl auth can-i list pods \
  --as=system:serviceaccount:default:myapp

# Cross-namespace
kubectl auth can-i list pods \
  --as=system:serviceaccount:production:myapp \
  -n production

Responses: yes or no.

To check the full permission set of an SA:

kubectl auth can-i --list --as=system:serviceaccount:default:myapp
Tip

Combining --as with --list is a fast SA permission audit. The output contains a table with resources, versions, and permitted actions.

kubectl auth can-i flags

FlagPurpose
--as <subject>Subject to check
-n <namespace>Subject’s namespace (for SA)
--listAll permissions of the subject
--quiet / -qExit code only, no output
--no-headersNo table headers

Exit code: 0 for yes, 1 for no. Useful for scripts:

kubectl auth can-i delete secrets --as=system:serviceaccount:default:myapp
if [ $? -eq 0 ]; then
  echo "SA can delete secrets — review the policy"
fi

Binding ClusterRole to a Service Account: RoleBinding vs ClusterRoleBinding

A service account is bound to a role through two resources. The difference is scope.

RoleBinding binds a Role or ClusterRole to an SA within a single namespace:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: myapp-pod-reader
  namespace: default
subjects:
  - kind: ServiceAccount
    name: myapp
    namespace: default
roleRef:
  kind: ClusterRole        # reference to ClusterRole
  name: pod-reader        # ClusterRole name
  apiGroup: rbac.authorization.k8s.io
Note

RoleBinding can reference either Role or ClusterRole. With Role, permissions are limited to that namespace. With ClusterRole, permissions apply within the RoleBinding’s namespace but inherit all ClusterRole rules.

ClusterRoleBinding binds a ClusterRole cluster-wide:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: myapp-cluster-reader
subjects:
  - kind: ServiceAccount
    name: myapp
    namespace: default
roleRef:
  kind: ClusterRole
  name: cluster-reader
  apiGroup: rbac.authorization.k8s.io
ScenarioResource
SA needs permissions in one namespace onlyRoleBinding → ClusterRole
SA needs cluster-wide permissionsClusterRoleBinding
Shared role for different SA across namespacesClusterRoleBinding with multiple subjects

Subject in CSR: reading and verifying

A CSR (Certificate Signing Request) contains spec.username and spec.groups. For an SA it looks like this:

kubectl get csr <csr-name> -o jsonpath='{.spec}' | jq .

Output:

{
  "request": "base64-encoded-certificate-request",
  "username": "system:serviceaccount:default:myapp",
  "groups": ["system:serviceaccount", "system:serviceaccounts", "system:serviceaccounts:default"],
  "uid": "...",
  "extra": {
    "authentication.kubernetes.io/credential-id": ["..."],
    "authentication.kubernetes.io/node-name": ["..."]
  }
}

Three components in username separated by colons: system:serviceaccount:<namespace>:<name>.

To check permissions of a specific SA from a CSR:

# Extract SA from CSR
SUBJECT=$(kubectl get csr <csr-name> -o jsonpath='{.spec.username}')
kubectl auth can-i list pods --as="$SUBJECT"
Warning

CSR is created by kubelet when a node connects or through ServiceAccount admission. If an SA uses the TokenRequest API (the modern approach), no CSR is generated — the token is issued directly.

Quick check in CI/CD

In a pipeline you need to confirm the deploy service account has sufficient rights before running manifests:

#!/bin/bash
SA="system:serviceaccount:ci-runner:deployer"
RESOURCES=("pods" "services" "configmaps" "secrets")

for RES in "${RESOURCES[@]}"; do
  kubectl auth can-i create "$RES" --as="$SA" -n "$NAMESPACE" || {
    echo "ERROR: SA cannot create $RES"
    exit 1
  }
done

echo "Permissions confirmed"
kubectl auth can-i get pods --as="$SA" -n "$NAMESPACE"
Tip

Add this check after kubectl apply or helm template — an early exit is cheaper than a crashed pod with ImagePullBackOff due to missing imagePullSecrets.

Useful output for diagnostics in CI logs:

kubectl auth can-i --list --as="system:serviceaccount:default:myapp" --no-headers

Lines without headers are easy to grep for suspicious wildcards like */* or */delete.