Minimize Wildcard Use In Roles And ClusterRoles
More Info:
Wildcards in RBAC rules grant access to all resources or verbs, effectively broad privilege. Replace them with explicit resources and actions.
Risk Level
Critical
Address
Security
Compliance Standards
- CIS Kubernetes
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
Identify ClusterRoles using wildcards (any machine with kubectl access)
kubectl get clusterroles -o name | while read -r cr; dorules=$(kubectl get "$cr" -o json | jq -c '.rules')if echo "$rules" | grep -q '\["\*"\]'; thenecho "$cr uses wildcards:"echo "$rules"echofidone -
For each non-system ClusterRole using wildcards, export its definition for review (any machine with kubectl access)
# example for one ClusterRole; repeat for each affected ClusterRolekubectl get clusterrole <clusterrole-name> -o yaml > /tmp/clusterrole-<clusterrole-name>.yaml -
Manually analyze required permissions and replace wildcards (manual review)
- Consult application/team owners to determine the minimum set of:
apiGroupsactually needed (e.g."",apps,batch,rbac.authorization.k8s.io)resourcesactually used (e.g.pods,deployments,secrets,configmaps,cronjobs)verbsactually required (e.g.get,list,watch,create,update,patch,delete)
- In each exported YAML under
.rules:- Replace
apiGroups: ["*"]with an explicit list of required API groups. - Replace
resources: ["*"]with an explicit list of required resources. - Replace
verbs: ["*"]with an explicit list of required verbs.
- Replace
- Do not modify Kubernetes-critical or provider-managed ClusterRoles (e.g. those starting with
system:,eks:,gke-,azure-, etc.) unless you fully understand the impact.
- Consult application/team owners to determine the minimum set of:
-
Apply the edited ClusterRole definitions back to the cluster (any machine with kubectl access)
# example for one ClusterRole; repeat for each edited filekubectl apply -f /tmp/clusterrole-<clusterrole-name>.yaml -
If necessary, split very broad ClusterRoles into multiple least-privilege roles (any machine with kubectl access)
- When different consumers need different subsets of permissions, create separate ClusterRoles:
# create from edited manifestkubectl apply -f /tmp/clusterrole-<new-name>.yaml
- Update existing ClusterRoleBindings or RoleBindings to point to the new, narrower ClusterRoles:
kubectl get clusterrolebindings --field-selector roleRef.name=<old-clusterrole> -o name# edit each binding to use the new ClusterRolekubectl edit clusterrolebinding <binding-name>
- When different consumers need different subsets of permissions, create separate ClusterRoles:
-
Verify no ClusterRoles still use wildcards (any machine with kubectl access)
kubectl get clusterroles -o custom-columns=CLUSTERROLE_NAME:.metadata.name --no-headers | while read -r clusterrole_namedoclusterrole_rules=$(kubectl get clusterrole "${clusterrole_name}" -o=json | jq -c '.rules')if echo "${clusterrole_rules}" | grep -q '\["\*"\]'; thenclusterrole_is_compliant="false"elseclusterrole_is_compliant="true"fiecho "**clusterrole_name: ${clusterrole_name} clusterrole_rules: ${clusterrole_rules} clusterrole_is_compliant: ${clusterrole_is_compliant}"done
Using kubectl
On any machine with kubectl access:
- Identify noncompliant ClusterRoles (those with
"*"in rules):
kubectl get clusterroles -o custom-columns=CLUSTERROLE_NAME:.metadata.name --no-headers | while read -r clusterrole_name
do
clusterrole_rules=$(kubectl get clusterrole "${clusterrole_name}" -o=json | jq -c '.rules')
if echo "${clusterrole_rules}" | grep -q "\[\"\*\"\]"; then
echo "${clusterrole_name}"
fi
done
- For each noncompliant ClusterRole, export the manifest for editing:
kubectl get clusterrole <CLUSTERROLE_NAME> -o yaml > /tmp/clusterrole-<CLUSTERROLE_NAME>.yaml
- Edit
/tmp/clusterrole-<CLUSTERROLE_NAME>.yamland replace wildcard entries with explicit resources/verbs. For example, change:
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
to something like (adjust to the minimal required permissions):
rules:
- apiGroups: [""]
resources: ["pods", "services"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch"]
Ensure no ["*"] remains in apiGroups, resources, verbs, resourceNames, or nonResourceURLs.
- Apply the updated ClusterRole:
kubectl apply -f /tmp/clusterrole-<CLUSTERROLE_NAME>.yaml
Repeat steps 2–4 for each affected ClusterRole.
- Verification (rerun check for ClusterRoles):
kubectl get clusterroles -o custom-columns=CLUSTERROLE_NAME:.metadata.name --no-headers | while read -r clusterrole_name
do
clusterrole_rules=$(kubectl get clusterrole "${clusterrole_name}" -o=json | jq -c '.rules')
if echo "${clusterrole_rules}" | grep -q "\[\"\*\"\]"; then
clusterrole_is_compliant="false"
else
clusterrole_is_compliant="true"
fi;
echo "**clusterrole_name: ${clusterrole_name} clusterrole_rules: ${clusterrole_rules} clusterrole_is_compliant: ${clusterrole_is_compliant}"
done
Automation
#!/usr/bin/env bash
# Purpose: Identify and interactively remediate wildcard (“*”) use in ClusterRoles.
# Scope: Run on any machine with kubectl access to the cluster.
# NOTE: This control is MANUAL. This script only helps you find and edit
# problematic ClusterRoles; it cannot safely choose replacements for "*".
set -euo pipefail
# REQUIREMENTS:
# - kubectl configured to point at the target cluster
# - jq installed
# CONFIGURATION:
EDITOR_CMD="${EDITOR:-kubectl neat 2>/dev/null || true; :}" # not actually used; edits go via kubectl edit
echo "=== Step 1: Discover ClusterRoles using wildcard [\"*\"] in rules ==="
noncompliant_clusterroles=()
while read -r clusterrole_name; do
# Skip empty lines
[[ -z "${clusterrole_name}" ]] && continue
rules_json="$(kubectl get clusterrole "${clusterrole_name}" -o=json | jq -c '.rules')"
if echo "${rules_json}" | grep -q '\["\*"\]'; then
noncompliant_clusterroles+=("${clusterrole_name}")
echo "NON-COMPLIANT: ${clusterrole_name}"
echo " rules: ${rules_json}"
fi
done < <(kubectl get clusterroles -o custom-columns=CLUSTERROLE_NAME:.metadata.name --no-headers)
if [ "${#noncompliant_clusterroles[@]}" -eq 0 ]; then
echo "No ClusterRoles with wildcard [\"*\"] in rules were found."
exit 0
fi
echo
echo "=== Step 2: Manual review & edit guidance ==="
echo "For each listed ClusterRole, you must:"
echo " 1) Determine which resources and verbs are actually required."
echo " 2) Replace any occurrence of \"*\" in:"
echo " - .rules[].verbs"
echo " - .rules[].resources"
echo " - .rules[].apiGroups"
echo " - .rules[].resourceNames"
echo " with explicit values (e.g. [\"get\",\"list\"] instead of [\"*\"],"
echo " or [\"pods\",\"configmaps\"] instead of [\"*\"])."
echo " 3) Avoid modifying system/provided ClusterRoles unless you fully"
echo " understand the impact; prefer creating a new, least-privilege role."
echo
echo "You will now be prompted to edit each non-compliant ClusterRole using:"
echo " kubectl edit clusterrole <name>"
echo
for cr in "${noncompliant_clusterroles[@]}"; do
echo "----- Editing ClusterRole: ${cr} -----"
echo "Current rules (JSON):"
kubectl get clusterrole "${cr}" -o=json | jq '.rules'
echo
read -r -p "Open this ClusterRole for editing now? [y/N]: " ans
case "${ans}" in
[yY][eE][sS]|[yY])
# This opens the resource in $EDITOR. User must manually replace "*" with explicit values.
kubectl edit clusterrole "${cr}"
;;
*)
echo "Skipping edit for ${cr}. It will remain NON-COMPLIANT until corrected."
;;
esac
echo
done
echo "=== Step 3: Re-run compliance check for ClusterRoles only ==="
clusterrole_noncompliant_after=0
while read -r clusterrole_name; do
[[ -z "${clusterrole_name}" ]] && continue
clusterrole_rules="$(kubectl get clusterrole "${clusterrole_name}" -o=json | jq -c '.rules')"
if echo "${clusterrole_rules}" | grep -q '\["\*"\]'; then
clusterrole_is_compliant="false"
clusterrole_noncompliant_after=$((clusterrole_noncompliant_after + 1))
else
clusterrole_is_compliant="true"
fi
echo "**clusterrole_name: ${clusterrole_name} clusterrole_rules: ${clusterrole_rules} clusterrole_is_compliant: ${clusterrole_is_compliant}"
done < <(kubectl get clusterroles -o custom-columns=CLUSTERROLE_NAME:.metadata.name --no-headers)
echo
if [ "${clusterrole_noncompliant_after}" -eq 0 ]; then
echo "Result: All ClusterRoles are now compliant with respect to wildcard [\"*\"] usage."
else
echo "Result: ${clusterrole_noncompliant_after} ClusterRole(s) still contain wildcard [\"*\"] in rules."
echo "Re-run this script after further manual remediation."
fi