Skip to main content
RunBook Academy

KubernetesLVIII · RBACRBAC

RoleBinding and ClusterRoleBinding — granting the role

Advanced⏱ ~15 minkubectl

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

Not yet marked complete on this device.

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’s dev group.
  • ServiceAccount:ci-runner — the ci-runner SA in the ci namespace.

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 name is the UserInfo.username. The apiGroup is always rbac.authorization.k8s.io.
  • Group — a named set of users from the same authentication source. The name is the UserInfo.group. For OIDC, this is the prefixed group (idp:dev).
  • ServiceAccount — a workload identity. The name is the SA name, the namespace is 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:

  1. CI/CD read-onlyRoleBinding in the target namespace, bound to the CI/CD SA, with a Role that has get, list, watch only.
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
  1. OperatorClusterRoleBinding to a ClusterRole that has full verbs on the CRD plus get, list, watch on 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
  1. Human admin via OIDCClusterRoleBinding to a ClusterRole like admin (not cluster-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:

  1. Group: system:authenticated — every authenticated user gets the role. A developer with OIDC access who should only read in dev accidentally gets write in prod.
  2. Group: system:serviceaccounts:prod — every SA in prod gets the role, including the default SA. A compromised workload in prod has the role without explicit binding.
  3. Group: system:masters — every user in the system:masters group 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

  1. Binding to system:authenticated — every authenticated user gets the role. A developer with legitimate dev access has prod access.
  2. Binding to system:serviceaccounts:<ns> — every SA in the namespace gets the role, including compromised workloads.
  3. Binding to system:masters — the role is always cluster-admin. The binding is a no-op that hides the actual cluster-admin from a casual audit.
  4. Binding to Group: * — every group gets the role. The wildcard is rarely intentional.
  5. 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

  1. Q1. What is the risk of binding a Role to `Group: system:serviceaccounts:prod`?

  2. Q2. A RoleBinding can reference a ClusterRole, but the granted permissions are limited to the RoleBinding's namespace.

  3. 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.

  4. 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.