Limit Use Of The Bind, Impersonate And Escalate Permissions
More Info:
The bind, impersonate and escalate verbs allow a subject to acquire additional privileges beyond those directly granted. Their use should be tightly restricted.
Risk Level
High
Address
Security
Compliance Standards
- CIS GKE
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
List all roles/clusterroles using bind/impersonate/escalate
- Run on: any machine with kubectl access
- Command (given):
kubectl get clusterrole,role -A -o json | jq -r 'def risky_verbs: ["bind","impersonate","escalate"];.items[]| . as $r| [ $r.rules[]?| select((.verbs // [] | any(. as $v | $v == "bind" or $v == "impersonate" or $v == "escalate")))| {resources: ((.resources // ["*"]) | join(",")),verbs: ((.verbs // []) | map(select(IN("bind","impersonate","escalate"))) | join(","))}] as $matches| select($matches | length > 0)| [$r.kind,$r.metadata.name,($r.metadata.namespace // "cluster-wide"),($matches | map(.resources) | unique | join(",")),($matches | map(.verbs) | unique | join(","))] | @tsv' | awk -F'\t' 'BEGIN{printf "%-15s %-40s %-20s %-40s %-30s\n","KIND","NAME","NAMESPACE","RESOURCES","VERBS"print "--------------- ---------------------------------------- -------------------- ---------------------------------------- ------------------------------"}{printf "%-15s %-40s %-20s %-40s %-30s\n",$1,$2,$3,$4,$5}'
-
For each risky Role/ClusterRole, identify who uses it and why
- Run on: any machine with kubectl access
- For a ClusterRole:
CLUSTERROLE_NAME="<name-from-output>"kubectl get clusterrolebinding -A \--field-selector metadata.name=${CLUSTERROLE_NAME} -o yamlkubectl get clusterrolebinding -A -o json | jq -r \--arg cr "${CLUSTERROLE_NAME}" '.items[] | select(.roleRef.kind=="ClusterRole" and .roleRef.name==$cr)| {name:.metadata.name, namespace:(.metadata.namespace//"cluster-wide"), subjects:.subjects}'
- For a namespaced Role:
ROLE_NAME="<name-from-output>"ROLE_NAMESPACE="<namespace-from-output>"kubectl get rolebinding -n "${ROLE_NAMESPACE}" -o json | jq -r \--arg rn "${ROLE_NAME}" '.items[] | select(.roleRef.kind=="Role" and .roleRef.name==$rn)| {name:.metadata.name, subjects:.subjects}'
- Use this to decide if the subject truly needs bind/impersonate/escalate or could operate with lesser privileges (e.g., read/update only).
-
Narrow or remove risky verbs where not strictly required
- Run on: any machine with kubectl access
- Fetch the role for editing:
# ClusterRolekubectl get clusterrole "<name-from-output>" -o yaml > /tmp/clusterrole-risky.yaml# OR namespaced Rolekubectl get role "<name-from-output>" -n "<namespace-from-output>" -o yaml > /tmp/role-risky.yaml
- In the YAML file, for each rule containing
bind,impersonate, orescalate:- Remove those verbs entirely when they are not required, or
- Move them into a more restricted role intended only for a small set of trusted subjects.
- Apply the edited role:
# ClusterRolekubectl apply -f /tmp/clusterrole-risky.yaml# OR namespaced Rolekubectl apply -f /tmp/role-risky.yaml
-
Where risky verbs are necessary, scope access as tightly as possible
- Run on: any machine with kubectl access
- In the same YAML files:
- Replace
resources: ["*"]or broad resource sets with the minimum concrete resources (e.g.,["roles","rolebindings"]instead of["*"]). - If feasible, separate duties:
- One role with normal verbs (get/list/watch/create/update/delete) for day‑to‑day tasks.
- A distinct, rarely used, strongly controlled role with
bind/impersonate/escalate.
- Replace
- Re‑apply with
kubectl apply -fas in step 3.
-
Tighten bindings to trusted subjects only
- Run on: any machine with kubectl access
- For each RoleBinding/ClusterRoleBinding referencing a role that still uses any of these verbs:
- Export, edit, and re‑apply:
# ClusterRoleBindingkubectl get clusterrolebinding "<binding-name>" -o yaml > /tmp/crb-risky.yaml# RoleBindingkubectl get rolebinding "<binding-name>" -n "<namespace>" -o yaml > /tmp/rb-risky.yaml
- In the YAML, remove untrusted/unused subjects from
subjects:and keep only tightly controlled identities (e.g., a break‑glass admin group). - Apply:
kubectl apply -f /tmp/crb-risky.yaml# orkubectl apply -f /tmp/rb-risky.yaml
- Export, edit, and re‑apply:
-
Re‑run the audit to verify and document accepted exceptions
- Run on: any machine with kubectl access
- Verification command (same as step 1):
kubectl get clusterrole,role -A -o json | jq -r 'def risky_verbs: ["bind","impersonate","escalate"];.items[]| . as $r| [ $r.rules[]?| select((.verbs // [] | any(. as $v | $v == "bind" or $v == "impersonate" or $v == "escalate")))| {resources: ((.resources // ["*"]) | join(",")),verbs: ((.verbs // []) | map(select(IN("bind","impersonate","escalate"))) | join(","))}] as $matches| select($matches | length > 0)| [$r.kind,$r.metadata.name,($r.metadata.namespace // "cluster-wide"),($matches | map(.resources) | unique | join(",")),($matches | map(.verbs) | unique | join(","))] | @tsv' | awk -F'\t' 'BEGIN{printf "%-15s %-40s %-20s %-40s %-30s\n","KIND","NAME","NAMESPACE","RESOURCES","VERBS"print "--------------- ---------------------------------------- -------------------- ---------------------------------------- ------------------------------"}{printf "%-15s %-40s %-20s %-40s %-30s\n",$1,$2,$3,$4,$5}'
- For any remaining entries, explicitly document why the risky verb is required, who owns it, and how access is controlled (break‑glass, approval workflow, etc.).
Using kubectl
# 1) List all Roles/ClusterRoles that use bind/impersonate/escalate (from any machine with kubectl access)
kubectl get clusterrole,role -A -o json | jq -r '
def risky_verbs: ["bind","impersonate","escalate"];
.items[]
| . as $r
| [ $r.rules[]?
| select(
(.verbs // [] | any(. as $v | $v == "bind" or $v == "impersonate" or $v == "escalate"))
)
| {
resources: ((.resources // ["*"]) | join(",")),
verbs: ((.verbs // []) | map(select(IN("bind","impersonate","escalate"))) | join(","))
}
] as $matches
| select($matches | length > 0)
| [
$r.kind,
$r.metadata.name,
($r.metadata.namespace // "cluster-wide"),
($matches | map(.resources) | unique | join(",")),
($matches | map(.verbs) | unique | join(","))
] | @tsv
' | awk -F'\t' 'BEGIN{
printf "%-15s %-40s %-20s %-40s %-30s\n","KIND","NAME","NAMESPACE","RESOURCES","VERBS"
print "--------------- ---------------------------------------- -------------------- ---------------------------------------- ------------------------------"
}{
printf "%-15s %-40s %-20s %-40s %-30s\n",$1,$2,$3,$4,$5
}'
Problem indication:
- Any line in this table is a role that uses at least one of:
bind,impersonate, orescalate. - Treat these as potentially risky and review each role for necessity and scope.
# 2) For each suspicious ClusterRole, inspect full rules
# Example for a cluster role named "example-clusterrole"
kubectl get clusterrole example-clusterrole -o yaml
Problem indication in the YAML:
- Rules where
verbsincludesbind,impersonate, orescalate, especially when:resources: ["*"]or very broad resources are present.apiGroups: ["*"]or cross-namespace/global impact is visible.- There is no clear, tightly scoped operational need.
# 3) For each suspicious namespaced Role, inspect full rules
# Example for a role named "example-role" in namespace "example-namespace"
kubectl get role example-role -n example-namespace -o yaml
Same problem indicators as above, but scoped to a namespace.
# 4) See who is bound to a given risky ClusterRole
# Example for "example-clusterrole"
kubectl get clusterrolebinding -o wide | grep 'example-clusterrole' || true
kubectl get clusterrolebinding -o yaml | grep -A5 'name: example-clusterrole'
Problem indication:
ClusterRoleBindingsubjects that are:- Broad groups (e.g.,
system:authenticated,system:serviceaccounts, wildcard-like SSO groups). - Service accounts in default or shared namespaces that many workloads can use.
- Human users/groups that do not need role-binding, impersonation, or escalation capabilities.
- Broad groups (e.g.,
# 5) For a risky namespaced Role, see who is bound to it
# Example role "example-role" in "example-namespace"
kubectl get rolebinding -n example-namespace -o wide | grep 'example-role' || true
kubectl get rolebinding -n example-namespace -o yaml | grep -A5 'name: example-role'
Problem indication:
- RoleBindings that grant these verbs to:
- Many service accounts or all service accounts in a namespace.
- Shared or default service accounts.
- Broad user groups where only a few operators should have the capability.
# 6) Verify after any changes (re-run audit)
kubectl get clusterrole,role -A -o json | jq -r '
def risky_verbs: ["bind","impersonate","escalate"];
.items[]
| . as $r
| [ $r.rules[]?
| select(
(.verbs // [] | any(. as $v | $v == "bind" or $v == "impersonate" or $v == "escalate"))
)
| {
resources: ((.resources // ["*"]) | join(",")),
verbs: ((.verbs // []) | map(select(IN("bind","impersonate","escalate"))) | join(","))
}
] as $matches
| select($matches | length > 0)
| [
$r.kind,
$r.metadata.name,
($r.metadata.namespace // "cluster-wide"),
($matches | map(.resources) | unique | join(",")),
($matches | map(.verbs) | unique | join(","))
] | @tsv
' | awk -F'\t' 'BEGIN{
printf "%-15s %-40s %-20s %-40s %-30s\n","KIND","NAME","NAMESPACE","RESOURCES","VERBS"
print "--------------- ---------------------------------------- -------------------- ---------------------------------------- ------------------------------"
}{
printf "%-15s %-40s %-20s %-40s %-30s\n",$1,$2,$3,$4,$5
}'
Verification indication:
- You must still manually assess necessity, but a reduction in rows or narrowed resources/subjects shows progress in limiting
bind,impersonate, andescalateusage.
Automation
#!/usr/bin/env bash
# Report ClusterRoles/Roles using bind, impersonate, or escalate
set -euo pipefail
# REQUIREMENT: run on any machine with kubectl access and correct KUBECONFIG
echo "[INFO] Scanning ClusterRoles and Roles for bind/impersonate/escalate verbs..."
echo
kubectl get clusterrole,role -A -o json | jq -r '
def risky_verbs: ["bind","impersonate","escalate"];
.items[]
| . as $r
| [ $r.rules[]?
| select(
(.verbs // [] | any(. as $v | $v == "bind" or $v == "impersonate" or $v == "escalate"))
)
| {
resources: ((.resources // ["*"]) | join(",")),
verbs: ((.verbs // []) | map(select(IN("bind","impersonate","escalate"))) | join(","))
}
] as $matches
| select($matches | length > 0)
| [
$r.kind,
$r.metadata.name,
($r.metadata.namespace // "cluster-wide"),
($matches | map(.resources) | unique | join(",")),
($matches | map(.verbs) | unique | join(","))
] | @tsv
' | awk -F'\t' 'BEGIN{
printf "%-15s %-40s %-20s %-40s %-30s\n","KIND","NAME","NAMESPACE","RESOURCES","VERBS"
print "--------------- ---------------------------------------- -------------------- ---------------------------------------- ------------------------------"
}{
printf "%-15s %-40s %-20s %-40s %-30s\n",$1,$2,$3,$4,$5
}'
echo
echo "[INFO] Detailed JSON for review (who can use these roles):"
echo
# For each risky role, show bindings and subject details
kubectl get clusterrole,role -A -o json | jq -r '
def risky_verbs: ["bind","impersonate","escalate"];
.items[]
| . as $r
| [ $r.rules[]?
| select(
(.verbs // [] | any(. as $v | $v == "bind" or $v == "impersonate" or $v == "escalate"))
)
] as $matches
| select($matches | length > 0)
| {
kind: .kind,
name: .metadata.name,
namespace: (.metadata.namespace // "cluster-wide"),
rules: $matches
}
' | jq -s '
. as $risky
| {
riskyRoles: $risky,
roleBindings: (
[
(kubectl get rolebinding -A -o json | .items[] | . as $b | {
bindingKind: "RoleBinding",
bindingName: .metadata.name,
bindingNamespace: .metadata.namespace,
roleRefKind: .roleRef.kind,
roleRefName: .roleRef.name,
subjects: (.subjects // [])
}),
(kubectl get clusterrolebinding -o json | .items[] | . as $b | {
bindingKind: "ClusterRoleBinding",
bindingName: .metadata.name,
bindingNamespace: "cluster-wide",
roleRefKind: .roleRef.kind,
roleRefName: .roleRef.name,
subjects: (.subjects // [])
})
] | add
)
}
| .riskyRoles[]
| . as $rr
| {
kind: $rr.kind,
name: $rr.name,
namespace: $rr.namespace,
rules: $rr.rules,
bindings: (
. as $dummy
| $ENV.roleBindings
)
}
' roleBindings="$(kubectl get rolebinding -A -o json; kubectl get clusterrolebinding -o json)" 2>/dev/null || {
echo "[WARN] Could not build detailed role-to-subject mapping; inspect bindings manually."
}
How to interpret the output
- The first table lists every
RoleorClusterRolethat uses any of the risky verbs inVERBS(one or more ofbind,impersonate,escalate) and whichRESOURCESthey apply to. - Any line in this table indicates a potential problem and must be manually reviewed:
- Confirm whether that role truly needs the listed verb(s).
- If not strictly required, plan to remove the verb(s) from that role’s rules.
- The JSON section (if it succeeds) is for deeper analysis: it links each risky role to bindings and subjects. Any subject bound to these roles is a candidate for privilege reduction.