Minimize Wildcard Use In Roles And ClusterRoles
More Info:
Wildcards in RBAC verbs, resources or apiGroups grant broad, hard-to-audit permissions. They should be replaced with explicit objects and actions.
Risk Level
Critical
Address
Security
Compliance Standards
- CIS GKE
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
List all Roles and ClusterRoles that use wildcards (run on any machine with kubectl access):
kubectl get roles --all-namespaces -o json | jq -r '.items[] |select(.rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*")) |"ROLE " + .metadata.namespace + "/" + .metadata.name'kubectl get clusterroles -o json | jq -r '.items[] |select(.rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*")) |"CLUSTERROLE " + .metadata.name' -
For each reported ClusterRole, export it to a manifest for review and editing (example for one ClusterRole named
example-clusterrole):kubectl get clusterrole example-clusterrole -o yaml > /tmp/example-clusterrole.yaml -
Manually review
/tmp/example-clusterrole.yamland replace wildcard entries with explicit values:- Replace
verbs: ["*"]or- "*"with an explicit verb list such as["get","list","watch","create","update","patch","delete"]as needed. - Replace
resources: ["*"]with only the required resource names, for example["pods","deployments"]. - Replace
apiGroups: ["*"]with the specific API groups needed, for example["","apps"]. - Remove any rule entries that are not actually required for the workloads using this ClusterRole.
- Replace
-
Apply the edited ClusterRole back to the cluster (example):
kubectl apply -f /tmp/example-clusterrole.yaml -
If any wildcard-bearing Role objects (namespaced) were reported, repeat steps 2–4 for those, substituting
kubectl get role -n <namespace> <name> -o yaml > /tmp/<name>.yamlandkubectl apply -f /tmp/<name>.yaml. -
Verification (run on any machine with kubectl access):
wildcards=$(kubectl get roles --all-namespaces -o json | jq '.items[] | select(.rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*"))' | wc -l)wildcards_clusterroles=$(kubectl get clusterroles -o json | jq '.items[] | select(.rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*"))' | wc -l)total=$((wildcards + wildcards_clusterroles))if [ "$total" -gt 0 ]; thenecho "wildcards_present"elseecho "no_wildcards_in_roles_or_clusterroles"fi
Using kubectl
This control is MANUAL. There is no one-shot kubectl fix, because each wildcard must be evaluated and replaced with explicit permissions case‑by‑case.
Below are practical review steps and kubectl commands to help you identify, inspect, and update ClusterRoles.
1. Identify ClusterRoles using wildcards
Run on: any machine with kubectl access.
kubectl get clusterroles -o json | jq '
.items[]
| select(
.rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*")
)
| .metadata.name' -r
Optionally, see full definitions:
kubectl get clusterroles -o json | jq '
.items[]
| select(
.rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*")
)'
2. Inspect an individual ClusterRole
Pick a ClusterRole name from the list and inspect it:
kubectl get clusterrole <CLUSTERROLE_NAME> -o yaml
Decision guidance during review:
- Is this a built‑in or system role?
- Names like
cluster-admin,system:*, or cloud‑provider managed roles often legitimately use wildcards and are relied upon by the platform. Avoid changing them unless you fully understand the impact.
- Names like
- Is this a custom role for an application or team?
- Prefer replacing
*inverbs,resources, orapiGroupswith just the specific items actually needed.
- Prefer replacing
- Is the role even used?
- Check ClusterRoleBindings to see if it’s bound to any subjects. If unused, consider deletion instead of tightening.
List bindings that use a given ClusterRole:
kubectl get clusterrolebindings -o json | jq '
.items[]
| select(.roleRef.kind=="ClusterRole" and .roleRef.name=="<CLUSTERROLE_NAME>")
| {name: .metadata.name, subjects: .subjects}'
3. Edit a ClusterRole to remove wildcards
Run on: any machine with kubectl access.
Interactive edit:
kubectl edit clusterrole <CLUSTERROLE_NAME>
In the opened YAML:
-
Replace
verbs: ["*"]orverbs: - "*"-
With an explicit list, e.g.:
verbs:- get- list- watch- create- update- patch- delete -
Choose only the verbs actually required by the workload.
-
-
Replace
resources: ["*"]orresources: - "*"-
With explicit resources, for example:
resources:- pods- pods/log- deployments- configmaps
-
-
Replace
apiGroups: ["*"]orapiGroups: - "*"-
With specific API groups, for example:
apiGroups:- ""- apps- batch
-
Repeat for each rule under rules: that uses *.
Declarative approach using manifests (preferred for GitOps/IaC):
-
Export the current role to a file:
kubectl get clusterrole <CLUSTERROLE_NAME> -o yaml > clusterrole-<CLUSTERROLE_NAME>.yaml -
Edit the file with your editor, replacing
*as described above. -
Apply the updated manifest:
kubectl apply -f clusterrole-<CLUSTERROLE_NAME>.yaml
Operational impact: tightening a ClusterRole can break workloads or tooling that previously relied on broad access. After each change, confirm that affected applications and users still function as expected.
4. Optionally remove unused overly‑broad ClusterRoles
If you confirmed a ClusterRole has no bindings and is not needed:
kubectl delete clusterrole <CLUSTERROLE_NAME>
5. Verification
Re-run the audit for ClusterRoles to confirm wildcard usage has been eliminated or intentionally minimized:
wildcards_clusterroles=$(kubectl get clusterroles -o json | jq '
.items[] | select(
.rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*")
)' | wc -l)
echo "clusterroles_with_wildcards=${wildcards_clusterroles}"
You can also list remaining offending ClusterRoles by name:
kubectl get clusterroles -o json | jq '
.items[]
| select(
.rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*")
)
| .metadata.name' -r
Automation
#!/usr/bin/env bash
#
# Purpose:
# Assist review of wildcard use in ClusterRoles by exporting and listing
# them for manual editing, then verifying reduction of wildcards.
#
# Scope:
# Run on any machine with kubectl access to the cluster.
#
# NOTES:
# - This check is MANUAL in the benchmark: there is no safe, generic way
# to automatically replace "*" with specific verbs/resources/apiGroups.
# - This script does NOT change any RBAC objects. It only:
# * Identifies ClusterRoles using wildcards
# * Exports them into separate YAMLs for human review/edit
# * Helps you re-apply your edited manifests
# * Verifies wildcard usage afterwards
#
# Requirements:
# - kubectl installed and configured with sufficient permissions
# - jq installed
set -euo pipefail
OUT_DIR="${OUT_DIR:-./clusterrole-wildcards-$(date +%Y%m%d%H%M%S)}"
echo "[*] Detecting ClusterRoles that use wildcards in verbs, resources, or apiGroups..."
wildcards_clusterroles_json=$(kubectl get clusterroles -o json | jq '
.items[]
| select(
.rules[]?
| (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*")
)
')
if [[ -z "${wildcards_clusterroles_json}" ]]; then
echo "[*] No ClusterRoles with wildcard verbs/resources/apiGroups found."
exit 0
fi
mkdir -p "${OUT_DIR}"
echo "${wildcards_clusterroles_json}" | jq -r '.metadata.name' | sort -u > "${OUT_DIR}/clusterroles_with_wildcards.txt"
echo "[*] ClusterRoles with wildcards:"
cat "${OUT_DIR}/clusterroles_with_wildcards.txt"
echo
echo "[*] Exporting each affected ClusterRole to individual YAML manifests in: ${OUT_DIR}"
# Export each affected ClusterRole
while read -r cr_name; do
if [[ -z "${cr_name}" ]]; then
continue
fi
out_file="${OUT_DIR}/clusterrole-${cr_name}.yaml"
echo " - Exporting ClusterRole/${cr_name} -> ${out_file}"
kubectl get clusterrole "${cr_name}" -o yaml > "${out_file}"
done < "${OUT_DIR}/clusterroles_with_wildcards.txt"
cat <<'EOF'
[MANUAL ACTION REQUIRED]
1) Review each exported ClusterRole manifest in the output directory.
For each rule, where possible:
- Replace verbs: ["*"] with an explicit list, e.g. ["get","list","watch"]
- Replace resources: ["*"] with explicit resources, e.g. ["pods","deployments"]
- Replace apiGroups: ["*"] with only the required apiGroups, e.g. ["","apps"]
2) Save your edited YAML files.
3) To apply your edited ClusterRoles back to the cluster, run:
# Replace <OUT_DIR> with the directory printed above
kubectl apply -f <OUT_DIR>/
(You can safely re-run this command; it is idempotent.)
EOF
read -rp "[?] Have you already edited the manifests and applied them? [y/N]: " CONFIRM
CONFIRM=${CONFIRM:-n}
if [[ "${CONFIRM}" =~ ^[Yy]$ ]]; then
echo "[*] Verifying wildcard usage after your changes..."
# Re-run the wildcard detection, but scoped to the previously affected ClusterRoles
remaining=$(kubectl get clusterroles -o json | jq --argfile names "${OUT_DIR}/clusterroles_with_wildcards.txt" '
.items[]
| select(.metadata.name as $n | ($names | map(select(. == $n)) | length) > 0)
| select(
.rules[]?
| (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*")
)
| .metadata.name
' | sort -u || true)
if [[ -z "${remaining}" ]]; then
echo "[*] Verification passed: no wildcards remain in the previously flagged ClusterRoles."
else
echo "[!] Verification found remaining wildcards in these ClusterRoles:"
echo "${remaining}"
echo "[!] Please re-check these manifests and further restrict wildcard use where possible."
fi
else
echo "[*] Skipping verification because manifests have not been edited/applied yet."
echo "[*] After you apply your changes, you can re-run this script to re-check."
fi