skip to content

Kubernetes refuses to let a user create a Role granting permissions they do not themselves hold, unless they have the escalate verb. Explain that privilege-escalation prevention rule, what the bind verb does, and how it shapes delegating RBAC administration to teams.

level: seniorimportance: should knowfreq 38%

answer

  1. can't grant what you don't hold — checked on role writes
  2. escalate = waiver on role creation ≈ cluster-admin
  3. bind + resourceNames = hand out one curated role
  4. built-in admin via RoleBinding = safe namespace self-service
  5. hidden escalations: impersonate, pod create, exec, secrets get

basics

~20 s

When you create or update a Role or ClusterRole, the API server checks that you already hold every permission in it; otherwise it rejects the write. Creating a binding likewise requires holding the role's permissions, or the bind verb on that role. The escalate verb waives the first check. This stops namespace admins from minting themselves cluster power.

solid answer

~60 s

**The rule.** RBAC write operations are special-cased. To `create`/`update` a Role or ClusterRole, the API server requires that you already possess every rule it contains, evaluated in the target scope. Otherwise: `403 ... attempt to grant extra privileges`. Without this, anyone with `create` on `roles` in their namespace could write a role granting `secrets: *` and bind it to themselves. **Two escape hatches, both explicit grants:** - **`escalate`** on `roles`/`clusterroles` — waives the "must already hold it" check on role *creation*. Effectively equivalent to cluster-admin; grant it only to controllers that install RBAC. - **`bind`** on a specific `roleRef` — lets you create a binding to a named role you do not hold. This is the useful one: grant a team `bind` on a curated `app-deployer` ClusterRole with `resourceNames`, and they can delegate that exact role to their own ServiceAccounts without being able to invent new roles. **Delegation pattern.** Give namespace owners the built-in `admin` ClusterRole via RoleBinding: it lets them manage Roles and RoleBindings *within* the namespace, and the escalation check naturally caps them at what `admin` itself holds. Curate ClusterRoles centrally, grant `bind` with `resourceNames` for the ones teams may hand out.

code

yaml · 13 lines
yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: team-a
  name: can-delegate-ci-deployer
rules:
  - apiGroups: ["rbac.authorization.k8s.io"]
    resources: ["clusterroles"]
    resourceNames: ["ci-deployer"]
    verbs: ["bind"]
  - apiGroups: ["rbac.authorization.k8s.io"]
    resources: ["rolebindings"]
    verbs: ["create", "get", "list", "delete"]

go deeper

for a junior

Know that you cannot create a Role granting more than you already have, and that this is why namespace self-service RBAC is safe.

for a middle

Explain the check on both role writes and binding creation, and what the escalate and bind verbs waive.

for a senior

Design the delegation: built-in admin per namespace, curated ClusterRoles with narrow bind grants, and an audit that also covers impersonate, pod create, exec and secrets read.

for a principal

Frame the whole trust model — which team may grant what to whom, where escalate legitimately lives for operators, and how you continuously detect drift toward cluster-wide grants.

## Why RBAC needs a special rule about itself RBAC objects are ordinary API resources, so "who may write Roles" is itself an RBAC question. That creates a bootstrapping hazard: if writing a Role were a plain `create` permission, then anyone with `create` on `roles` in their namespace could author a Role granting anything — read all Secrets, exec into any pod — bind it to themselves, and have escalated. Namespace-level delegation would be equivalent to cluster-admin. Kubernetes closes this with two checks performed by the RBAC authorizer on writes to RBAC objects themselves. ## Check 1 — privilege escalation prevention on role writes When you `create` or `update` a `Role` or `ClusterRole`, the API server verifies that **every rule in the object is already permitted to you** in the relevant scope. If any rule exceeds your own permissions the write is rejected: ``` roles.rbac.authorization.k8s.io "x" is forbidden: user "alice" (groups=...) is attempting to grant RBAC permissions not currently held ``` Scope matters: writing a namespaced Role is checked against your permissions *in that namespace*, so a namespace admin can freely author Roles covering anything they themselves can do there. Writing a ClusterRole is checked cluster-wide. The waiver is the **`escalate`** verb on `roles`/`clusterroles`. A subject holding it may write roles containing permissions they lack. Treat holding `escalate` on `clusterroles` as equivalent to cluster-admin, because the holder can write themselves a cluster-admin-equivalent role in one step (they still need to bind it, but `bind`/`escalate` are usually granted together to the operators that need them). Legitimate holders are controllers and operators that install RBAC as part of a chart or CRD lifecycle. ## Check 2 — binding requires holding, or bind Creating a `RoleBinding`/`ClusterRoleBinding` is guarded too. To bind a role you must either: - hold every permission the referenced role contains (same escalation check), **or** - hold the **`bind`** verb on that role, ideally narrowed with `resourceNames`. `bind` is the precise delegation primitive. It says: *you may hand out this specific, pre-approved role, even though you do not hold it yourself.* A platform team can curate a `ci-deployer` ClusterRole and grant application teams `bind` on exactly that name; the team can then create RoleBindings attaching it to their own ServiceAccounts, and can neither modify the role nor invent a broader one. ```yaml rules: - apiGroups: ["rbac.authorization.k8s.io"] resources: ["clusterroles"] resourceNames: ["ci-deployer"] verbs: ["bind"] ``` Note the subtlety: `resourceNames` works here because binding references a *named* role, exactly the case `resourceNames` was built for. ## The built-in admin role The default `admin` ClusterRole, bound with a **RoleBinding**, is the intended "namespace owner" grant. It includes write on `roles` and `rolebindings` in that namespace, so the team can self-serve RBAC for their own workloads. The escalation check is what makes that safe: an admin can only author roles containing permissions `admin` itself confers in that namespace. They cannot grant node access, cannot grant cluster-scoped resources, cannot exceed themselves. This is why the correct answer to "how do I let teams manage their own RBAC?" is almost never a custom broad role — it is `admin` scoped by RoleBinding, plus targeted `bind` grants for anything centrally curated. ## Adjacent escalation paths the rule does not cover The escalation check is about *writing RBAC*. Several other permissions escalate without touching an RBAC object, and reviewers should treat them as equivalently sensitive: - **`impersonate`** on users/groups/serviceaccounts — act as anyone, including a cluster-admin identity. Frequently the forgotten one. - **`create` on `pods`** in a namespace with a powerful ServiceAccount — you can schedule a pod that mounts that SA's token and inherit it. Pod-create is therefore approximately "union of all ServiceAccount permissions in the namespace". - **`pods/exec`** — take over a running workload's identity. - **`get` on `secrets`** — read a ServiceAccount token or any credential. - **`create` on `serviceaccounts/token`** — mint tokens for other ServiceAccounts. - **Write on validating/mutating webhook configurations, or on CRDs** — subvert admission for the whole cluster. A meaningful RBAC review enumerates who holds these across all bindings, not just who holds `cluster-admin`. ## Auditing Practical checks: list every ClusterRoleBinding and inspect its subjects; grep all Roles and ClusterRoles for the verbs `escalate`, `bind`, `impersonate` and for `*` in verbs or resources; and use `kubectl auth can-i --list --as <subject>` for each human group and each high-value ServiceAccount. Any `bind` grant without `resourceNames` should be justified — unrestricted `bind` on clusterroles means the holder can bind `cluster-admin`.

  • A namespace admin says they cannot create a Role granting read on nodes. Is that a bug?
    No, it is the escalation check working. Their admin grant is namespaced and confers no access to nodes, which are cluster-scoped, so authoring a role containing that rule would grant a privilege they do not hold and the API server rejects it. The correct path is a platform-owned ClusterRole plus a ClusterRoleBinding created by someone who does hold node access.
  • Why is granting the escalate verb roughly equivalent to granting cluster-admin?
    Escalate waives the check that a role's contents cannot exceed the author's own permissions, so the holder can author a ClusterRole containing every verb on every resource. Combined with the ability to create bindings — which such operators almost always also have — that is one step from full cluster control. Reserve it for controllers that must install RBAC, and audit anything that holds it.
  • Beyond RBAC write permissions, which grants let a subject escalate anyway?
    Impersonate lets them act as any user or ServiceAccount. Create on pods in a namespace effectively grants the union of that namespace's ServiceAccount permissions, since a pod can mount any SA's token. pods/exec takes over a running workload's identity, get on secrets can read credentials and tokens, and write access to webhook configurations or CRDs subverts admission cluster-wide. A review that only looks for cluster-admin misses all of these.

You may write a job description only for duties you are already authorized to perform. The bind verb is being handed a pre-signed offer letter for one specific role you cannot perform yourself but may hire someone into.

saying these in an interview costs you the question

  • Thinking a namespace admin can grant themselves cluster-wide permissions
  • Treating the escalate verb as a minor convenience rather than near-cluster-admin
  • Granting bind on clusterroles without resourceNames
  • Assuming RBAC is safe as long as nobody is bound to cluster-admin, ignoring impersonate and pod-create
  • Believing the escalation check applies to ordinary resources rather than only to RBAC object writes

context