Most people learn RBAC as a way to grant access: write a Role, bind it to a ServiceAccount, done. On the Certified Kubernetes Security Specialist (CKS) exam, the harder — and more frequently tested — question is the inverse: which permissions let a subject grant itself more permissions? That is privilege escalation, and RBAC has three special verbs that exist precisely to control it: escalate, bind, and impersonate.
If you already know how to create a least-privilege Role, this guide is the next layer. We assume the fundamentals from the CKS cluster setup and hardening guide — Role vs ClusterRole, RoleBinding vs ClusterRoleBinding, and the kubectl auth can-i habit — and focus entirely on the escalation mechanics that the exam’s “minimize exposure with RBAC” objective is really testing.
Why RBAC Is an Escalation Surface
RBAC is additive and permissive-by-omission: a subject can do exactly what some binding grants, and nothing else. That sounds safe until you notice that some permissions are permissions to manage permissions. If a compromised ServiceAccount can create a ClusterRoleBinding, it can bind itself to cluster-admin and own the cluster. The blast radius of a leaked token isn’t the token’s current rights — it’s the transitive closure of everything those rights can be used to grant.
The exam rewards you for spotting these transitive paths in a Role and shutting them down. There are three categories to internalize:
| Escalation path | What it looks like in a Role | Why it’s dangerous |
|---|---|---|
| Manage RBAC objects | create/update/patch on roles, rolebindings, clusterroles, clusterrolebindings | Write your own grants |
| Special verbs | escalate, bind, impersonate | Bypass the built-in guardrails |
| Control a powerful identity | create pods, create on serviceaccounts/token, control a Secret holding a token | Borrow someone else’s rights |
Kubernetes anticipated the first category, so it built two guardrails into the RBAC authorizer. Understanding those guardrails — and the verbs that turn them off — is the core of this topic.
Guardrail #1: Escalation Prevention and the escalate Verb
Here is the rule most candidates miss: you cannot create or update a Role or ClusterRole that contains permissions you do not already hold. The RBAC authorizer checks every rule in the role you are trying to write against your own effective permissions. If any rule grants something you can’t already do, the request is rejected — even if you have create on roles.
This stops the obvious attack. A user with create rolebindings and create roles in a namespace cannot simply author a Role with verbs: ["*"] on secrets and grant it to themselves, because they don’t already hold * on secrets.
The escalate verb is the deliberate exception. Granting escalate on roles/clusterroles turns the check off for that subject, letting them write roles more powerful than their own:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: role-author-danger
rules:
# With this, the subject can craft ANY ClusterRole, including cluster-admin-equivalent
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["clusterroles"]
verbs: ["create", "update", "escalate"]
On the exam, if you see escalate in a rule, treat it as a red flag and be ready to explain why: it removes the guardrail that would otherwise confine a role author to their own privilege level. Legitimate uses exist (controllers that manage roles), but for a hardening task, escalate almost never belongs on a workload ServiceAccount.
Guardrail #2: Binding Restrictions and the bind Verb
The second guardrail governs binding, not authoring. To create a RoleBinding or ClusterRoleBinding that references a role, you must satisfy one of two conditions:
- You already hold all the permissions contained in the role you’re referencing, or
- You have the
bindverb on that specific role.
Without this, a subject with create rolebindings could bind the built-in cluster-admin ClusterRole to themselves. The guardrail blocks that: since they don’t already have cluster-admin, and they don’t have bind on cluster-admin, the binding is refused.
The bind verb is how you grant a controlled exception. Note that it is usually scoped to named roles with resourceNames, so a subject can bind only an approved role and nothing more powerful:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: can-bind-view-only
rules:
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["clusterroles"]
verbs: ["bind"]
resourceNames: ["view"] # may ONLY bind the built-in 'view' ClusterRole
Exam reflex: create on rolebindings without matching permissions and without bind is safe from escalation — the authorizer will reject any attempt to bind a role the subject doesn’t already hold. The danger appears when bind is granted broadly (no resourceNames) or when the subject already holds broad permissions.
Guardrail Bypass #3: the impersonate Verb
Impersonation is the most direct escalation of the three because it sidesteps roles entirely. A subject with the impersonate verb can send requests as another user, group, or ServiceAccount, inheriting that identity’s permissions for the request:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: impersonator-danger
rules:
- apiGroups: [""]
resources: ["users", "groups", "serviceaccounts"]
verbs: ["impersonate"]
With that grant, the subject runs:
# Act as a cluster-admin ServiceAccount
kubectl get secrets -A \
--as=system:serviceaccount:kube-system:some-powerful-sa
# Act as the built-in super-group — instant full admin
kubectl get secrets -A --as-group=system:masters --as=attacker
That second command is the killer. The group system:masters is a hardcoded superuser group in the API server’s authorization layer — members are granted full access regardless of RBAC. (kubeadm also creates a cluster-admin ClusterRoleBinding for it.) So impersonate on groups, unrestricted, is equivalent to handing out cluster-admin.
Lock impersonation down with resourceNames so a subject can impersonate only specific, low-privilege identities — never groups in general:
rules:
- apiGroups: [""]
resources: ["serviceaccounts"]
verbs: ["impersonate"]
resourceNames: ["limited-audit-sa"] # this SA only, nothing else
The Sneaky One: Aggregated ClusterRoles
Kubernetes’ built-in admin, edit, and view ClusterRoles are aggregated — their rules are assembled automatically from any ClusterRole carrying the right label, such as rbac.authorization.k8s.io/aggregate-to-admin: "true". The controller merges labelled roles into the aggregate.
That creates a subtle escalation path: if a subject can create clusterroles (even without escalate), they can create a new ClusterRole with the aggregate-to-admin label and inject their chosen rules into admin. Anyone bound to admin — a common, seemingly-safe grant — silently gains those extra permissions.
For a hardening task, restrict who can create ClusterRoles at all, and be suspicious of any workload that needs it. This is exactly the kind of indirect path the CKS likes to hide in a “review this RBAC and fix the over-permission” question.
The Certificate Path (Cross-Domain Escalation)
RBAC isn’t the only route to system:masters. The CertificateSigningRequest (CSR) API is another: a subject who can create CSRs and approve them (certificatesigningrequests/approval + a signer) can mint a client certificate with O=system:masters and authenticate as a full admin — no RBAC binding required, because the group is honored at authentication time.
This connects Cluster Hardening to certificate management. If you want the certificate mechanics, see Kubernetes Certificate Management for the CKA Exam. For CKS, the takeaway is narrower: approve on CSRs plus signing permission is an admin-equivalent grant, so treat it like escalate when you audit a role.
Detecting Escalation: the auth can-i Workflow
You can’t fix what you can’t see. kubectl auth can-i with the impersonation flags (--as, --as-group) lets you ask the API server exactly what a subject is allowed to do — the single most valuable habit for this domain.
# Everything a ServiceAccount can do, as a flat list
kubectl auth can-i --list \
--as=system:serviceaccount:web:app-sa -n web
# Can this SA do the escalation-critical things?
kubectl auth can-i create clusterrolebindings \
--as=system:serviceaccount:web:app-sa
kubectl auth can-i escalate clusterroles \
--as=system:serviceaccount:web:app-sa
kubectl auth can-i impersonate groups \
--as=system:serviceaccount:web:app-sa
# The blunt "is this basically admin?" check
kubectl auth can-i '*' '*' \
--as=system:serviceaccount:web:app-sa
A focused audit checklist for any subject you’re reviewing:
| Question to ask | Command fragment | Bad answer |
|---|---|---|
| Can it manage bindings? | create clusterrolebindings | yes |
| Can it author roles freely? | escalate clusterroles | yes |
| Can it bind broadly? | bind clusterroles (no resourceName) | yes |
| Can it impersonate? | impersonate groups / users | yes |
| Can it mint admin certs? | approve certificatesigningrequests | yes |
| Can it run any pod? | create pods in a sensitive namespace | often yes, investigate |
To find who across the cluster holds a dangerous grant, list bindings and inspect the referenced roles, or lean on the ecosystem tools you’re allowed to use in a lab (kubectl-who-can, rbac-tool) — but on the exam, auth can-i --as is always available and always sufficient.
Worked Example: Fixing an Over-Permissioned Role
A classic CKS task hands you a Role and asks you to remove privilege-escalation potential without breaking the app’s real job (say, reading ConfigMaps). You’re given this:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: app-runtime
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list"]
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["clusterroles", "clusterrolebindings"]
verbs: ["create", "escalate", "bind"] # ⚠️ escalation engine
- apiGroups: [""]
resources: ["users", "groups", "serviceaccounts"]
verbs: ["impersonate"] # ⚠️ act as anyone
The fix is to strip everything that isn’t the app’s actual need. The application reads ConfigMaps; it has no business writing RBAC or impersonating identities:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: app-runtime
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list"]
Then verify the escalation paths are gone while the real capability remains:
kubectl auth can-i get configmaps \
--as=system:serviceaccount:web:app-sa # yes ✅ still works
kubectl auth can-i escalate clusterroles \
--as=system:serviceaccount:web:app-sa # no ✅ fixed
kubectl auth can-i impersonate groups \
--as=system:serviceaccount:web:app-sa # no ✅ fixed
The mental model to carry into the exam: grant the noun (the resource) and the minimal verbs the app truly uses; never grant a verb that manages RBAC or identity unless the task explicitly requires it.
Hardening Checklist
- Never grant
escalate,bind, orimpersonateto a workload ServiceAccount without an explicit, reviewed reason. - When
bindorimpersonateis genuinely needed, constrain it withresourceNamesto specific, low-privilege targets. - Keep
create/update/patchonroles,rolebindings,clusterroles, andclusterrolebindingsoff application identities. - Restrict who can create ClusterRoles to avoid the aggregation-injection path into
admin/edit. - Treat
approveon CSRs plus a signer as admin-equivalent. - Audit with
kubectl auth can-i --list --as=...and the'*' '*'check before you call a role least-privilege. - Pair tight RBAC with a disabled token where the pod never calls the API — see ServiceAccount token security for CKS — so a leaked token has no credential to begin with.
- Wire up API audit logging so impersonation and binding attempts are recorded; the runtime security guide covers the audit-policy side.
- Consider an admission guardrail (e.g. a policy that rejects bindings to
cluster-admin) via admission control as defense in depth.
Practice on a Real Cluster Before Exam Day
Reading “impersonate on groups equals cluster-admin” is easy; proving it on a live cluster — running kubectl --as-group=system:masters, watching it succeed, then locking it down and confirming the fix with auth can-i — is what makes the knowledge stick under the two-hour clock.
Sailor.sh’s Certified Kubernetes Security Specialist (CKS) Mock Exam Bundle gives you a browser-based, exam-style terminal wired to a real Kubernetes cluster, with Cluster Hardening scenarios that ask you to find and remove escalation paths exactly like the worked example above. It mirrors the exam’s format and time pressure so the reflexes are there when it counts. Sequence it with the CKS study plan, confirm you’ve met the CKS prerequisites, and use the CKS exam topics breakdown to see how Cluster Hardening fits alongside the other domains.
Frequently Asked Questions
What is the difference between the escalate and bind verbs?
escalate applies when you author a Role/ClusterRole: it lets you write rules more powerful than your own permissions, bypassing the authorizer’s escalation-prevention check. bind applies when you create a binding: it lets you reference a role you don’t already fully hold. Authoring vs binding — different steps, different verbs.
Can a user with create rolebindings bind themselves to cluster-admin?
No — not by default. The RBAC authorizer refuses to create a binding to a role the subject doesn’t already possess, unless they have the bind verb on that role. So plain create rolebindings is not, by itself, an escalation to cluster-admin.
Why is impersonating the system:masters group so dangerous?
system:masters is treated as a superuser group in the API server’s authorization layer (and kubeadm binds it to cluster-admin). Any request made as that group is granted full access regardless of RBAC. So an unrestricted impersonate on groups is effectively a cluster-admin grant.
How do I check what permissions a ServiceAccount really has?
Use kubectl auth can-i --list --as=system:serviceaccount:<ns>:<name> -n <ns> for the full list, and targeted checks like kubectl auth can-i escalate clusterroles --as=... for the specific escalation verbs. The --as and --as-group flags let you ask the API server on behalf of any subject.
Are aggregated ClusterRoles really an escalation path?
Yes. Because admin, edit, and view are assembled from labelled ClusterRoles, a subject who can create ClusterRoles can inject rules into admin via the aggregate-to-admin label, silently expanding what everyone bound to admin can do. Restrict ClusterRole creation to prevent it.
How much of the CKS exam involves RBAC?
RBAC lives in the Cluster Hardening area and is one of the most reliably tested skills on the exam. Rather than fixate on a percentage, treat “read a role, spot the escalation path, and remove it with auth can-i proof” as a guaranteed exam muscle — see the CKS exam topics breakdown for how the domains fit together.
Conclusion
Least-privilege RBAC isn’t just about small verbs lists — it’s about refusing the meta-permissions that let a subject rewrite the permission model itself. Learn the three guardrail verbs cold: escalate (author beyond your rights), bind (bind a role you don’t hold), and impersonate (become another identity). Add the RBAC-object write permissions and the CSR-approval path, and you can look at any role and immediately answer the exam’s real question — can this identity give itself more? Prove it with kubectl auth can-i --as, strip what isn’t needed, and you’ve mastered one of the highest-value skills the CKS tests.