Kubernetes RBAC: Roles and Bindings
Introduction¶
Kubernetes RBAC is built from four object types. Once you see how they pair up — a what and a who — the model is small and predictable.
The four objects¶
| Object | Scope | Says |
|---|---|---|
| Role | one namespace | a set of permitted (verbs × resources) |
| ClusterRole | cluster-wide | same, but also usable in any namespace or for cluster-scoped resources |
| RoleBinding | one namespace | grants a Role (or ClusterRole) to subjects in that namespace |
| ClusterRoleBinding | cluster-wide | grants a ClusterRole to subjects across all namespaces |
Rules are purely additive — there are no deny rules. If no rule grants an action, it's forbidden.
A namespace-scoped example¶
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: team-a
name: deploy-manager
rules:
- apiGroups: ["apps"]
resources: ["deployments", "replicasets"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
namespace: team-a
name: team-a-deployers
subjects:
- kind: Group
name: team-a-devs # from your OIDC/auth provider
apiGroup: rbac.authorization.k8s.io
- kind: ServiceAccount
name: ci-deployer
namespace: team-a
roleRef:
kind: Role
name: deploy-manager
apiGroup: rbac.authorization.k8s.io
Subjects¶
- User / Group — Kubernetes has no user database; these strings come from your authenticator (OIDC claims, client cert CN/O, IAM). RBAC just matches the string.
- ServiceAccount — a real cluster object, for pods. A pod's SA token is
mounted at
/var/run/secrets/kubernetes.io/serviceaccount/. Reference it assystem:serviceaccount:<ns>:<name>in a ClusterRoleBinding.
ClusterRole for a namespaced resource¶
A ClusterRole listing pods can be bound with a RoleBinding to scope it to
one namespace. This is how the built-in view / edit / admin ClusterRoles
are reused per-namespace:
kind: RoleBinding
metadata: { namespace: team-b, name: readonly }
subjects: [{ kind: Group, name: auditors, apiGroup: rbac.authorization.k8s.io }]
roleRef: { kind: ClusterRole, name: view, apiGroup: rbac.authorization.k8s.io }
Aggregated ClusterRoles¶
kind: ClusterRole
metadata:
name: monitoring
labels:
rbac.example.com/aggregate-to-view: "true" # rolls up into the built-in "view"
rules:
- apiGroups: ["monitoring.coreos.com"]
resources: ["servicemonitors"]
verbs: ["get", "list", "watch"]
view/edit/admin have aggregationRules; label a ClusterRole to extend
them without editing the originals.
Debugging "forbidden"¶
# Can I do it?
kubectl auth can-i create deployments -n team-a
kubectl auth can-i '*' '*' --all-namespaces # am I cluster-admin?
# Can someone else? (needs impersonation rights)
kubectl auth can-i list secrets -n team-a --as=jane
kubectl auth can-i get pods -n team-a \
--as=system:serviceaccount:team-a:ci-deployer
# What can this SA do?
kubectl auth can-i --list --as=system:serviceaccount:team-a:ci-deployer -n team-a
# Who is bound to what
kubectl get rolebindings,clusterrolebindings -A -o wide | grep team-a-devs
Verification and troubleshooting¶
Error from server (Forbidden): ... cannot list resource "pods" in API group ""— read it literally: verblist, resourcepods, core group. Add that tuple to a Role and bind it.kubectl auth can-i --listshows the current grants.- RoleBinding created but still forbidden — subject string mismatch
(group/user name from the token differs from what you wrote — check
kubectl get --raw /apiwith-v=8or your OIDC claims), or wrong namespace, or you bound aRolethat doesn't have the rule. - ServiceAccount in a pod gets 403 — the pod uses
defaultSA (no rules). SetserviceAccountName:and bind that SA. - ClusterRoleBinding used where a RoleBinding was meant — grants cluster-wide, a common over-permission. Use a RoleBinding to a ClusterRole to scope it.
patchworks butupdatedoesn't (or vice versa) — they're separate verbs.apply(server-side) needspatch+create(+get). kubectl client-side apply needsget+patch+create.- Can create pods but not exec —
pods/execis a subresource, its own rule (resources: ["pods/exec"], verbs: ["create"]).
Related tools and reading¶
- On-site: JWT decoder (inspect SA tokens), YAML validator.
- Related posts: ConfigMaps and Secrets done right, kubectl commands you use daily.
Stuck on something this site can't fix?Reach out to Prabath directly on LinkedIn.More in Docker & Kubernetes
StatefulSets Explained
StatefulSets give pods sticky names, sticky storage, and ordered operations — what databases and clustered apps need. Here's how each guarantee works.
October 24, 2026Persistent Volumes and Claims, Explained
PVC is a request, PV is the fulfilled storage, StorageClass is the factory. Most 'Pending PVC' problems are an access-mode or provisioner mismatch.
October 24, 2026Kubernetes Jobs and CronJobs
A Job runs pods until they succeed; a CronJob creates Jobs on a schedule. Here's parallelism, retry limits, the missed-schedule trap, and history cleanup.
October 24, 2026