Role and ClusterRole — the verbs the cluster allows
What you'll learn
- Write a minimal Role and ClusterRole for a real workload
- Distinguish resourceName (one object) from resources (a kind)
- Use aggregation rules to compose ClusterRoles from common building blocks
- Identify the failure modes of wildcard RBAC
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 is a named set of permissions within a namespace. A ClusterRole is the same, cluster-wide. Every production RBAC implementation starts with the smallest possible Role that allows the work, then composes larger roles out of smaller ones via aggregation. This lesson covers the shape of a Role, the verbs and resources, the aggregation pattern, and the wildcard failure modes.
The anatomy of a Role
A Role has three fields: apiGroups, resources, and
verbs. The intersection is what is allowed.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: prod
rules:
- apiGroups: [""] # the core API group
resources: ["pods"]
verbs: ["get", "watch", "list"]
- apiGroups: [""] # can also include resourceNames
resources: ["pods/log"]
verbs: ["get"]
resourceNames: ["api", "worker"] # only these pods
A user bound to this Role can get, watch, and
list Pods in the prod namespace, and get the
logs of two specific pods (api and worker). No
other resources, no other verbs, no other namespaces.
flowchart LR
A[Identity] --> B[RoleBinding]
B --> C[Role]
C --> D[Verbs on resources]
D --> E[Within namespace]
The verbs
The Kubernetes API has seven verbs that apply to almost every resource:
| Verb | What it allows |
|---|---|
get | Read a single object by name |
list | Read all objects of a kind |
watch | Subscribe to changes (used by informers) |
create | Create a new object |
update | Replace an existing object (full overwrite) |
patch | Apply a partial change |
delete | Delete an object |
deletecollection | Delete all objects of a kind |
Plus three special verbs that appear on subresources:
| Verb | What it allows |
|---|---|
bind | Bind a RoleBinding to a Role (rare) |
escalate | Create a RoleBinding that grants permissions the caller does not have |
impersonate | Act as another user (rare) |
use | Use a resource (e.g., pods/exec) |
The resources
The resources field is the API kind: pods,
services, configmaps, secrets, nodes,
persistentvolumeclaims, etc. The apiGroups field is
the API group: "" (core), apps, batch,
rbac.authorization.k8s.io, etc.
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch"]
- apiGroups: ["batch"]
resources: ["jobs", "cronjobs"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["configmaps", "secrets"]
verbs: ["get", "list", "watch"]
A role for a typical CI/CD pipeline that needs to read
deployments, jobs, configmaps, and secrets — but never
write — has exactly these rules. Adding update to any
of them expands the surface significantly.
ClusterRole
A ClusterRole is the same shape as a Role, but cluster-wide:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: pod-reader-all
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get"]
A ClusterRoleBinding to this ClusterRole grants the permissions in every namespace. A role for a monitoring workload that scrapes every Pod’s metrics is typically a ClusterRole.
Aggregation rules
A ClusterRole can aggregate permissions from other ClusterRoles via label selectors:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: monitoring-all
labels:
rbac.example.com/aggregate-to-monitoring: "true"
aggregationRule:
clusterRoleSelectors:
- matchLabels:
rbac.example.com/aggregate-to-monitoring: "true"
rules: [] # populated automatically
Any ClusterRole with the label
rbac.example.com/aggregate-to-monitoring: "true" is
included. The aggregated role’s rules are the union of
all matching ClusterRoles. Adding a new ClusterRole
with the label automatically extends the aggregated
role.
flowchart LR
A[ClusterRole: monitoring-pods] -->|label match| D[ClusterRole: monitoring-all]
B[ClusterRole: monitoring-services] -->|label match| D
C[ClusterRole: monitoring-configmaps] -->|label match| D
D --> E[ClusterRoleBinding]
This is the pattern used by the upstream cluster-admin
role’s aggregation — every add-on controller adds a
ClusterRole with the right label, and cluster-admin
automatically grants it.
Wildcards
A Role can use * for apiGroups, resources, or
verbs. Each wildcard dramatically expands the surface:
# Worst-case ClusterRole
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
This is cluster-admin. A user bound to this is God.
A misconfiguration that grants this to a ServiceAccount
is the most common root cause of cluster compromises.
# Less awful but still wrong
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["*"]
This allows the user to create, update, patch, and delete Deployments in the namespace. Better than cluster-admin, but still wide. A pattern to avoid.
# Minimum surface
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch"]
resourceNames: ["myapp"] # only this one Deployment
This allows read of one specific Deployment. The smallest possible role.
Common production patterns
Three patterns recur:
- CI/CD read —
get,list,watchondeployments,pods,services,configmaps,secrets. No write verbs. - Application runtime —
get,list,watchon a specific ConfigMap or Secret (viaresourceNames). No other resources. - Operator — full verbs on the CRD it manages,
plus
get/list/watchon the underlying resources (Deployments, Services). Often uses aggregation to compose the role.
Production failure modes
verbs: ["*"]instead of["get", "list", "watch"]. A role with all verbs is a write role. The team intended read-only.resources: ["*"]. A role with all resources includes Secrets, ConfigMaps, and CRDs. The team intended a specific set.apiGroups: ["*"]. A role with all API groups includesrbac.authorization.k8s.ioandadmissionregistration.k8s.io. The user can create RoleBindings and admission policies — RBAC escalation.- Aggregation that grows unbounded. An aggregated role that pulls in every role with a label can grant permissions the operator never intended. Audit the aggregation chain.
Cross-course references
- The Linux course covers the file permissions (0600, 0640) that Kubernetes RBAC does not enforce — file permissions on Secret data are a separate concern.
- The Observability course covers the audit log that records every RBAC decision.
Quiz
Knowledge check · 4 questions
Q1. Which is the smallest possible RBAC rule that allows a workload to read the contents of a specific ConfigMap named `app-config` in the `prod` namespace?
Q2. An RBAC role that grants `update` on Pods allows the caller to modify the Pod's container image and security context, but does not allow Pod creation or deletion.
Q3. Your team's Helm chart ships a ServiceAccount with a ClusterRoleBinding to a ClusterRole called `read-everything`. The ClusterRole has `apiGroups: ['*'], resources: ['*'], verbs: ['get', 'list', 'watch']`. An attacker compromises a Pod that uses this SA. What is the blast radius?
The ClusterRole has full read on every resource in every API group in the cluster. The SA is `default` in the `ci` namespace. The cluster has 80 nodes, 1,200 workloads, 200 ServiceAccounts. The SA's token is projected into the Pod.
Q4. Explain how RBAC aggregation works and give one production use case.
Passing score: 75%. Answers are checked in this browser.
Production discipline
A defensible RBAC implementation writes the smallest
Role that allows the work, scopes it to a namespace
unless cluster-wide is required, and avoids wildcards.
Aggregation is the right pattern for composing roles
from common building blocks (monitoring, observability,
CI/CD), but every aggregation chain must be audited —
the aggregated role’s surface is the union of every
contributing role. A cluster that has
apiGroups: ['*'], resources: ['*'], verbs: ['*'] in
a ClusterRoleBinding to a ServiceAccount is one
compromised Pod away from a full cluster compromise.
The discipline is to write the minimum, audit the
aggregation, and test with kubectl auth can-i.