RBAC in Depth
RBAC in Depth
Role-Based Access Control (RBAC) is Kubernetes' primary authorization mechanism. Every production cluster — from a 10-node startup deployment to a thousands-of-nodes fleet at a top-tier cloud provider — depends on RBAC being configured correctly. Get it wrong and you either lock engineers out of their own clusters or, far worse, give compromised workloads the ability to read secrets across every namespace or pivot to the control plane.
This lesson builds a thorough mental model: what RBAC checks, how the API server evaluates it, and how senior SREs design least-privilege policies that hold up under a security audit.
How the API Server Evaluates a Request
Every request arriving at the Kubernetes API server passes through a pipeline: Authentication → Authorization → Admission Control. RBAC sits in the Authorization phase. The API server asks a single question: "Does this identity, operating on this resource in this namespace, have permission to perform this verb?"
Kubernetes denies by default. A request is allowed only if at least one RBAC policy explicitly grants it. There is no concept of deny rules — you model restrictions by simply not granting the permission in the first place.
The Four Core RBAC Objects
RBAC uses four resource kinds arranged in two pairs:
- Role — grants permissions within a single namespace.
- ClusterRole — grants permissions cluster-wide, or on non-namespaced resources such as Nodes, PersistentVolumes, and Namespaces themselves.
- RoleBinding — binds a Role or a ClusterRole to subjects inside one namespace.
- ClusterRoleBinding — binds a ClusterRole to subjects cluster-wide.
A common production pattern is to define a ClusterRole once (for example, pod-reader) and then use per-namespace RoleBindings to grant it only where needed. This avoids duplicating identical role manifests across dozens of namespaces.
Subjects: Users, Groups, and ServiceAccounts
Bindings attach to three kinds of subject:
- User — a human identity asserted by the authenticator (certificate CN field or OIDC
subclaim). Kubernetes has no User resource; the name is just a string. - Group — a set of users, typically driven by OIDC group claims or the certificate Organization field. Binding to groups (e.g.,
team-platform) is far more maintainable than binding individual users. - ServiceAccount — a namespaced Kubernetes object, automatically mounted as a projected JWT into every pod. This is how workloads authenticate to the API server at runtime.
system: prefix is reserved. Built-in subjects like system:authenticated, system:serviceaccounts:kube-system, and system:masters are managed by Kubernetes. Never create custom users or groups with this prefix — they may collide with internal bindings or break on a cluster upgrade.
Writing Least-Privilege Manifests
The production baseline: every workload runs under its own dedicated ServiceAccount with only the verbs it actually exercises. The default ServiceAccount in every namespace mounts a token automatically — disable this for workloads that make no Kubernetes API calls.
automountServiceAccountToken: false as the default. Then set automountServiceAccountToken: true only on the pods that actually call the Kubernetes API. This eliminates the token attack surface on every batch job, frontend pod, and database workload in the cluster.
Aggregated ClusterRoles
Kubernetes ships three default ClusterRoles built for humans: view, edit, and admin. They use aggregation — a label selector that automatically pulls in rules from any ClusterRole carrying a matching label. When you install a CRD (custom resource) and want it visible to users who already hold view, you add this to your CRD's ClusterRole:
Auditing Permissions: Who Can Do What?
Before a production launch or a compliance review, you need to enumerate exactly what each identity can do. kubectl auth can-i answers single questions, while the rakkess and kubectl-who-can plugins give you a full matrix view.
* wildcards and escalate/bind verbs. A role with verbs: ["*"] or resources: ["*"] is effectively cluster admin within its scope. The escalate verb lets a subject create Roles with more permissions than they currently hold; the bind verb lets them attach ClusterRoles to arbitrary subjects. Both are privilege-escalation vectors that should never appear in developer-facing roles. Audit for them regularly with: kubectl get clusterroles -o json | jq '.items[] | select(.rules[].verbs[] | contains("escalate","bind"))'.
Least-Privilege Principles at Scale
Large organizations operationalize RBAC through a few proven patterns:
- GitOps all RBAC manifests. Store every Role, ClusterRole, RoleBinding, and ClusterRoleBinding in Git. No manual
kubectl create rolein production — pull requests enforce peer review, and drift is caught automatically. - Namespace-per-team isolation. Each team owns exactly the namespaces assigned to them; their ServiceAccounts have no cross-namespace permissions. Shared platform services use dedicated namespaces with explicitly scoped bindings.
- Time-bound escalation. For break-glass scenarios, grant cluster-admin via a ClusterRoleBinding with an
ownerReferencepointing to a TTL-based Job, or use tools likeTeleportorPomeriumfor JIT (just-in-time) access that auto-revokes after a session ends. - Regular permission reviews. Run
kubectl auth reconcile --dry-runto detect drift. Schedule quarterly audits that compare current bindings against the GitOps-declared state and flag any ServiceAccount withsecrets getor namespace-widecreatepermissions.
Mastering RBAC is what separates engineers who can deploy Kubernetes from engineers who can operate it safely. Every concept in this tutorial — admission webhooks, custom operators, multi-tenancy — rests on the RBAC foundation you have built here.