How does RBAC work -- Roles, ClusterRoles, RoleBindings, and ServiceAccounts?
Quick Answer
RBAC (Role-Based Access Control) in Kubernetes controls who can perform what actions on which resources. Roles and ClusterRoles define permissions (verbs on resources), RoleBindings and ClusterRoleBindings attach those permissions to subjects (Users, Groups, or ServiceAccounts), with Roles scoped to a namespace and ClusterRoles scoped cluster-wide.
Detailed Answer
Think of RBAC like the security system of a large office building. A Role is like a keycard that opens specific doors on a specific floor (namespace). A ClusterRole is like a master keycard that works across all floors. A RoleBinding is the act of issuing a keycard to a specific employee for a specific floor. A ServiceAccount is an employee badge for an automated system (like the mail robot) that needs to move through certain areas. Without RBAC, every employee would have a master key, which is the equivalent of running everything as cluster-admin.
In Kubernetes, RBAC is one of several authorization modules (others include ABAC, Webhook, and Node authorization). It is enabled by default in most distributions and is the standard mechanism for controlling access to the API server. RBAC operates on four object types: Role (namespaced permissions), ClusterRole (cluster-wide permissions), RoleBinding (grants a Role or ClusterRole to subjects in a specific namespace), and ClusterRoleBinding (grants a ClusterRole to subjects across all namespaces). The API server evaluates RBAC rules on every request by checking if any binding grants the requesting subject the required verb on the requested resource.
Internally, when a request hits the kube-apiserver, it passes through three stages: Authentication (who are you?), Authorization (are you allowed?), and Admission Control (any mutations or validations?). During the Authorization stage, the RBAC authorizer retrieves all RoleBindings and ClusterRoleBindings that reference the requesting subject. For each binding, it checks if the associated Role or ClusterRole contains a rule that matches the request's verb (get, list, create, update, patch, delete, watch), resource (pods, services, deployments), API group (apps, batch, networking.k8s.io), and optionally the specific resource name. If any rule matches, the request is allowed; if no rule matches across all bindings, the request is denied. Rules are additive only -- there are no deny rules in RBAC.
At scale, RBAC management becomes complex. Large organizations use ClusterRoles as templates bound via RoleBindings in specific namespaces, allowing a single ClusterRole like 'namespace-admin' to be reused across hundreds of namespaces. Aggregated ClusterRoles (using aggregationRule with label selectors) allow CRD operators to automatically extend existing roles. ServiceAccounts are the primary identity for Pods: each namespace has a 'default' ServiceAccount, and Pods that do not specify a ServiceAccount use it. Since Kubernetes 1.24, ServiceAccount tokens are no longer auto-mounted as long-lived Secrets; instead, the TokenRequest API issues short-lived, audience-bound tokens projected into Pods via projected volumes.
A non-obvious gotcha is that RoleBindings can reference ClusterRoles, which is actually a powerful pattern. You define the ClusterRole once and bind it in specific namespaces, scoping its permissions to that namespace. Without this pattern, you would need to duplicate Role definitions in every namespace. Another trap: the default ServiceAccount in each namespace often has no permissions (good), but many teams add permissions to the default ServiceAccount instead of creating dedicated ServiceAccounts per workload. This means any Pod in the namespace inherits those permissions, violating least privilege. The automountServiceAccountToken: false setting should be applied to the default ServiceAccount, and workload-specific ServiceAccounts should be created for Pods that actually need API access.