Authorization runs only after the request is authenticated. The apiserver takes the request attributes (user, group, verb, resource, namespace…) and asks each module listed in --authorization-mode (for example Node,RBAC) in turn.
flowchart LR
R["Authenticated request"] --> N{"Node"}
N -- "no opinion" --> B{"RBAC"}
B -- "no opinion" --> W{"Webhook"}
W -- "no opinion" --> D["403 Forbidden"]
N -- "allow" --> OK["On to admission"]
B -- "allow" --> OK
W -- "allow" --> OK
The first module that says allow or deny decides at once; if no module allows the request it is refused (default deny).
| Mode | Used for |
|---|---|
Node |
Kubelets only: read/write objects related to pods on that node |
ABAC |
Attribute policies in a JSON file (one object per line), changes need an apiserver restart; rarely used |
RBAC |
Role-based rights declared as API objects — the most common |
Webhook |
Asks an external REST service through an HTTP POST |
RBAC has allow rules only, no "deny" rule: to block something, simply do not grant it. Tell 401 (not authenticated) apart from 403 (authenticated but not allowed).
| Command | Meaning |
|---|---|
kubectl auth can-i create deployments -n dev |
May you create Deployments in dev |
kubectl auth can-i list pods --as=system:serviceaccount:dev:ci -n dev |
Check as another identity (needs impersonate rights) |
kubectl api-versions \| grep rbac |
rbac.authorization.k8s.io/v1 means RBAC is on |
How a request is described
Authorizers see the request as attributes:
| Attribute | Example |
|---|---|
| User and groups | alice, devops, system:authenticated |
| Verb | get, list, watch, create, update, patch, delete |
| API group and resource | apps / deployments |
| Subresource | pods/log, pods/exec, deployments/scale |
| Namespace and name | dev / web |
Subresources matter: permission to get pods does not include pods/exec or pods/log, so you can let developers read logs without allowing them to open shells in containers.
Special groups and users
Kubernetes adds groups automatically: system:authenticated for every signed-in identity, system:unauthenticated for anonymous requests, and system:serviceaccounts:<namespace> for ServiceAccounts. Nodes authenticate as system:node:<name> in the system:nodes group, which is what the Node authorizer (together with the NodeRestriction admission plugin) uses to limit each kubelet to its own pods.
Checking permissions
kubectl auth can-i --list -n dev # everything you may do in dev
kubectl auth can-i delete pods --as=alice -n prod # what alice may do
kubectl auth can-i get pods/log --as=system:serviceaccount:dev:ci -n dev
kubectl get errors include the denied verb and resource, which tells you exactly which rule is missing.
Webhook authorization in managed clusters
Managed services use the webhook mode to connect cloud identity systems: Azure RBAC for Kubernetes on AKS lets Entra ID role assignments grant Kubernetes permissions, and GKE combines Google IAM with Kubernetes RBAC. In those clusters, a request can be allowed by either system, so check both when debugging.
Least privilege habits
Avoid giving * verbs or resources. Grant edit or view ClusterRoles through namespaced RoleBindings for most people, reserve cluster-admin for a small break-glass group, and review bindings regularly with tools such as kubectl-who-can or rakkess.