Skip to main content

Limit Use Of The Bind, Impersonate And Escalate Permissions

More Info:

The bind, impersonate and escalate RBAC verbs allow subjects to grant themselves or others additional privileges. Restrict them tightly.

Risk Level

High

Address

Security

Compliance Standards

  • CIS Kubernetes

Triage and Remediation

Remediation

Manual Steps
  1. List all ClusterRoles/roles using bind, impersonate, or escalate

    • On any machine with kubectl access:
      kubectl get clusterroles -o json | \
      jq -r '.items[]
      | select(.rules[]?
      | any(.verbs[]?; .=="bind" or .=="escalate" or .=="impersonate"))
      | .metadata.name'
      kubectl get roles --all-namespaces -o json | \
      jq -r '.items[]
      | select(.rules[]?
      | any(.verbs[]?; .=="bind" or .=="escalate" or .=="impersonate"))
      | "\(.metadata.namespace):\(.metadata.name)"'
    • Save the outputs; these are the RBAC definitions to review.
  2. Inspect the privileges and intended use of each risky role

    • For each ClusterRole name from step 1:
      kubectl get clusterrole <CLUSTERROLE_NAME> -o yaml
    • For each namespaced Role (namespace:name) from step 1:
      kubectl get role <ROLE_NAME> -n <NAMESPACE> -o yaml
    • Manually determine:
      • Which subjects (users/groups/serviceaccounts) are supposed to have these capabilities, if any.
      • Whether these verbs are strictly required for the role’s intended function (e.g., controller that must create/modify RBAC).
  3. Identify who can use those roles via bindings

    • For each risky ClusterRole:
      kubectl get clusterrolebindings -o json | \
      jq -r '.items[]
      | select(.roleRef.kind=="ClusterRole" and .roleRef.name=="<CLUSTERROLE_NAME>")
      | .metadata.name'
      kubectl get clusterrolebinding <BINDING_NAME> -o yaml
    • For each risky namespaced Role:
      kubectl get rolebindings --all-namespaces -o json | \
      jq -r '.items[]
      | select(.roleRef.kind=="Role" and .roleRef.name=="<ROLE_NAME>")
      | "\(.metadata.namespace):\(.metadata.name)"'
      kubectl get rolebinding <BINDING_NAME> -n <NAMESPACE> -o yaml
    • Manually review whether each bound subject truly needs bind/impersonate/escalate.
  4. Decide on least‑privilege changes per role and binding
    For each role/binding you reviewed, choose one of:

    • Remove the dangerous verbs entirely if not strictly needed: edit the role and delete bind, escalate, and impersonate from the verbs list.
      kubectl edit clusterrole <CLUSTERROLE_NAME>
      # or
      kubectl edit role <ROLE_NAME> -n <NAMESPACE>
    • Scope down subjects if the verbs are needed only for a very small set of trusted identities:
      • Remove unnecessary subjects from the corresponding ClusterRoleBinding/RoleBinding.
        kubectl edit clusterrolebinding <BINDING_NAME>
        # or
        kubectl edit rolebinding <BINDING_NAME> -n <NAMESPACE>
    • Split roles: create a separate role without these verbs for most users, keeping bind/impersonate/escalate only in a dedicated, tightly bound role for specific automation or administrators (via manifest updates or kubectl apply -f).
  5. Re-apply or create updated RBAC manifests (if using GitOps/IaC)

    • If your cluster uses manifests as the source of truth, mirror the edits from step 4 into your RBAC YAML and re-apply:
      kubectl apply -f <UPDATED_RBAC_MANIFEST.yaml>
    • Ensure CI/GitOps will not reintroduce the removed verbs or bindings.
  6. Verify that risky verbs are now limited to explicitly approved roles

    • Re-run the evidence commands from step 1 on any machine with kubectl:
      kubectl get clusterroles -o json | \
      jq -r '.items[]
      | select(.rules[]?
      | any(.verbs[]?; .=="bind" or .=="escalate" or .=="impersonate"))
      | .metadata.name'
      kubectl get roles --all-namespaces -o json | \
      jq -r '.items[]
      | select(.rules[]?
      | any(.verbs[]?; .=="bind" or .=="escalate" or .=="impersonate"))
      | "\(.metadata.namespace):\(.metadata.name)"'
    • Manually confirm that:
      • Only the minimal, explicitly justified roles still include these verbs.
      • Their bindings grant access only to tightly controlled, trusted subjects.
Using kubectl
# 1) List all ClusterRoles that include bind, impersonate, or escalate
# Run on: any machine with kubectl access
kubectl get clusterroles -o json | jq -r '
.items[]
| select(
[.rules[].verbs[]?] | inside(["bind"]) or
[.rules[].verbs[]?] | inside(["impersonate"]) or
[.rules[].verbs[]?] | inside(["escalate"])
)
| .metadata.name'

Problem indication: Any ClusterRole name returned here has at least one of the sensitive verbs and must be reviewed.


# 2) Inspect details of each suspicious ClusterRole (replace NAME with one from above)
kubectl get clusterrole NAME -o yaml

What to look for (problem indication):

  • verbs containing bind, impersonate, or escalate.
  • Combined with broad resources, for example:
    • resources: ["*"]
    • apiGroups: ["*"]
  • Or high‑risk targets such as:
    • resources: ["clusterroles","roles","clusterrolebindings","rolebindings","serviceaccounts","users","groups"]
  • Use by subjects that are not tightly controlled (see next commands).

# 3) See which ClusterRoleBindings and RoleBindings use those ClusterRoles
# Run once to get all bindings that reference sensitive-verb ClusterRoles
for cr in $(kubectl get clusterroles -o json | jq -r '
.items[]
| select(
[.rules[].verbs[]?] | inside(["bind"]) or
[.rules[].verbs[]?] | inside(["impersonate"]) or
[.rules[].verbs[]?] | inside(["escalate"])
)
| .metadata.name'); do
echo "=== Bindings for ClusterRole: $cr ==="
kubectl get clusterrolebindings -o json | jq -r --arg CR "$cr" '
.items[]
| select(.roleRef.kind=="ClusterRole" and .roleRef.name==$CR)
| .metadata.name + " (ClusterRoleBinding)"'
kubectl get rolebindings --all-namespaces -o json | jq -r --arg CR "$cr" '
.items[]
| select(.roleRef.kind=="ClusterRole" and .roleRef.name==$CR)
| .metadata.namespace + "/" + .metadata.name + " (RoleBinding)"'
done

Problem indication: Sensitive-verb ClusterRoles bound to:

  • subjects with kind: ServiceAccount in broad or default namespaces,
  • kind: User or kind: Group representing general developer or CI users, not a small, trusted admin set.

# 4) Inspect specific bindings and their subjects (replace NAME/NAMESPACE)
kubectl get clusterrolebinding NAME -o yaml
kubectl get rolebinding NAME -n NAMESPACE -o yaml

Problem indication:

  • subjects that are many or loosely defined (e.g., system:authenticated, large teams, generic service accounts).
  • Any non‑break‑glass / non‑cluster‑admin identity holding these permissions.

# 5) Check for impersonation permissions specifically
kubectl get clusterroles -o json | jq -r '
.items[]
| select(
any(.rules[]?; any(.verbs[]?; .=="impersonate"))
)
| .metadata.name as $name
| "ClusterRole: \($name)"'

Then, as in steps 2–4, inspect:

kubectl get clusterrole <NAME> -o yaml
kubectl get clusterrolebindings --all-namespaces -o yaml | \
yq 'select(.roleRef.kind=="ClusterRole" and .roleRef.name=="<NAME>")'
kubectl get rolebindings --all-namespaces -o yaml | \
yq 'select(.roleRef.kind=="ClusterRole" and .roleRef.name=="<NAME>")'

Problem indication: impersonate on users, groups, or serviceaccounts granted to any subject that is not a strictly controlled admin/break‑glass identity.


# 6) Quick summary table of all sensitive-verb ClusterRoles and which verbs they use
kubectl get clusterroles -o json | jq -r '
.items[]
| {name: .metadata.name, rules: .rules}
| select(.rules != null)
| .name as $n
| ([.rules[].verbs[]?] | unique) as $verbs
| select(any($verbs[]; .=="bind" or .=="impersonate" or .=="escalate"))
| "\($n): \($verbs | join(","))"'

Problem indication: Roles with multiple sensitive verbs or with these verbs in roles that are not clearly “admin‑only” are higher‑risk and should be candidates for restriction or redesign.

Automation
#!/usr/bin/env bash
# Report ClusterRoles and Roles that grant bind / impersonate / escalate,
# and which subjects can use them (directly or via RoleBindings/ClusterRoleBindings).

set -euo pipefail

echo "=== 1) ClusterRoles with bind/impersonate/escalate verbs ==="
kubectl get clusterroles -o json \
| jq -r '
.items[]
| {name: .metadata.name, rules: .rules}
| select(
.rules != null and
([.rules[].verbs[]?] | inside(["bind","impersonate","escalate"]) or
(.rules[]? | .verbs[]? as $v | select($v=="bind" or $v=="impersonate" or $v=="escalate")))
)
| "ClusterRole: \(.name)\nRules:\n\(.rules | tojson)\n---"
'

echo
echo "=== 2) Namespaced Roles with bind/impersonate/escalate verbs ==="
kubectl get roles --all-namespaces -o json \
| jq -r '
.items[]
| {ns: .metadata.namespace, name: .metadata.name, rules: .rules}
| select(
.rules != null and
([.rules[].verbs[]?] | inside(["bind","impersonate","escalate"]) or
(.rules[]? | .verbs[]? as $v | select($v=="bind" or $v=="impersonate" or $v=="escalate")))
)
| "Role: \(.ns)/\(.name)\nRules:\n\(.rules | tojson)\n---"
'

echo
echo "=== 3) ClusterRoleBindings referencing those high-privilege ClusterRoles ==="
# First collect ClusterRoles that have the sensitive verbs
high_priv_crs=$(kubectl get clusterroles -o json \
| jq -r '
.items[]
| select(
.rules != null and
([.rules[].verbs[]?] | inside(["bind","impersonate","escalate"]) or
(.rules[]? | .verbs[]? as $v | select($v=="bind" or $v=="impersonate" or $v=="escalate")))
)
| .metadata.name
' | sort -u)

if [ -n "$high_priv_crs" ]; then
# shellcheck disable=SC2086
kubectl get clusterrolebindings -o json \
| jq -r --argjson crs "$(printf '%s\n' $high_priv_crs | jq -R . | jq -s .)" '
.items[]
| select(.roleRef.kind=="ClusterRole" and (.roleRef.name as $n | $crs | index($n)))
| "ClusterRoleBinding: \(.metadata.name)\n RoleRef: \(.roleRef.kind)/\(.roleRef.name)\n Subjects: \(.subjects // [] | tojson)\n---"
'
else
echo "No ClusterRoles with bind/impersonate/escalate verbs found."
fi

echo
echo "=== 4) RoleBindings referencing high-privilege Roles ==="
# Collect Roles that have the sensitive verbs
high_priv_roles=$(kubectl get roles --all-namespaces -o json \
| jq -r '
.items[]
| select(
.rules != null and
([.rules[].verbs[]?] | inside(["bind","impersonate","escalate"]) or
(.rules[]? | .verbs[]? as $v | select($v=="bind" or $v=="impersonate" or $v=="escalate")))
)
| .metadata.namespace + "/" + .metadata.name
' | sort -u)

if [ -n "$high_priv_roles" ]; then
kubectl get rolebindings --all-namespaces -o json \
| jq -r --argjson roles "$(printf '%s\n' $high_priv_roles | jq -R . | jq -s .)" '
.items[]
| . as $rb
| ($rb.roleRef.kind + ":" + $rb.metadata.namespace + "/" + $rb.roleRef.name) as $key
| select(
($rb.roleRef.kind=="Role") and
($roles | map("Role:" + .) | index($key))
)
| "RoleBinding: \(.metadata.namespace)/\(.metadata.name)\n RoleRef: \(.roleRef.kind)/\(.roleRef.name)\n Subjects: \(.subjects // [] | tojson)\n---"
'
else
echo "No Roles with bind/impersonate/escalate verbs found."
fi

echo
echo "=== Interpretation ==="
cat <<'EOF'
Potential problems indicated by this report:
- Any ClusterRole or Role listed in sections (1) or (2) that is not strictly required.
- Any ClusterRoleBinding or RoleBinding in sections (3) or (4) that grants these verbs to:
* broad groups (e.g., system:authenticated, system:masters, or large custom groups)
* service accounts in general-purpose namespaces
* end-user identities that do not administer RBAC

These entries should be reviewed manually. Where possible, remove bind/impersonate/escalate
from the role, or narrow/remove the bindings that grant access to such roles.
EOF

Run this from any machine with kubectl access.
Problematic output is any role giving ["bind","impersonate","escalate"] (alone or among other verbs) to non-essential admin identities or broad subjects, especially in shared or application namespaces.