RoleBinding and ClusterRoleBinding — granting the role
What you'll learn
- Write a RoleBinding and a ClusterRoleBinding correctly
- Distinguish the subject kinds (User, Group, ServiceAccount) and their scope
- Identify the production patterns for binding roles to workloads, CI/CD, and humans
- Recognise the failure modes of over-broad bindings
Prerequisites
Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16
A Role grants permissions; a RoleBinding grants the Role to subjects. A Role without a binding is unused; a RoleBinding without a minimum-surface Role is a liability. This lesson covers the anatomy of a binding, the subject kinds, and the production patterns for binding the right Role to the right subject at the right scope.
The anatomy of a RoleBinding
A RoleBinding has three fields: subjects (who gets
the role), roleRef (what role they get), and the
implicit namespace from metadata.namespace.
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-reader
namespace: prod
subjects:
- kind: User
name: alice
apiGroup: rbac.authorization.k8s.io
- kind: Group
name: idp:dev
apiGroup: rbac.authorization.k8s.io
- kind: ServiceAccount
name: ci-runner
namespace: ci
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
The binding grants the pod-reader Role to:
User:alice— alice, authenticated via OIDC.Group:idp:dev— any user in the IdP’sdevgroup.ServiceAccount:ci-runner— theci-runnerSA in thecinamespace.
All three subjects can now read Pods in the prod
namespace. None can read in any other namespace; none
can write.
flowchart LR
A[User: alice] --> B[RoleBinding: pod-reader]
C[Group: idp:dev] --> B
D[SA: ci-runner] --> B
B --> E[Role: pod-reader]
E --> F[get, list, watch on pods in 'prod']
The subject kinds
Three kinds of subject:
- User — an authenticated identity from outside the
cluster (X.509, OIDC, webhook). The
nameis the UserInfo.username. TheapiGroupis alwaysrbac.authorization.k8s.io. - Group — a named set of users from the same
authentication source. The
nameis the UserInfo.group. For OIDC, this is the prefixed group (idp:dev). - ServiceAccount — a workload identity. The
nameis the SA name, thenamespaceis required.
# Bind to all SAs in a namespace (anti-pattern, but explicit)
subjects:
- kind: Group
name: system:serviceaccounts:ci
apiGroup: rbac.authorization.k8s.io
# Every SA in the 'ci' namespace gets the role
The system:serviceaccounts:<namespace> and
system:serviceaccounts (cluster-wide) groups are
built-in. Binding to them is convenient but dangerous —
it grants the role to every SA in the namespace,
including the default SA.
ClusterRoleBinding
A ClusterRoleBinding grants a ClusterRole cluster-wide to subjects:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: monitoring-all
subjects:
- kind: ServiceAccount
name: prometheus
namespace: monitoring
roleRef:
kind: ClusterRole
name: monitoring-all
apiGroup: rbac.authorization.k8s.io
The Prometheus SA in the monitoring namespace gets
the monitoring-all ClusterRole (read pods, services,
configmaps cluster-wide) — every namespace, every Pod.
A ClusterRoleBinding cannot reference a Role; the
API server rejects this. ClusterRoleBindings always
reference ClusterRoles.
Production patterns
Three patterns recur:
- CI/CD read-only —
RoleBindingin the target namespace, bound to the CI/CD SA, with aRolethat hasget,list,watchonly.
kind: RoleBinding
metadata:
name: ci-readonly
namespace: prod
subjects:
- kind: ServiceAccount
name: ci-runner
namespace: ci
roleRef:
kind: Role
name: readonly
apiGroup: rbac.authorization.k8s.io
- Operator —
ClusterRoleBindingto aClusterRolethat has full verbs on the CRD plusget,list,watchon the underlying resources (Deployments, Services).
kind: ClusterRoleBinding
metadata:
name: myapp-operator
subjects:
- kind: ServiceAccount
name: myapp-operator
namespace: operators
roleRef:
kind: ClusterRole
name: myapp-operator
apiGroup: rbac.authorization.k8s.io
- Human admin via OIDC —
ClusterRoleBindingto aClusterRolelikeadmin(notcluster-admin), with the subject as the IdP’s prefixed admin group.
kind: ClusterRoleBinding
metadata:
name: prod-admins
subjects:
- kind: Group
name: idp:prod-admins
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: admin
apiGroup: rbac.authorization.k8s.io
Binding to the wrong subjects
Three common failure modes:
Group: system:authenticated— every authenticated user gets the role. A developer with OIDC access who should only read indevaccidentally gets write inprod.Group: system:serviceaccounts:prod— every SA inprodgets the role, including thedefaultSA. A compromised workload inprodhas the role without explicit binding.Group: system:masters— every user in thesystem:mastersgroup gets the role. This is the cluster-admin group; the binding is redundant with the built-in cluster-admin binding.
Verifying bindings
# What can a specific SA do?
kubectl auth can-i --list --as=system:serviceaccount:prod:api
# What bindings exist for a specific user?
kubectl get rolebindings,clusterrolebindings -A -o json | \
jq '.items[] | select(.subjects[]?.name == "alice")'
# What role does this binding actually grant?
kubectl get rolebinding pod-reader -n prod -o yaml
Production failure modes
- Binding to
system:authenticated— every authenticated user gets the role. A developer with legitimatedevaccess hasprodaccess. - Binding to
system:serviceaccounts:<ns>— every SA in the namespace gets the role, including compromised workloads. - Binding to
system:masters— the role is alwayscluster-admin. The binding is a no-op that hides the actual cluster-admin from a casual audit. - Binding to
Group: *— every group gets the role. The wildcard is rarely intentional. - No binding to revoke. A fired employee remains in the IdP group, the IdP group remains in the binding, the employee has access. The fix is to remove the employee from the IdP group at HR termination.
Cross-course references
- The Observability course covers the audit log that records every RBAC decision.
- The OPNsense course covers the network-level access controls that complement RBAC.
Quiz
Knowledge check · 4 questions
Q1. What is the risk of binding a Role to `Group: system:serviceaccounts:prod`?
Q2. A RoleBinding can reference a ClusterRole, but the granted permissions are limited to the RoleBinding's namespace.
Q3. Your team added a RoleBinding `cluster-info-reader` to the `kube-public` namespace with subject `Group: system:authenticated`, granting read on `configmaps` with name `cluster-info`. The intent was to allow OIDC users to read the cluster-info ConfigMap. The actual effect is wider than intended. Why, and how do you fix it?
The binding is correct in shape but the subject `system:authenticated` includes every user authenticated against the cluster, not just those who should read cluster-info. A developer with read-only access in `dev` can now read the `cluster-info` ConfigMap in `kube-public`, which contains the API server URL and CA. The intent was probably fine, but the audit log shows the access is more visible than expected.
Q4. Name three production RoleBinding patterns and the subject kind each one uses.
Passing score: 75%. Answers are checked in this browser.
Production discipline
A defensible RBAC implementation binds the smallest
Role to the most specific subject at the smallest
scope. The subject is usually a specific
ServiceAccount (workloads) or a specific IdP group
(humans) — never system:authenticated,
system:serviceaccounts:<ns>, or *. The binding’s
scope matches the role’s scope: namespace-scoped Roles
use RoleBindings in the same namespace; ClusterRoles
that should apply cluster-wide use ClusterRoleBindings,
and ClusterRoles that should apply in one namespace use
RoleBindings. A cluster whose bindings are
indiscriminate has an RBAC programme that is not
defensible; the audit log will surface the over-broad
bindings.