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-ibefore 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-lookupshows which subjects have access to resourceskubectl-who-cananswers “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.