Implement RBAC for Cluster Security
Learn to secure your Kubernetes cluster with Role-Based Access Control (RBAC). This hands-on tutorial covers roles, bindings, and best practices to enforce least-privilege access.
Focus: implement rbac for cluster security
Have you ever given a Kubernetes user or application more permissions than it needed, just to get things running quickly? That cluster-admin binding may feel convenient at first, but it opens a dangerous hole in your cluster's security. This lesson shows you how to implement Role-Based Access Control (RBAC) for cluster security—replacing dangerous blanket permissions with precise, least-privilege roles that protect your workloads and data.
The problem this lesson solves
Kubernetes, by default, places few restrictions on who can do what inside the cluster. Without RBAC, every authenticated user may have full access to pods, secrets, and cluster resources. In production, this means:
- A compromised CI/CD token can destroy your entire namespace.
- Developers can accidentally delete critical system components.
- Auditors cannot trace who performed destructive actions.
RBAC solves these problems by defining exact who (user, group, service account) can do what (verb) to which resource (pod, secret, deployment, namespace). It is the standard authorization mechanism for Kubernetes clusters since v1.6.
Pro tip: RBAC is not an add-on—it is required by most managed Kubernetes services (EKS, AKS, GKE) and is enabled out of the box. Ignoring it means operating without any access control.
Core concept / mental model
Think of RBAC as an employee badge system for your cluster:
- Roles are the job descriptions: "Can read logs, cannot delete pods."
- RoleBindings are the badges pinned to individuals: "Alice gets the developer role."
- Subject is the person (or service) wearing the badge.
The magic is that you never assign permissions directly to a subject. Instead, you create a Role and bind it to a subject with a RoleBinding (or ClusterRole / ClusterRoleBinding for cluster-scoped actions).
Key definitions
| Term | Description | Example |
|---|---|---|
| Role | Namespace-scoped set of rules | get, list, watch pods in default namespace |
| ClusterRole | Cluster-wide rules (or rules that apply to namespaced resources) | get nodes, create persistentvolumes |
| RoleBinding | Binds a Role to subjects in a namespace | alice → pod-reader Role in default namespace |
| ClusterRoleBinding | Binds a ClusterRole to subjects cluster-wide | cluster-admins group → cluster-admin ClusterRole |
| Subject | User, group, or ServiceAccount | system:serviceaccount:default:my-app |
A ClusterRole can also be used with a regular RoleBinding to grant namespace-scoped permissions without creating a new Role. This is common for common patterns like
view,edit,admin.
How it works step by step
RBAC works through the Kubernetes API server, which checks each request against the current set of bindings. The request flow is:
- Authentication – Who is making the request? (TLS certificate, token, OIDC, etc.)
- Authorization – Does the subject have a RoleBinding that allows this action?
- Admission control – Extra plugins (e.g., PodSecurityPolicy) further filter requests.
The RBAC evaluation follows these rules:
- If a binding grants
get pods, the subject can read pods in that namespace. - If no binding allows the action, it is denied. Kubernetes denies by default.
- If a subject matches multiple bindings, the permissions union (OR logic) applies.
- Deny rules do not exist in RBAC—you cannot explicitly deny a user; you simply do not grant the permission.
Creating a namespace-scoped Role and RoleBinding
- Define a Role with allowed verbs and resources.
- Identify the subject (user, group, or ServiceAccount).
- Create a RoleBinding that links subject to the Role.
Cluster-level permissions
For resources that are not namespaced (e.g., nodes, persistentvolumes, storageclasses) or if you want the binding to apply to all namespaces, use ClusterRole and ClusterRoleBinding.
Hands-on walkthrough
Let's create a safe environment: a read-only developer account in a test namespace.
Step 1: Create a namespace and a ServiceAccount
kubectl create namespace dev-team
kubectl create serviceaccount read-only-dev -n dev-team
Step 2: Define a Role for reading pods and logs
Save this as pod-reader-role.yaml:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: dev-team
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "watch", "list"]
Apply it:
kubectl apply -f pod-reader-role.yaml
Step 3: Bind the role to the ServiceAccount
Save as pod-reader-binding.yaml:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-reader-binding
namespace: dev-team
subjects:
- kind: ServiceAccount
name: read-only-dev
namespace: dev-team
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
Apply it:
kubectl apply -f pod-reader-binding.yaml
Step 4: Test the permissions
# Get the token of the ServiceAccount
TOKEN=$(kubectl get secret $(kubectl get sa read-only-dev -n dev-team -o jsonpath='{.secrets[0].name}') -n dev-team -o jsonpath='{.data.token}' | base64 --decode)
# Test get pods (should succeed)
kubectl --token=$TOKEN get pods -n dev-team
# Expected output: No resources found in dev-team namespace.
# Test delete a pod (should fail)
kubectl --token=$TOKEN delete pod some-pod -n dev-team
# Expected output: Error from server (Forbidden): pods "some-pod" is forbidden: User "system:serviceaccount:dev-team:read-only-dev" cannot delete resource "pods" in API group "" in the namespace "dev-team"
The deletion attempt shows exactly how RBAC rejects unauthorized actions with a clear 403 Forbidden error.
Step 5: Create a ClusterRole to read nodes
Save as 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 and bind to your ServiceAccount:
kubectl apply -f node-reader-clusterrole.yaml
kubectl create clusterrolebinding node-reader-binding --clusterrole=node-reader --serviceaccount=dev-team:read-only-dev
Now the ServiceAccount can also list nodes.
Compare options / when to choose what
| Approach | When to use | Example |
|---|---|---|
| Role + RoleBinding | Permissions only in one namespace | Developer accessing only their team namespace |
| ClusterRole + ClusterRoleBinding | Cluster-wide permissions | Admin viewing all nodes |
| ClusterRole + RoleBinding | Reuse a common role in many namespaces but limit per namespace | view ClusterRole bound to many namespaces |
Key insight: Prefer namespace-scoped Roles for most users. Use ClusterRoles only when necessary (e.g., monitoring tools that need to read cluster-wide metrics).
Troubleshooting & edge cases
Problem 1: Your role exists but the user gets "forbidden"
Possible cause: The binding is missing, incorrect namespace, or subject name does not match.
Check:
kubectl describe rolebinding <binding-name> -n <namespace>
kubectl auth can-i --list --as=system:serviceaccount:dev-team:read-only-dev -n dev-team
Problem 2: A ServiceAccount inherits too many permissions
Possible cause: ClusterRoleBinding applies to all subjects in a group. Review all bindings:
kubectl get clusterrolebindings --all-namespaces
kubectl describe clusterrolebinding <name>
Problem 3: You need to give a third-party Helm chart minimal permissions
Most charts ship with their own RBAC templates. Override them by installing with --set rbac.create=false and create your own minimal Role/ClusterRole before installing.
Edge case: Group-level bindings
Kuberentes does not have first-class groups, but you can bind to groups from external identity providers:
subjects:
- kind: Group
name: "devops-team"
apiGroup: rbac.authorization.k8s.io
Common mistake: Forgetting that
RoleBindingcannot bind to a subject outside its namespace. UseClusterRoleBindingfor cluster-wide subjects.
What you learned & what's next
You now understand how to implement RBAC for cluster security by:
- Distinguishing between Roles, ClusterRoles, RoleBindings, and ClusterRoleBindings.
- Creating concrete Role definitions and binding them to users or ServiceAccounts.
- Testing permissions with kubectl auth can-i and live API calls.
- Troubleshooting common RBAC permission errors.
Next step: In the following lesson, you will learn how to audit RBAC configurations and build a least-privilege strategy using tools like kubectl rbac-lookup and custom validation webhooks.
Practice recap
Now apply your understanding: create a new ServiceAccount called deployer in a prod namespace, then write a Role that allows get, list, watch on deployments and create on pods. Bind it to the ServiceAccount and verify that deleting a deployment is rejected. This exercise reinforces how granular permissions prevent accidental production changes.
Common mistakes
- Binding a Role directly to a user or ServiceAccount without a RoleBinding—the binding object is required.
- Using a RoleBinding with a ClusterRole from a different namespace—RoleBindings must be in the same namespace as the Role.
- Forgetting to include the
apiGroupsfield for non-core resources (e.g.,apps/v1for deployments). - Assigning cluster-wide ClusterRoleBindings to ServiceAccounts that only need namespace-scoped access.
- Not testing permissions with
kubectl auth can-ibefore deploying into production.
Variations
- Use Kubernetes RBAC aggregration (aggregationRule) to combine multiple ClusterRoles into one.
- Leverage external authorization webhooks (e.g., OPA Gatekeeper) for fine-grained policy beyond RBAC.
- Use
kubectl create roleandkubectl create rolebindingshorthand commands to avoid YAML.
Real-world use cases
- A CI/CD pipeline only needs
get,list,watchon pods in a staging namespace—create a dedicated ServiceAccount with a RoleBinding. - Cluster-wide monitoring tool (e.g., Prometheus) must read pod and node metrics across all namespaces—use a ClusterRole + ClusterRoleBinding.
- A multi-tenant SaaS platform isolates each customer into a separate namespace with its own
adminRoleBinding granting full control only within that namespace.
Key takeaways
- RBAC is Kubernetes' primary authorization mechanism—always enabled by default, never disable it.
- RoleBindings apply to a specific namespace; ClusterRoleBindings apply cluster-wide.
- Verbs (
get,list,create,delete,watch) are the actions a role permits—map them explicitly to match your security needs. - Test any RBAC change with
kubectl auth can-ibefore depending on it in production. - Use
ServiceAccounttokens for workloads (pods), not human users; combine withkubectlfor manual testing. - Prefer namespace-scoped Roles over ClusterRoles to follow the principle of least privilege.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.