coderain guide

Kubernetes RBAC: Securing Cluster Access with Precision

In the world of Kubernetes, where clusters manage hundreds of microservices, user accounts, and automated processes, securing access is not just a best practice—it’s a necessity. Without granular control over who can do what, clusters become vulnerable to accidental misconfigurations, data breaches, or even full-scale attacks. Enter **Role-Based Access Control (RBAC)**, Kubernetes’ built-in framework for defining and enforcing access policies with precision. RBAC transforms the chaos of "who can access what" into a structured system, where permissions are tied to roles, and roles are assigned to users or service accounts. Whether you’re a cluster administrator securing sensitive workloads, a developer needing limited access to a namespace, or a DevOps engineer automating deployments, RBAC ensures that every action is authorized—and nothing more. In this blog, we’ll demystify Kubernetes RBAC, break down its core components, walk through practical implementation examples, and share best practices to lock down your cluster like a pro.

Table of Contents

  1. What is Kubernetes RBAC?
  2. Core Components of RBAC
  3. How RBAC Works: The Evaluation Process
  4. Setting Up RBAC: Practical Examples
  5. Advanced RBAC Concepts
  6. Best Practices for RBAC
  7. Troubleshooting RBAC Issues
  8. Conclusion
  9. 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).

RoleClusterRole
Namespace-scopedCluster-scoped
Applies only to its namespaceApplies 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.

RoleBindingClusterRoleBinding
Namespace-scopedCluster-scoped
Binds a Role (or ClusterRole) to subjects within a specific namespaceBinds 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:

  1. Authentication: Verifies the subject’s identity (e.g., via TLS certificates, tokens).
  2. 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/v1 for Deployments, core/v1 for Pods).
      • Resource Names (optional): Specific resource names (e.g., only pod/my-app).
      • Non-Resource URLs (optional): Non-resource endpoints (e.g., /healthz).
  3. Admission Control: Applies additional checks (e.g., network policies, resource quotas).
  4. 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

  1. Follow Least Privilege: Start with minimal permissions and add only what’s needed.
  2. Use Namespaces for Isolation: Restrict roles to specific namespaces (e.g., dev, prod).
  3. Avoid cluster-admin: Reserve this role for emergency use only. Use edit or custom roles instead.
  4. Audit Regularly: Use kubectl auth can-i --list --as=user to review permissions. Tools like kube-bench or Prisma Cloud automate checks.
  5. Rotate ServiceAccount Tokens: Use short-lived tokens (Kubernetes 1.24+ auto-rotates SA tokens).
  6. Limit Resource Names: Restrict actions to specific resources (e.g., resourceNames: ["my-app"]).
  7. Avoid Wildcards: Never use verbs: ["*"] or resources: ["*"] 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 dev linking alice to a Role with pods and list permissions.
    • Verify the Role’s apiGroups (e.g., pods are in the core group "").
  • 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., update on clusterrolebindings).
  • Service account can’t access resources:

    • Verify the pod’s serviceAccountName matches the RoleBinding’s subject.
    • Check if the RoleBinding is in the pod’s namespace.

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.

References