Kubernetes RBAC (Role-Based Access Control) and ABAC (Attribute-Based Access Control) aren’t just different ways to manage permissions; they represent fundamentally different philosophies on how to grant access to your cluster.
Let’s see RBAC in action. Imagine a developer, alice, who needs to deploy pods but shouldn’t be able to delete namespaces.
First, we define a Role that grants specific permissions within a namespace.
# developer-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: dev
name: pod-deployer
rules:
- apiGroups: [""] # "" indicates the core API group
resources: ["pods", "pods/log"]
verbs: ["create", "get", "list", "watch", "delete"]
Then, we bind this Role to alice in the dev namespace using a RoleBinding.
# developer-rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: alice-dev-deployer
namespace: dev
subjects:
- kind: User
name: alice # Name is case-sensitive
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role # Can be ClusterRole for cluster-wide permissions
name: pod-deployer # Name of the Role or ClusterRole
apiGroup: rbac.authorization.k8s.io
Now, alice can kubectl apply -f my-app.yaml within the dev namespace. If she tries kubectl delete ns dev, she’ll get a "forbidden" error because her Role doesn’t include the delete verb for namespaces.
Contrast this with ABAC, which is far more complex and less commonly used in modern Kubernetes deployments for application-level permissions. ABAC grants access based on attributes of the user, the resource, and the environment. For example, you might grant access to a backend service if the user is in the engineering group AND the request is coming from a specific IP range AND the target resource is tagged with environment: staging.
Here’s a simplified conceptual example of an ABAC policy. Kubernetes ABAC policies are typically defined in a JSON file passed to the API server.
// Example ABAC Policy (Conceptual - actual implementation is server-side configuration)
{
"apiVersion": "abac.authorization.kubernetes.io/v1",
"kind": "Policy",
"spec": {
"user": "alice",
"group": ["engineering"],
"resource": "*", // All resources
"readonly": false, // Can perform write operations
"namespace": "dev",
"cluster": "my-cluster",
"reason": "Developer needs to deploy to dev"
}
}
This is a highly simplified representation. Real ABAC policies involve intricate matching of JSON fields against request attributes.
The core problem RBAC solves is managing permissions at scale without an explosion of complexity. Instead of assigning permissions to individual users for every resource, you define roles (sets of permissions) and then bind those roles to users or groups. This is a much more manageable and auditable approach. ABAC, while powerful in theory, becomes a labyrinth of rules to maintain, making it brittle and hard to debug.
The key difference lies in the granularity and the unit of control. RBAC uses Roles and ClusterRoles as the primary units of permissions, which are then assigned to Subjects (Users, Groups, ServiceAccounts) via RoleBindings and ClusterRoleBindings. ABAC, on the other hand, directly attributes permissions to the request itself, considering all its constituent parts (user, group, verb, resource, namespace, etc.) in a single, often very large, policy.
With RBAC, you can easily answer questions like: "What can the developers group do in the staging namespace?" You look at the RoleBindings for staging and the Roles they reference. With ABAC, to answer the same question, you’d have to sift through potentially thousands of individual policy rules that might grant or deny access based on a combination of attributes, some of which might be related to the developers group or the staging namespace, but others might not be.
When you create a Role in RBAC, you’re defining a template of permissions. A RoleBinding then instantiates that template for a specific Subject within a specific Namespace. If you need cluster-wide permissions, you use a ClusterRole and a ClusterRoleBinding. This separation of permission definition (Role/ClusterRole) from assignment (RoleBinding/ClusterRoleBinding) is what makes RBAC so scalable.
The most common pitfall when migrating to RBAC, or when designing RBAC policies, is forgetting to grant permissions to the kube-system namespace for essential controllers or to forget the list and watch verbs, which are crucial for many controllers and kubectl commands to function correctly. For instance, a Deployment controller needs list and watch on pods and replicasets to know their status. Without them, deployments appear to hang.
The next hurdle you’ll likely encounter is managing ServiceAccount permissions, which often requires a deeper understanding of how controllers and pods interact with the Kubernetes API.