Kubernetes RBAC: Role-Based Access Control

Role-Based Access Control (RBAC) is Kubernetes' native authorization mechanism for controlling who can perform what actions on which resources in your cluster. Without properly configured RBAC,...

Key Insights

  • RBAC in Kubernetes operates through four core objects: Roles define permissions, ClusterRoles define cluster-wide permissions, while RoleBindings and ClusterRoleBindings attach those permissions to users, groups, or ServiceAccounts.
  • The distinction between namespace-scoped (Role/RoleBinding) and cluster-scoped (ClusterRole/ClusterRoleBinding) resources is critical—you can bind a ClusterRole with a RoleBinding to grant its permissions within a single namespace.
  • Always test RBAC configurations using kubectl auth can-i before deploying to production, and never grant cluster-admin privileges when more restrictive permissions will suffice.

Introduction to RBAC in Kubernetes

Role-Based Access Control (RBAC) is Kubernetes’ native authorization mechanism for controlling who can perform what actions on which resources in your cluster. Without properly configured RBAC, you’re either running an insecure cluster where anyone can do anything, or you’re locked out of managing your own infrastructure.

RBAC implements the principle of least privilege by allowing you to grant the minimum permissions necessary for users, applications, and services to function. This matters because Kubernetes clusters often run workloads with different security requirements, house sensitive data, and serve as the foundation for your entire infrastructure.

The RBAC API provides four fundamental object types: Role and ClusterRole define sets of permissions, while RoleBinding and ClusterRoleBinding attach those permissions to subjects (users, groups, or ServiceAccounts). Understanding how these objects interact is essential for securing any production Kubernetes environment.

RBAC Core Concepts and Architecture

RBAC authorization decisions revolve around three questions: who (subject) wants to do what (verb) to which resource?

Subjects represent entities requesting access:

  • Users: Typically humans authenticated through certificates, tokens, or external identity providers
  • Groups: Collections of users, useful for organization-wide permissions
  • ServiceAccounts: Kubernetes-native identities for pods and applications running in the cluster

Resources are Kubernetes API objects like pods, services, deployments, configmaps, secrets, and namespaces themselves. You can specify individual resources or use wildcards.

Verbs define allowed actions: get, list, watch, create, update, patch, delete, and deletecollection. Non-resource endpoints like /healthz can also be controlled.

The critical architectural distinction is between namespace-scoped and cluster-scoped permissions. Roles and RoleBindings operate within a single namespace, while ClusterRoles and ClusterRoleBindings work across the entire cluster. However, you can bind a ClusterRole using a RoleBinding to grant its permissions within just one namespace—a powerful pattern for reusing permission templates.

# This illustrates the relationship between RBAC components
# Subject (ServiceAccount) -> RoleBinding -> Role -> Resources

apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-reader
  namespace: production
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-reader
  namespace: production
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: production
subjects:
- kind: ServiceAccount
  name: app-reader
  namespace: production
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

Creating Roles and ClusterRoles

A Role grants permissions within a specific namespace. Use Roles when permissions should be isolated to a particular namespace—the most common scenario for application-specific access.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: development
  name: developer-role
rules:
- apiGroups: [""]
  resources: ["pods", "pods/log", "pods/exec"]
  verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: ["apps"]
  resources: ["deployments", "replicasets"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
  resources: ["services", "configmaps"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

A ClusterRole defines permissions that apply cluster-wide or to cluster-scoped resources like nodes, persistent volumes, or namespaces themselves.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "list", "watch"]
- apiGroups: [""]
  resources: ["namespaces"]
  verbs: ["get", "list"]

Aggregated ClusterRoles combine multiple ClusterRoles using label selectors. Kubernetes uses this pattern for default roles like admin, edit, and view:

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/aggregate-to-monitoring: "true"
rules: [] # Rules are automatically filled in by the controller

Binding Roles to Subjects

RoleBindings and ClusterRoleBindings connect subjects to roles. A RoleBinding grants permissions within a specific namespace:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: developer-binding
  namespace: development
subjects:
- kind: User
  name: jane@example.com
  apiGroup: rbac.authorization.k8s.io
- kind: ServiceAccount
  name: ci-deployer
  namespace: development
roleRef:
  kind: Role
  name: developer-role
  apiGroup: rbac.authorization.k8s.io

A ClusterRoleBinding grants cluster-wide permissions:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: cluster-admin-binding
subjects:
- kind: User
  name: admin@example.com
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

Remember: you can bind a ClusterRole with a RoleBinding to limit its scope to one namespace. This is useful for reusing ClusterRole definitions across multiple namespaces with different bindings.

Practical RBAC Patterns

Here’s a complete RBAC configuration for a development team with namespace-limited access:

# Namespace for the team
apiVersion: v1
kind: Namespace
metadata:
  name: team-alpha
---
# ServiceAccount for CI/CD pipeline
apiVersion: v1
kind: ServiceAccount
metadata:
  name: ci-deployer
  namespace: team-alpha
---
# Role for developers
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: team-alpha-developer
  namespace: team-alpha
rules:
- apiGroups: ["", "apps", "batch"]
  resources: ["pods", "deployments", "replicasets", "jobs", "cronjobs", "services", "configmaps"]
  verbs: ["*"]
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "list"]  # Read-only for secrets
---
# Role for CI/CD
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: ci-deployer-role
  namespace: team-alpha
rules:
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups: [""]
  resources: ["pods", "pods/log"]
  verbs: ["get", "list", "watch"]
---
# Binding for developers
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: team-alpha-developer-binding
  namespace: team-alpha
subjects:
- kind: Group
  name: team-alpha-developers
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: team-alpha-developer
  apiGroup: rbac.authorization.k8s.io
---
# Binding for CI/CD
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: ci-deployer-binding
  namespace: team-alpha
subjects:
- kind: ServiceAccount
  name: ci-deployer
  namespace: team-alpha
roleRef:
  kind: Role
  name: ci-deployer-role
  apiGroup: rbac.authorization.k8s.io

For read-only auditor access across the cluster:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: auditor
rules:
- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["get", "list", "watch"]
- nonResourceURLs: ["*"]
  verbs: ["get"]

Testing and Troubleshooting RBAC

The kubectl auth can-i command is your primary RBAC testing tool:

# Check if you can create deployments
kubectl auth can-i create deployments --namespace=production

# Check if a specific user can delete pods
kubectl auth can-i delete pods --namespace=development --as=jane@example.com

# Check if a ServiceAccount can get secrets
kubectl auth can-i get secrets --namespace=production --as=system:serviceaccount:production:ci-deployer

# List all verbs you can perform on deployments
kubectl auth can-i --list --namespace=production

When debugging “forbidden” errors, impersonate the user to see their perspective:

# Impersonate a user
kubectl get pods --namespace=production --as=jane@example.com

# Impersonate a ServiceAccount
kubectl get secrets --as=system:serviceaccount:production:app-reader

To view existing RoleBindings and ClusterRoleBindings:

# List RoleBindings in a namespace
kubectl get rolebindings -n production

# Describe a specific binding
kubectl describe rolebinding read-pods -n production

# List all ClusterRoleBindings
kubectl get clusterrolebindings

Best Practices and Security Considerations

Never grant cluster-admin unless absolutely necessary. This role provides unrestricted access to all cluster resources. Most use cases require far less privilege.

Conduct regular RBAC audits. Review who has access to what, especially for sensitive namespaces containing production workloads or secrets. Remove unused ServiceAccounts and bindings.

Use namespaces as security boundaries. Separate teams, environments, and applications into distinct namespaces with appropriate RBAC policies.

Manage ServiceAccount tokens carefully. Kubernetes automatically mounts ServiceAccount tokens into pods. Disable this for pods that don’t need API access:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: limited-account
automountServiceAccountToken: false

Use RBAC visualization tools to understand complex permission structures:

  • rbac-lookup shows which subjects have access to resources
  • kubectl-who-can answers “who can perform this action?”
  • rakkess (Resource Access Review for Kubernetes) provides a matrix view of permissions

Implement the principle of least privilege from day one. Start with minimal permissions and expand as needed. It’s far easier to grant additional access than to revoke overly broad permissions from production systems.

Consider using external authorization systems like Open Policy Agent (OPA) for more complex policy requirements beyond what RBAC can express, such as attribute-based access control or context-aware policies.

Liked this? There's more.

Every week: one practical technique, explained simply, with code you can use immediately.