RBAC Best Practices
A comprehensive guide to Kubernetes RBAC best practices covering roles, clusterroles, bindings, service accounts, least privilege, and practical implementation strategies for securing cluster access.
Role-Based Access Control (RBAC) is the primary authorization mechanism in Kubernetes. It controls who can access the cluster API and what they can do with resources. RBAC is essential for security, compliance, and operational governance.
RBAC consists of four key components:
- Roles/ClusterRoles: Define what permissions are granted
- Subjects: Users, groups, or service accounts
- Bindings: Connect subjects to roles
- Service Accounts: Special identities for pods
Role
ClusterRole
RoleBinding
ClusterRoleBinding
ServiceAccount
Subject
# Basic Role - Read-only pods in namespace
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: default
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
# Role with multiple resources
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: deployment-manager
namespace: default
rules:
- apiGroups: ["apps"]
resources: ["deployments", "statefulsets", "daemonsets"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
# Role with subresources
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-log-reader
namespace: default
rules:
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get", "list"]
# ClusterRole - Read-only cluster-wide
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cluster-readonly
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["get", "list", "watch"]
- nonResourceURLs: ["/healthz", "/readyz"]
verbs: ["get"]
# ClusterRole - Admin (full permissions)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cluster-admin
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
- nonResourceURLs: ["*"]
verbs: ["*"]
# Role for managing secrets (limited)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: secret-manager
namespace: production
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "create", "update", "delete"]
resourceNames: ["db-credentials", "tls-cert"] # Limit to specific secrets
- Use Roles (namespace-scoped) over ClusterRoles when possible
- Be specific with resources and verbs
- Use
resourceNamesto limit access to specific instances - Create reusable roles for common patterns (read-only, write, admin)
- Avoid using
"*"for apiGroups, resources, or verbs unless absolutely necessary
Bindings attach roles to subjects (users, groups, or service accounts). RoleBindings are namespace-scoped, while ClusterRoleBindings are cluster-scoped.
# RoleBinding - Bind Role to User
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: developer-access
namespace: default
subjects:
- kind: User
name: developer@example.com
apiGroup: rbac.authorization.k8s.io
- kind: User
name: jane@example.com
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
# RoleBinding - Bind Role to Group
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: team-access
namespace: default
subjects:
- kind: Group
name: development-team
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: deployment-manager
apiGroup: rbac.authorization.k8s.io
# RoleBinding - Bind ClusterRole within Namespace
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: admin-within-namespace
namespace: production
subjects:
- kind: User
name: ops-user
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: cluster-admin # ClusterRole bound to specific namespace
apiGroup: rbac.authorization.k8s.io
# ClusterRoleBinding - Bind ClusterRole Cluster-wide
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cluster-admin-binding
subjects:
- kind: User
name: cluster-admin@example.com
apiGroup: rbac.authorization.k8s.io
- kind: Group
name: platform-engineering
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
# RoleBinding - Bind to ServiceAccount
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: app-reader
namespace: default
subjects:
- kind: ServiceAccount
name: my-app-sa
namespace: default
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
- Use groups instead of individual users when possible (manage permissions at group level)
- Prefer RoleBindings over ClusterRoleBindings for namespace-specific access
- Create separate bindings for different teams or roles
- Use namespaces to isolate permissions
- Regularly audit bindings to remove unnecessary permissions
ServiceAccounts are Kubernetes identities for pods. They allow pods to authenticate to the Kubernetes API and external services. Each namespace has a default ServiceAccount, but you should create specific ServiceAccounts for different workloads.
# Create a ServiceAccount
kubectl create serviceaccount my-app-sa -n default
# ServiceAccount YAML
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app-sa
namespace: default
labels:
app: my-app
secrets:
- name: my-app-sa-token-xxxxx # Mounted token secret
# Use ServiceAccount in Pod
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
serviceAccountName: my-app-sa # Use specific SA instead of default
containers:
- name: app
image: myapp:latest
# Automount ServiceAccount token (disable if not needed)
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app-sa
automountServiceAccountToken: false
# Pod with no ServiceAccount token
apiVersion: v1
kind: Pod
metadata:
name: no-sa-pod
spec:
automountServiceAccountToken: false # Don't mount token
containers:
- name: app
image: myapp:latest
# Grant ServiceAccount permissions
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: app-sa-binding
namespace: default
subjects:
- kind: ServiceAccount
name: my-app-sa
namespace: default
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
# Get ServiceAccount token (for external authentication)
kubectl get secret my-app-sa-token-xxxxx -o jsonpath="{.data.token}" | base64 -d
- Create specific ServiceAccounts for different applications
- Bind ServiceAccounts to roles with least privilege
- Disable automounting of tokens (
automountServiceAccountToken: false) if not needed - Use separate ServiceAccounts for different environments (dev, staging, prod)
- Rotate ServiceAccount tokens regularly
- Use AWS IAM Roles for Service Accounts (IRSA) or GCP Workload Identity for cloud integration
Implementing least privilege is the most critical RBAC best practice. Here are common patterns for different scenarios:
Developer Access
Operations Access
Application Access
Admin Access
# Developer Role (read-only + logs)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: developer
namespace: dev
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch"]
# Operations Role (manage workloads)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: operator
namespace: production
rules:
- apiGroups: ["*"]
resources: ["deployments", "statefulsets", "daemonsets", "services", "configmaps"]
verbs: ["*"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list"] # Read-only for secrets
# Application ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-sa
namespace: default
automountServiceAccountToken: false # Disable API access
# If API access needed, grant minimal
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: app-sa-binding
namespace: default
subjects:
- kind: ServiceAccount
name: app-sa
namespace: default
roleRef:
kind: Role
name: app-reader
apiGroup: rbac.authorization.k8s.io
Regular RBAC audits are essential for maintaining security. Here are commands and tools for auditing and troubleshooting RBAC.
# Check permissions for current user
kubectl auth can-i get pods
kubectl auth can-i create deployments --namespace production
kubectl auth can-i delete secrets --namespace default
# Check permissions for specific user
kubectl auth can-i get pods --as=developer@example.com
kubectl auth can-i create deployments --as=developer@example.com --namespace dev
# Check permissions for ServiceAccount
kubectl auth can-i get pods --as=system:serviceaccount:default:my-app-sa
# View RBAC resources
kubectl get roles --all-namespaces
kubectl get clusterroles
kubectl get rolebindings --all-namespaces
kubectl get clusterrolebindings
# Describe specific role
kubectl describe role developer -n dev
kubectl describe clusterrole cluster-admin
# Check who has access to a specific resource
kubectl get rolebindings -n default -o yaml | grep -A 5 subjects
# Using kubectl-rbac-tool
# Install: kubectl krew install rbac-tool
kubectl rbac-tool who-can get pods -n default
kubectl rbac-tool audit
# Using rbac-view
kubectl rbac-tool view --output dot | dot -Tpng > rbac.png
# Check aggregated ClusterRoles
kubectl get clusterroles -o yaml | grep -A 5 aggregationRule
# Validate RBAC with OPA/Gatekeeper
# Create constraint to enforce RBAC best practices
| Component | Scope | Purpose | Example Use |
|---|---|---|---|
| Role | Namespace | Define permissions within a namespace | Read pods in 'default' |
| ClusterRole | Cluster | Define permissions cluster-wide | Manage nodes, persistent volumes |
| RoleBinding | Namespace | Grant Role permissions to subjects in a namespace | Give developer read access in 'dev' |
| ClusterRoleBinding | Cluster | Grant ClusterRole permissions to subjects cluster-wide | Give admin full cluster access |
| ServiceAccount | Namespace | Identity for pods | App authentication to API |
| User | External | Human identity | Developer, operator login |
| Group | External | Manage multiple users | Development team permissions |
subjects: - kind: User name: user@example.com.kubectl auth can-i. For example: kubectl auth can-i get pods --as=developer@example.com. This checks if the user has permission to get pods.aggregationRule field in a ClusterRole. It allows you to combine multiple ClusterRoles into a single role. This is useful for creating composite roles like 'view' and 'edit' that aggregate other roles.kubectl commands to list roles and bindings. Use tools like kubectl-rbac-tool or rbac-view for visualization. Regular audits should be scheduled to review and remove unnecessary permissions.RBAC is the foundation of Kubernetes security. Implement least privilege, audit regularly, and use ServiceAccounts for pod identities to maintain a secure cluster environment.