Table of Contents
- What is Kubernetes RBAC?
- Core Components of RBAC
- How RBAC Works: The Evaluation Process
- Setting Up RBAC: Practical Examples
- Advanced RBAC Concepts
- Best Practices for RBAC
- Troubleshooting RBAC Issues
- Conclusion
- References
What is Kubernetes RBAC?
RBAC (Role-Based Access Control) is Kubernetes’ authorization system that determines whether a user or service account is allowed to perform an action on a resource. Unlike its predecessor, ABAC (Attribute-Based Access Control), RBAC is declarative, API-driven, and easier to manage at scale.
Key Principles of RBAC:
- Least Privilege: Users/service accounts get only the permissions they need to perform their tasks.
- Role-Based: Permissions are grouped into “roles,” which are then assigned to “subjects” (users, groups, service accounts).
- Scopeable: Roles can be limited to a single namespace (Role) or apply cluster-wide (ClusterRole).
Core Components of RBAC
To implement RBAC, you’ll work with four primary API objects (all in the rbac.authorization.k8s.io/v1 API group) and “subjects” (the entities being granted access).
Subjects
Subjects are the entities (users, groups, or service accounts) to which you grant permissions.
- Users: External entities (e.g., developers, admins) managed outside Kubernetes (e.g., LDAP, OAuth2). Kubernetes does not store user data natively.
- Groups: Collections of users (e.g.,
dev-team,security-admins). - ServiceAccounts (SAs): Kubernetes-managed accounts for pods to interact with the API server (e.g., a deployment needing to list pods).
Roles & ClusterRoles
Roles and ClusterRoles define permissions (verbs like get, list, create) for resources (e.g., pods, deployments).
| Role | ClusterRole |
|---|---|
| Namespace-scoped | Cluster-scoped |
| Applies only to its namespace | Applies to all namespaces (or cluster resources like nodes) |
| Defines permissions for namespaced resources (pods, secrets) | Defines permissions for namespaced resources (across namespaces) or cluster-scoped resources (nodes, namespaces) |
RoleBindings & ClusterRoleBindings
Bindings associate roles (or ClusterRoles) with subjects, granting the role’s permissions to the subject.
| RoleBinding | ClusterRoleBinding |
|---|---|
| Namespace-scoped | Cluster-scoped |
| Binds a Role (or ClusterRole) to subjects within a specific namespace | Binds a ClusterRole to subjects cluster-wide |
How RBAC Works: The Evaluation Process
When a subject (e.g., a user) makes a request to the Kubernetes API server (e.g., kubectl get pods), the API server follows this flow:
- Authentication: Verifies the subject’s identity (e.g., via TLS certificates, tokens).
- Authorization (RBAC): Checks if the subject is allowed to perform the action.
- The API server inspects all RoleBindings/ClusterRoleBindings associated with the subject.
- For each binding, it checks if the linked Role/ClusterRole grants the required permissions:
- Verb: The action (e.g.,
get,create,delete). - Resource: The target resource (e.g.,
pods,deployments). - API Group: The resource’s API group (e.g.,
apps/v1for Deployments,core/v1for Pods). - Resource Names (optional): Specific resource names (e.g., only
pod/my-app). - Non-Resource URLs (optional): Non-resource endpoints (e.g.,
/healthz).
- Verb: The action (e.g.,
- Admission Control: Applies additional checks (e.g., network policies, resource quotas).
- Fulfill Request: If authorized, the API server processes the request.
Setting Up RBAC: Practical Examples
Let’s walk through hands-on examples to solidify your understanding.
Example 1: Namespace-Scoped Role & Binding
Goal: Allow user alice to get, list, and watch pods in the dev namespace.
Step 1: Create a Namespace
kubectl create namespace dev
Step 2: Define a Role
Create pod-reader-role.yaml:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: dev
name: pod-reader
rules:
- apiGroups: [""] # "" refers to the core API group
resources: ["pods"]
verbs: ["get", "list", "watch"]
Apply it:
kubectl apply -f pod-reader-role.yaml
Step 3: Bind the Role to User alice
Create pod-reader-binding.yaml:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods-binding
namespace: dev
subjects:
- kind: User
name: alice
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
Apply it:
kubectl apply -f pod-reader-binding.yaml
Verify Permissions
Test as alice (replace alice with your user):
kubectl auth can-i get pods --namespace dev --as=alice
# Output: yes
kubectl auth can-i delete pods --namespace dev --as=alice
# Output: no (since we didn’t grant delete)
Example 2: Cluster-Scoped ClusterRole & Binding
Goal: Allow group security-team to get and list nodes cluster-wide.
Step 1: Define a ClusterRole
Create node-reader-clusterrole.yaml:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: node-reader
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list"]
Apply it:
kubectl apply -f node-reader-clusterrole.yaml
Step 2: Bind the ClusterRole to Group security-team
Create node-reader-clusterbinding.yaml:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: read-nodes-binding
subjects:
- kind: Group
name: security-team
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: node-reader
apiGroup: rbac.authorization.k8s.io
Apply it:
kubectl apply -f node-reader-clusterbinding.yaml
Verify Permissions
kubectl auth can-i list nodes --as-group=security-team
# Output: yes
Example 3: ServiceAccount with RBAC
Goal: Allow a pod in the prod namespace to create and delete pods using a ServiceAccount.
Step 1: Create a ServiceAccount
kubectl create serviceaccount pod-manager -n prod
Step 2: Define a Role and RoleBinding
Create pod-manager-role.yaml:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: prod
name: pod-manager
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["create", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-manager-binding
namespace: prod
subjects:
- kind: ServiceAccount
name: pod-manager
namespace: prod
roleRef:
kind: Role
name: pod-manager
apiGroup: rbac.authorization.k8s.io
Apply it:
kubectl apply -f pod-manager-role.yaml -n prod
Step 3: Use the ServiceAccount in a Pod
Create pod-using-sa.yaml:
apiVersion: v1
kind: Pod
metadata:
name: sa-demo
namespace: prod
spec:
serviceAccountName: pod-manager # Use the ServiceAccount
containers:
- name: alpine
image: alpine:3.14
command: ["sleep", "infinity"]
Apply it:
kubectl apply -f pod-using-sa.yaml -n prod
The pod sa-demo now has permissions to create/delete pods in prod.
Example 4: Restricting Access with Resource Names
Goal: Allow user bob to delete only the pod named critical-app in the prod namespace.
Create restricted-pod-deleter.yaml:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: prod
name: critical-pod-deleter
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["delete"]
resourceNames: ["critical-app"] # Restrict to this pod only
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: delete-critical-pod-binding
namespace: prod
subjects:
- kind: User
name: bob
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: critical-pod-deleter
apiGroup: rbac.authorization.k8s.io
Apply and test:
kubectl apply -f restricted-pod-deleter.yaml -n prod
# Bob can delete critical-app...
kubectl auth can-i delete pod/critical-app --namespace prod --as=bob
# Output: yes
# ...but not other pods
kubectl auth can-i delete pod/other-app --namespace prod --as=bob
# Output: no
Advanced RBAC Concepts
Aggregated ClusterRoles
Aggregated ClusterRoles combine permissions from multiple “child” ClusterRoles using labels. Useful for operators or platform teams managing shared permissions.
Example: Create an aggregated ClusterRole for “monitoring” that includes metrics-related permissions:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: monitoring-aggregated
labels:
rbac.example.com/aggregate-to-monitoring: "true"
aggregationRule:
clusterRoleSelectors:
- matchLabels:
rbac.example.com/monitoring-role: "true"
rules: [] # Rules are inherited from child roles
Child roles with label rbac.example.com/monitoring-role: "true" will automatically be aggregated into monitoring-aggregated.
Role References: Reusing ClusterRoles in Namespaces
You can bind a ClusterRole to a subject within a namespace using a RoleBinding. This reuses cluster-wide role definitions but scopes them to a single namespace.
Example: Bind the built-in view ClusterRole (grants read-only access to most resources) to user charlie in the staging namespace:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: charlie-view-staging
namespace: staging
subjects:
- kind: User
name: charlie
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole # Reuse the cluster-scoped "view" role
name: view
apiGroup: rbac.authorization.k8s.io
ABAC vs. RBAC: Why RBAC Wins
- ABAC: Uses policies based on attributes (e.g., user, resource, environment variables) stored in files. Hard to manage at scale and not API-driven.
- RBAC: Declarative API objects (Roles, Bindings) that can be version-controlled, audited, and updated dynamically. Preferred for most Kubernetes environments.
Impersonation: Testing RBAC Policies
Use kubectl --as or --as-group to test permissions without switching users:
# Test if alice can create deployments in dev
kubectl auth can-i create deployments --namespace dev --as=alice
# Test if the dev-team group can delete namespaces
kubectl auth can-i delete namespaces --as-group=dev-team
Best Practices for RBAC
- Follow Least Privilege: Start with minimal permissions and add only what’s needed.
- Use Namespaces for Isolation: Restrict roles to specific namespaces (e.g.,
dev,prod). - Avoid
cluster-admin: Reserve this role for emergency use only. Useeditor custom roles instead. - Audit Regularly: Use
kubectl auth can-i --list --as=userto review permissions. Tools like kube-bench or Prisma Cloud automate checks. - Rotate ServiceAccount Tokens: Use short-lived tokens (Kubernetes 1.24+ auto-rotates SA tokens).
- Limit Resource Names: Restrict actions to specific resources (e.g.,
resourceNames: ["my-app"]). - Avoid Wildcards: Never use
verbs: ["*"]orresources: ["*"]unless absolutely necessary.
Troubleshooting RBAC Issues
Common errors and fixes:
-
forbidden: User "alice" cannot list resource "pods" in API group "" in the namespace "dev"- Check if a RoleBinding exists in
devlinkingaliceto a Role withpodsandlistpermissions. - Verify the Role’s
apiGroups(e.g.,podsare in the core group"").
- Check if a RoleBinding exists in
-
clusterrolebindings.rbac.authorization.k8s.io "my-binding" is forbidden: cannot set blockOwnerDeletion if an ownerReference refers to a resource you can't set finalizers on- Ensure the subject has permissions to modify the binding (e.g.,
updateonclusterrolebindings).
- Ensure the subject has permissions to modify the binding (e.g.,
-
Service account can’t access resources:
- Verify the pod’s
serviceAccountNamematches the RoleBinding’s subject. - Check if the RoleBinding is in the pod’s namespace.
- Verify the pod’s
Conclusion
Kubernetes RBAC is the cornerstone of cluster security, enabling precise control over who can do what. By mastering Roles, ClusterRoles, and Bindings, you can enforce least privilege, isolate workloads, and protect against unauthorized access.
Start small: audit existing permissions, define custom roles for your teams, and use tools like kubectl auth can-i to validate policies. With RBAC, you’ll transform your cluster from a free-for-all to a secure, well-governed environment.