BlogKubernetes

Kubernetes RBAC least privilege: from admin to scoped roles

Replace blanket cluster-admin with namespaced Roles, audit who can do what, and test access with kubectl auth can-i.

Apr 14, 2026·4 min readIntermediate·By the SecOpsLog team · command-tested

Most clusters accumulate cluster-admin bindings the way garages accumulate boxes — a CI service account here, a dashboard SA there, a break-glass group that never got cleaned up. RBAC least privilege means every human and service account gets exactly the verbs and resources it needs, in exactly the namespaces it operates in. The proof is not a spreadsheet; it is kubectl auth can-i.

The goal is not zero cluster-admin forever — someone needs break-glass — but every binding should be intentional, scoped, and auditable. Start by listing what a service account can actually do today, then replace blanket grants with namespaced Roles. The Kubernetes administration course covers RBAC mechanics if Role versus ClusterRole still feels fuzzy.

How a pod proves identity to the API server

The token is identity. RBAC is permission. A leaked long-lived token is dangerous — prefer projected, short-lived, audience-bound JWTs.

authenticated request allow deny kubelet TokenRequest projection issues + rotates the token Pod workload container SA token · JWT short-lived · audience-bound kube-apiserver request pipeline · two gates 1 · Authenticate verify signature + expiry → system:serviceaccount:ns:name 2 · Authorize · RBAC check (Cluster)RoleBinding for that ServiceAccount ✓ etcd / resource ALLOWED · request proceeds ✕ 403 Forbidden DENIED · no binding grants it Identity = the signed token · Permissions = RBAC. A leaked long-lived token is dangerous, so tokens are short-lived + audience-scoped.
authenticated request allowed denied token issued / rotated
RBAC tightening workflow

Audit first, tighten second, test third. Skipping the audit means you revoke something production depends on at 2am.

1List bindingswho has cluster-admin2Audit SAsauth can-i --list3Namespaced Rolespecific verbs only4RoleBindingone SA, one namespace5Remove wildcardsno * on verbs6Test negativecan-i delete? no7Gate in CIpolicy-as-code check

Audit what a service account can do today

Before you write a single Role, see the world through the service account's eyes. kubectl auth can-i --list prints every allowed verb/resource pair. If you see * in the Verbs column, you have work to do.

bash — audit what a SA can dolive
kubectl auth can-i --list --as=system:serviceaccount:shop:web
Resources Verbs
pods [get list watch]
configmaps [get]
if this prints * [*] you have work to do

Prefer namespaced Role over ClusterRole

A Role applies to one namespace. A ClusterRole applies cluster-wide. Default to Role unless the workload genuinely needs cluster-scoped resources like Nodes or PersistentVolumes. Grant specific verbs on specific resources — no wildcards.

role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: shop
name: web-reader
rules:
- apiGroups: [""]
resources: [pods, configmaps]
verbs: [get, list, watch]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
namespace: shop
name: web-reader
subjects:
- kind: ServiceAccount
name: web
namespace: shop
roleRef:
kind: Role
name: web-reader
apiGroup: rbac.authorization.k8s.io

Find who still has cluster-admin

ClusterRoleBindings are the dangerous ones — they grant cluster-wide power. Every name in this list is a full-cluster takeover if compromised.

bash — the dangerous bindingslive
kubectl get clusterrolebindings -o wide | grep cluster-admin
NAME ROLE SUBJECTS
cluster-admin ClusterRole/cluster-admin Group system:masters
jenkins-deployer ClusterRole/cluster-admin SA ci:jenkins
default-dashboard ClusterRole/cluster-admin SA kube-system:dashboard
every name here is a full-cluster takeover if compromised
Wildcards are cluster-admin by another name
verbs ["*"] on resources ["*"] is the same blast radius as cluster-admin. Enumerate the verbs you actually use: get/list/watch for readers, add create/update/patch/delete only where the workload needs them.

Use Role aggregation sparingly

ClusterRoles like view, edit, and admin exist for human operators and are composed through RoleBinding to a namespaced Role. That is fine for developers who need broad namespace access. For automation — CI deployers, operators, controllers — never bind edit or admin; write a Role with exactly the verbs that controller calls in its reconcile loop.

Test before and after with auth can-i

Run the negative test explicitly. A reader that cannot delete pods but can read Secrets is still over-privileged. Check every verb that would hurt if an attacker had it. Document the intended access matrix in the Role's description or in your GitOps repo so reviewers know why each verb is there.

bash
# should be yes — the Role grants read
kubectl auth can-i get pods \
--as=system:serviceaccount:shop:web -n shop
# should be no — delete is not in the Role
kubectl auth can-i delete pods \
--as=system:serviceaccount:shop:web -n shop

Where this goes next

RBAC controls who can call the API. NetworkPolicy controls who can talk on the wire. Admission controllers like Gatekeeper enforce what objects can exist at all. The Kubernetes security (CKS) path walks all three layers with hands-on labs.

Go deeper in a courseKubernetes security (CKS-aligned)RBAC, Pod Security, admission control and runtime hardening.View course

Related posts