RBAC
TL;DR
- Role (namespaced) and ClusterRole (cluster-wide) define what is allowed; RoleBinding and ClusterRoleBinding define who
- ClusterRole bound via RoleBinding is scoped to that namespace only; binding type determines scope, not role type
apiGroups: [""]is the core API group (pods, services, secrets, configmaps); other groups must be named explicitly- Built-in roles:
cluster-admin(full access),admin(namespace access),edit(read/write),view(read-only, excludes Secrets) viewdeliberately excludes Secrets for security (sensitive data requires explicit grant)- Wildcards (
verbs: ["*"], resources: ["*"]) are dangerous; they grant access to future resource types, including CRDs
Core Concepts
The Four RBAC Objects
RBAC consists of four related objects: two define permissions, two apply those permissions to subjects.
Roles (Namespaced) — Define a set of permissions (rules) within a single namespace. Each rule specifies API groups, resources, and verbs (actions).
ClusterRoles (Cluster-wide) — Define a set of permissions across the entire cluster or for cluster-scoped resources (nodes, persistent volumes, namespaces). A ClusterRole is itself a cluster-scoped resource.
RoleBindings (Namespaced) — Grant a Role (or ClusterRole) to one or more subjects within a specific namespace. Critical nuance: a ClusterRole bound via a RoleBinding only applies within that one namespace.
ClusterRoleBindings (Cluster-wide) — Grant a ClusterRole to one or more subjects across the entire cluster.
Binding Scope, Not Role Scope
A critical and frequently tested distinction: the binding type determines scope, not the role type. A ClusterRole bound via a RoleBinding is restricted to that namespace. Only ClusterRoleBinding applies a ClusterRole’s permissions across all namespaces.
This design allows reusing generic ClusterRoles (like built-in view, edit, admin) across many namespaces without duplicating Role definitions.
Rule Structure
A Rule defines what a role allows:
rules:
- apiGroups: [""] # Core API group (pods, services, etc.)
resources: ["pods"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"] # Apps API group (deployments, statefulsets, etc.)
resources: ["deployments"]
verbs: ["get", "list", "create"]
apiGroups: [""]— Core API group; pods, services, configmaps, secrets, etc.- Named groups —
apps(deployments),batch(jobs),storage.k8s.io(storageclass), custom CRD groups, etc. resources— API resources (pods, deployments, secrets, etc.)verbs— HTTP-style actions (get, list, watch, create, update, delete, patch, exec, etc.)
Subject Types in RoleBindings
RoleBindings grant roles to subjects of three kinds:
Users — Kubernetes usernames (from certificates, OIDC, etc.). Represented as kind: User, name: jane-dev.
Groups — Groups of users (from certificate O= fields, OIDC claims, etc.). Represented as kind: Group, name: platform-team.
ServiceAccounts — Kubernetes service account objects. Represented as kind: ServiceAccount, name: deploy-bot, namespace: payments.
Built-in ClusterRoles
Kubernetes provides standard ClusterRoles to avoid reimplementation:
| ClusterRole | Purpose |
|---|---|
| cluster-admin | Full unrestricted access; can manage all objects including RBAC itself |
| admin | Full access within a namespace; cannot modify ResourceQuota or RBAC objects |
| edit | Read/write on most objects within a namespace; cannot view/edit RBAC or ResourceQuota |
| view | Read-only on most objects; intentionally excludes Secrets to prevent blanket credential exposure |
Configuration and Operations Reference
Creating Roles Imperatively
# Namespace-scoped Role
kubectl create role pod-reader \
--verb=get,list,watch \
--resource=pods \
-n payments
# ClusterRole
kubectl create clusterrole node-reader \
--verb=get,list \
--resource=nodes
Creating Bindings Imperatively
# Bind a Role to a user in a namespace
kubectl create rolebinding jane-pod-reader \
--role=pod-reader \
--user=jane-dev \
-n payments
# Bind a ClusterRole to a user cluster-wide
kubectl create clusterrolebinding jane-view \
--clusterrole=view \
--user=jane-dev
# Bind a ClusterRole to a ServiceAccount in a namespace (scoped)
kubectl create rolebinding deploy-bot-reader \
--clusterrole=view \
--serviceaccount=payments:deploy-bot \
-n payments
Inspecting RBAC
# List all Roles in a namespace
kubectl get roles -n payments
# Describe what a Role permits
kubectl describe role pod-reader -n payments
# List all RoleBindings and ClusterRoleBindings
kubectl get rolebindings,clusterrolebindings -A
# Find which RoleBindings grant access to a specific ServiceAccount
kubectl get rolebindings,clusterrolebindings -A -o json | \
jq '.items[] | select(.subjects[]?.name=="deploy-bot")'
# Test effective permissions for a user
kubectl auth can-i list pods --as=jane-dev -n payments
kubectl auth can-i delete nodes --as=jane-dev
Example: Complete RBAC Setup
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: payments-dev
namespace: payments
rules:
- apiGroups: [""]
resources: ["pods", "services", "configmaps"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: jane-payments-dev
namespace: payments
subjects:
- kind: User
name: jane-dev
apiGroup: rbac.authorization.k8s.io
- kind: Group
name: payments-team
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: payments-dev
apiGroup: rbac.authorization.k8s.io
Common Pitfalls
Pitfall — Binding Type Confusion Using a ClusterRole binding and expecting it to apply across all namespaces.
- Why: ClusterRole bound via RoleBinding is scoped to that namespace only. Only ClusterRoleBinding applies cluster-wide.
- Fix: Use ClusterRoleBinding for cluster-wide scope, or use RoleBinding if namespace scoping is intended.
Pitfall — Wildcard Permissions in Custom Roles
Using verbs: ["*"], resources: ["*"] to “just get it working.”
- Why: Wildcards grant access to any resource type added in the future, including new CRDs and unintended resource types.
- Fix: Always enumerate specific verbs and resources. Treat wildcards as a security finding requiring justification.
Pitfall — Assuming view Includes Secrets
Assigning users the view ClusterRole expecting blanket read access.
- Why: The
viewClusterRole intentionally excludes Secrets to prevent blanket credential exposure. - Fix: If a user needs to read Secrets, explicitly grant permission via a custom Role or ClusterRole, never assume
viewincludes them.
Pitfall — Multiple Subjects Not Combined in a Single Binding Creating separate RoleBindings for each user instead of combining subjects.
- Why: Not a violation, but less efficient and harder to maintain; a single RoleBinding can have multiple subjects.
- Fix: Combine related subjects (users, groups, serviceaccounts) in a single RoleBinding.
Interview Questions
Q — Explain the semantic difference between Role/ClusterRole and RoleBinding/ClusterRoleBinding.
Q — A ClusterRole is bound to a user via a RoleBinding in namespace “payments”. What is the effective scope? Why?
Q — Why does Kubernetes exclude Secrets from the view built-in ClusterRole?
Q — Design an RBAC policy for a multi-tenant cluster where team-A can only access their namespace.
Q — What is the difference between apiGroups: [""] and apiGroups: ["apps"]?
Q — How would you grant a ServiceAccount permission to create, update, and delete deployments in a specific namespace?
Q — What is the danger of using verbs: ["*"], resources: ["*"] in a custom Role?
Q — How would you check whether a user has permission to read secrets in a namespace without changing your own credentials?