Skip to main content

Limit Use Of The Bind, Impersonate And Escalate Permissions

More Info:

The bind, impersonate, and escalate permissions allow subjects to acquire additional privileges within the cluster. Remove these rights from subjects wherever possible.

Risk Level

High

Address

Security

Compliance Standards

  • CIS EKS

Triage and Remediation

Remediation

Manual Steps
  1. List all ClusterRoles that grant bind/impersonate/escalate

    • Run on: any machine with kubectl access
    kubectl get clusterroles -o json | jq -r '
    .items[]
    | select(
    ([.rules[].verbs[]?] | contains(["bind"]) or
    [.rules[].verbs[]?] | contains(["impersonate"]) or
    [.rules[].verbs[]?] | contains(["escalate"]))
    )
    | .metadata.name
    ' | sort -u
  2. Inspect the detailed rules for those ClusterRoles

    • Replace <CLUSTERROLE> with each name from step 1
    • Run on: any machine with kubectl access
    kubectl get clusterrole <CLUSTERROLE> -o yaml
  3. Identify where these ClusterRoles are bound (who gets these rights)

    • For each <CLUSTERROLE> from step 1, list ClusterRoleBindings and RoleBindings that reference it:
    • Run on: any machine with kubectl access
    # ClusterRoleBindings (cluster-wide subjects)
    kubectl get clusterrolebindings -o json | jq -r '
    .items[]
    | select(.roleRef.kind=="ClusterRole" and .roleRef.name=="<CLUSTERROLE>")
    | .metadata.name," -> subjects:",(.subjects[]? | " "+.kind+"/"+.name)
    '

    # Namespaced RoleBindings granting the ClusterRole
    for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
    echo "Namespace: $ns"
    kubectl get rolebindings -n "$ns" -o json | jq -r '
    .items[]
    | select(.roleRef.kind=="ClusterRole" and .roleRef.name=="<CLUSTERROLE>")
    | .metadata.name," -> subjects:",(.subjects[]? | " "+.kind+"/"+.name)
    '
    done
  4. Decide which subjects truly require bind/impersonate/escalate

    • For each binding found in step 3:
      • Confirm whether the subject (user/group/serviceaccount) is an infrastructure component or automation that must:
        • create/modify RoleBindings/ClusterRoleBindings (needs bind),
        • act on behalf of other users (needs impersonate),
        • change privilege levels or assign high-privilege roles (needs escalate).
      • Mark each subject as:
        • “Required” (document the justification), or
        • “Excess” (should be removed or replaced with a less-privileged role).
  5. Remove or reduce excessive permissions from bindings and/or roles

    • To remove a subject from a binding (safer than deleting the role):
    • Run on: any machine with kubectl access
    # Edit binding and remove the subject entry
    kubectl edit clusterrolebinding <BINDING_NAME>
    # or, for namespaced:
    kubectl edit rolebinding <BINDING_NAME> -n <NAMESPACE>
    • If a ClusterRole is used only to provide bind/impersonate/escalate and is no longer needed:
    kubectl delete clusterrole <CLUSTERROLE>
    • Alternatively, edit the ClusterRole to remove those verbs from its rules:
    kubectl edit clusterrole <CLUSTERROLE>
    # In the editor, remove "bind", "impersonate", and/or "escalate" from .rules[].verbs
  6. Verify that bind/impersonate/escalate are now limited

    • Re-run the initial discovery and ensure only justified, documented roles remain:
    kubectl get clusterroles -o json | jq -r '
    .items[]
    | select(
    ([.rules[].verbs[]?] | contains(["bind"]) or
    [.rules[].verbs[]?] | contains(["impersonate"]) or
    [.rules[].verbs[]?] | contains(["escalate"]))
    )
    | .metadata.name
    ' | sort -u
    • For any remaining roles listed, confirm that their bindings (step 3) match the “Required” subjects decided in step 4.
Using kubectl
# 1) List all ClusterRoles that grant bind/impersonate/escalate
# Run on: any machine with kubectl access

kubectl get clusterroles -o json | jq -r '
.items[]
| select(
# Rules that mention these sensitive verbs
(.rules[]? | (.verbs[]? | IN("bind","impersonate","escalate")))
# Or rules that target the SubjectAccessReview APIs (strong signal of privilege logic)
or (.rules[]? | (.resources[]? | test("subjectaccessreview"; "i")))
)
| .metadata.name
' | sort -u

Problem indication:
Any ClusterRole shown here is potentially sensitive and needs manual review.


# 2) Show full details of each potentially sensitive ClusterRole
# Replace <CLUSTERROLE_NAME> with each name from the previous command.

kubectl get clusterrole <CLUSTERROLE_NAME> -o yaml

What to look for:

Within rules::

  • Problematic verbs:
    • verbs: ["bind"]
    • verbs: ["impersonate"]
    • verbs: ["escalate"]
  • Problematic resources (often combined with above verbs):
    • resources: ["clusterroles", "roles"] with bind
    • resources including subjectaccessreviews, selfsubjectaccessreviews, localsubjectaccessreviews with wide verbs like ["create","update","*"]
  • Excessive wildcards:
    • verbs: ["*"]
    • resources: ["*"] or apiGroups: ["*"]

These indicate the role can grant or exercise extra privileges and must be justified.


# 3) Find which subjects are bound to these sensitive ClusterRoles
# For each <CLUSTERROLE_NAME> from step 1:

kubectl get clusterrolebindings -o json | jq -r '
.items[]
| select(.roleRef.kind == "ClusterRole" and .roleRef.name == "<CLUSTERROLE_NAME>")
| .metadata.name
'
# 4) Inspect each ClusterRoleBinding to see who gets these rights

kubectl get clusterrolebinding <BINDING_NAME> -o yaml

What to look for in bindings (subjects:):

  • Broad subjects:
    • kind: Group, name: system:authenticated or system:serviceaccounts
    • kind: ServiceAccount without namespace scoping in your manifests/IaC
  • Service accounts or users not clearly part of a privileged admin/CI/CD function.

Bindings that give these roles to wide groups or non-admin workloads are strong problems.


# 5) Also check namespace-scoped Roles (less common but possible)

kubectl get roles --all-namespaces -o json | jq -r '
.items[]
| select(.rules[]? | (.verbs[]? | IN("bind","impersonate","escalate")))
| "\(.metadata.namespace)/\(.metadata.name)"
' | sort
# 6) Show each flagged Role and its RoleBindings

# Inspect Role:
kubectl get role -n <NAMESPACE> <ROLE_NAME> -o yaml

# Find RoleBindings using that Role:
kubectl get rolebindings -n <NAMESPACE> -o json | jq -r '
.items[]
| select(.roleRef.kind == "Role" and .roleRef.name == "<ROLE_NAME>")
| .metadata.name
'

# Inspect each RoleBinding:
kubectl get rolebinding -n <NAMESPACE> <BINDING_NAME> -o yaml

Problem indication:
Namespace Roles that grant these verbs to regular application service accounts or broad groups should be treated as misconfigurations unless there is a clear, documented need.


Verification after manual review/changes

After you manually adjust roles/bindings (via edited manifests/IaC):

# Re-run the discovery to confirm remaining usage is limited and intentional

kubectl get clusterroles -o json | jq -r '
.items[]
| select(.rules[]? | (.verbs[]? | IN("bind","impersonate","escalate")))
| .metadata.name
' | sort -u

You should be able to account for every remaining ClusterRole listed and validate that only strictly necessary, well-justified subjects are bound to them.

Automation
#!/usr/bin/env bash
#
# Report ClusterRoles and Roles that grant:
# - verbs: impersonate, bind, escalate
# - or broad RBAC rights that include those verbs via wildcards
#
# Run on: any machine with kubectl access to the cluster
# Requirements: kubectl, jq, grep, awk, sed
set -euo pipefail

# Helper: header
hdr() {
echo
echo "============================================================"
echo "$1"
echo "============================================================"
}

# 1) Raw RBAC objects with explicit impersonate/bind/escalate verbs
hdr "1) ClusterRoles WITH explicit impersonate/bind/escalate verbs"
kubectl get clusterroles -o json \
| jq -r '
.items[]
| {name: .metadata.name, rules: .rules}
| select(
.rules != null and
(.rules[]
| select(.verbs != null)
| .verbs[]
| IN("impersonate","bind","escalate"))
)
| .name
' | sort -u || true

hdr "2) Roles WITH explicit impersonate/bind/escalate verbs (namespaced)"
kubectl get roles --all-namespaces -o json \
| jq -r '
.items[]
| {ns: .metadata.namespace, name: .metadata.name, rules: .rules}
| select(
.rules != null and
(.rules[]
| select(.verbs != null)
| .verbs[]
| IN("impersonate","bind","escalate"))
)
| "\(.ns)/\(.name)"
' | sort -u || true

# 2) RBAC objects that may indirectly allow these verbs via wildcards
hdr "3) ClusterRoles that use wildcard verbs or resources (potentially risky)"
kubectl get clusterroles -o json \
| jq -r '
.items[]
| {name: .metadata.name, rules: .rules}
| select(
.rules != null and
(.rules[]
| ( (.verbs != null and (.verbs[] == "*"))
or (.resources != null and (.resources[] == "*"))
or (.apiGroups != null and (.apiGroups[] == "*"))
)
)
)
| .name
' | sort -u || true

hdr "4) Roles that use wildcard verbs or resources (namespaced, potentially risky)"
kubectl get roles --all-namespaces -o json \
| jq -r '
.items[]
| {ns: .metadata.namespace, name: .metadata.name, rules: .rules}
| select(
.rules != null and
(.rules[]
| ( (.verbs != null and (.verbs[] == "*"))
or (.resources != null and (.resources[] == "*"))
or (.apiGroups != null and (.apiGroups[] == "*"))
)
)
)
| "\(.ns)/\(.name)"
' | sort -u || true

# 3) Subjects that are bound to these risky roles
hdr "5) ClusterRoleBindings that reference risky ClusterRoles"
# First, compute set of risky ClusterRoles
readarray -t risky_crs < <(
{
kubectl get clusterroles -o json \
| jq -r '
.items[]
| {name: .metadata.name, rules: .rules}
| select(
.rules != null and
(.rules[]
| select(.verbs != null)
| .verbs[]
| IN("impersonate","bind","escalate"))
)
| .name
' ;
kubectl get clusterroles -o json \
| jq -r '
.items[]
| {name: .metadata.name, rules: .rules}
| select(
.rules != null and
(.rules[]
| ( (.verbs != null and (.verbs[] == "*"))
or (.resources != null and (.resources[] == "*"))
or (.apiGroups != null and (.apiGroups[] == "*"))
)
)
)
| .name
'
} | sort -u
)

if ((${#risky_crs[@]} == 0)); then
echo "No risky ClusterRoles detected."
else
printf '%s\n' "${risky_crs[@]}" > /tmp/risky_clusterroles.txt

kubectl get clusterrolebindings -o json \
| jq -r '
.items[]
| {name: .metadata.name, roleRef: .roleRef, subjects: .subjects}
| select(.roleRef.kind == "ClusterRole")
| "\(.roleRef.name) \(.name)"
' \
| while read -r role binding; do
if grep -qx "$role" /tmp/risky_clusterroles.txt; then
echo "ClusterRoleBinding: $binding (role: $role)"
kubectl get clusterrolebinding "$binding" -o yaml
echo "------------------------------------------------------------"
fi
done
fi

hdr "6) RoleBindings that reference risky Roles (namespaced)"
# Compute set of risky Roles
readarray -t risky_roles < <(
{
kubectl get roles --all-namespaces -o json \
| jq -r '
.items[]
| {ns: .metadata.namespace, name: .metadata.name, rules: .rules}
| select(
.rules != null and
(.rules[]
| select(.verbs != null)
| .verbs[]
| IN("impersonate","bind","escalate"))
)
| "\(.ns)/\(.name)"
' ;
kubectl get roles --all-namespaces -o json \
| jq -r '
.items[]
| {ns: .metadata.namespace, name: .metadata.name, rules: .rules}
| select(
.rules != null and
(.rules[]
| ( (.verbs != null and (.verbs[] == "*"))
or (.resources != null and (.resources[] == "*"))
or (.apiGroups != null and (.apiGroups[] == "*"))
)
)
)
| "\(.ns)/\(.name)"
'
} | sort -u
)

if ((${#risky_roles[@]} == 0)); then
echo "No risky namespaced Roles detected."
else
printf '%s\n' "${risky_roles[@]}" > /tmp/risky_roles.txt

kubectl get rolebindings --all-namespaces -o json \
| jq -r '
.items[]
| {ns: .metadata.namespace, name: .metadata.name, roleRef: .roleRef}
| select(.roleRef.kind == "Role")
| "\(.ns) \(.name) \(.roleRef.name)"
' \
| while read -r ns binding role; do
if grep -qx "${ns}/${role}" /tmp/risky_roles.txt; then
echo "RoleBinding: ${ns}/${binding} (role: ${ns}/${role})"
kubectl -n "$ns" get rolebinding "$binding" -o yaml
echo "------------------------------------------------------------"
fi
done
fi

hdr "SUMMARY"
echo "1) Any ClusterRole or Role listed in sections 1 and 2 DEFINITELY uses impersonate/bind/escalate."
echo "2) Any role listed in sections 3 and 4 uses wildcards and MAY implicitly allow those verbs."
echo "3) Sections 5 and 6 show which subjects (users, groups, service accounts) are bound to risky roles."
echo
echo "Review each risky role and its bindings and remove impersonate/bind/escalate where not strictly required."

Explanation of output that indicates a problem:

  • Section 1 and 2: Any ClusterRole or Role listed here explicitly includes impersonate, bind, or escalate in .rules[].verbs. These are directly problematic and must be reviewed; remove those verbs unless strictly necessary.
  • Section 3 and 4: ClusterRoles/Roles listed here use * in verbs, resources, or apiGroups. These broad grants may indirectly allow impersonation or privilege escalation; they should be narrowed or redesigned.
  • Section 5 and 6: For each risky role, these sections show the RoleBindings/ClusterRoleBindings and their subjects. If high-privilege or many subjects are bound (e.g., generic groups like system:authenticated), that indicates higher risk.