Minimize Wildcard Use Roles And Cluster Roles
More Info:
Kubernetes Roles and ClusterRoles provide access to resources based on sets of objects and actions that can be taken on those objects. It is possible to set either of these to be the wildcard * which matches all items.
Risk Level
Medium
Address
Security
Compliance Standards
- APRA CPS 234 (Australia)
- BSI C5 (Germany)
- Brazil LGPD
- CCPA / CPRA (California)
- CIS Critical Security Controls v8
- CIS EKS
- CMMC 2.0
- CSA Cloud Controls Matrix v4
- DPDPA
- Digital Operational Resilience Act (EU)
- Essential 8
- ISO/IEC 27017
- ISO/IEC 27018
- ISO/IEC 27701
- KSA PDPL
- MAS Technology Risk Management (Singapore)
- MITRE ATT&CK (Cloud)
- NIS2 Directive
- NIST SP 800-171
- NYDFS 23 NYCRR 500
- SWIFT Customer Security Controls Framework
- Sarbanes-Oxley IT General Controls
- Securities and Exchange Board of India (SEBI) - Cloud Security Adoption Framework
- UK NCSC Cyber Assessment Framework
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 '.items[] | select(.rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*")) | {kind, metadata: {name, namespace}, rules}' | lesskubectl get clusterroles -o json | jq '.items[] | select(.rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*")) | {kind, metadata: {name}, rules}' | less -
For each identified Role, export the definition for review/editing
- Run on: any machine with kubectl access
- Example for a namespaced Role (replace values as needed):
kubectl get role <role-name> -n <role-namespace> -o yaml > /tmp/role-<role-name>.yaml- Open the file in an editor and replace
*inrules[].verbs,rules[].resources, andrules[].apiGroupswith the minimal explicit lists required for that Role’s purpose (for example, replaceverbs: ["*"]withverbs: ["get","list","watch"], and similarly forresourcesandapiGroups).
-
For each identified ClusterRole, export the definition for review/editing
- Run on: any machine with kubectl access
- Example for a ClusterRole:
kubectl get clusterrole <clusterrole-name> -o yaml > /tmp/clusterrole-<clusterrole-name>.yaml- Edit the file to replace any
*inrules[].verbs,rules[].resources, andrules[].apiGroupswith the narrowest explicit sets needed. Be especially careful with default or system ClusterRoles that may be relied upon by the cluster or add-ons; if they are managed by the platform or an operator, prefer creating a new, custom ClusterRole instead of modifying the managed one.
-
(Optional but recommended) Create new, minimal roles instead of broadening existing system roles
- Run on: any machine with kubectl access
- If a system or shared ClusterRole currently uses wildcards, consider:
- Leaving the original ClusterRole unchanged.
- Creating a new, minimal ClusterRole in a separate manifest file with only the needed verbs, resources, and apiGroups.
- Updating RoleBindings/ClusterRoleBindings to point to the new minimal role instead of the wildcard-based one. For example, edit the binding:
and change thekubectl edit clusterrolebinding <binding-name>roleRef.nameto your new ClusterRole. Save and exit.
-
Apply the edited Role and ClusterRole manifests back to the cluster
- Run on: any machine with kubectl access
- For each edited Role file:
kubectl apply -f /tmp/role-<role-name>.yaml- For each edited ClusterRole file:
kubectl apply -f /tmp/clusterrole-<clusterrole-name>.yaml -
Verification: confirm that no wildcards remain in Roles or ClusterRoles
- 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
On any machine with kubectl access:
- Identify ClusterRoles using wildcards
kubectl get clusterroles -o json | jq '
.items[] | select(
.rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*")
) | .metadata.name' -r
- Inspect each offending ClusterRole
Replace
<clusterrole-name>with a name from the previous output:
kubectl get clusterrole <clusterrole-name> -o yaml > /tmp/clusterrole-<clusterrole-name>.yaml
- Edit the manifest to replace wildcards
Open the file and replace*inverbs,resources, andapiGroupswith explicit values appropriate for your use case, for example:
Before:
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
After (example – adjust to your needs):
rules:
- apiGroups: [""]
resources:
- pods
- pods/log
verbs:
- get
- list
- watch
- Apply the updated ClusterRole
kubectl apply -f /tmp/clusterrole-<clusterrole-name>.yaml
Repeat steps 2–4 for each ClusterRole listed in step 1.
- (If Roles are also affected) Repeat for Roles List Roles with wildcards:
kubectl get roles --all-namespaces -o json | jq '
.items[] | select(
.rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*")
) | "\(.metadata.namespace) \(.metadata.name)"' -r
Export, edit, and apply each Role similarly:
kubectl get role <role-name> -n <namespace> -o yaml > /tmp/role-<namespace>-<role-name>.yaml
kubectl apply -f /tmp/role-<namespace>-<role-name>.yaml
- Verification Run the benchmark audit logic again; if nothing is printed, wildcards are no longer present:
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 ]; then
echo "wildcards_present"
else
echo "no_wildcards_in_roles_or_clusterroles"
fi
Automation
#!/usr/bin/env bash
set -euo pipefail
# PURPOSE:
# Identify Roles and ClusterRoles that use wildcards ("*") in rules and
# export them for manual, least-privilege review, then verify the presence
# of remaining wildcards.
#
# This script does NOT auto-edit RBAC, because the correct non-wildcard verbs,
# resources and apiGroups are application‑specific and must be chosen by an
# administrator. It is safe to re-run.
# RUN ON: Any machine with kubectl access and jq installed.
timestamp="$(date +%Y%m%d-%H%M%S)"
outdir="rbac-wildcard-review-${timestamp}"
mkdir -p "${outdir}"
echo "=== Exporting Roles with wildcard usage for review into: ${outdir} ==="
# Roles with wildcards
kubectl get roles --all-namespaces -o json | \
jq '
.items[]
| select(
.rules[]? |
(.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*")
)
' > "${outdir}/roles-with-wildcards.json"
# ClusterRoles with wildcards
kubectl get clusterroles -o json | \
jq '
.items[]
| select(
.rules[]? |
(.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*")
)
' > "${outdir}/clusterroles-with-wildcards.json"
echo "=== Summary of objects using wildcards (for manual hardening) ==="
echo "Roles:"
jq -r '.[].metadata | "\(.namespace)/\(.name)"' "${outdir}/roles-with-wildcards.json" 2>/dev/null || echo " (none)"
echo "ClusterRoles:"
jq -r '.[].metadata.name' "${outdir}/clusterroles-with-wildcards.json" 2>/dev/null || echo " (none)"
cat <<'EOF'
NEXT STEPS (manual, per benchmark remediation):
1. For each Role or ClusterRole listed above, open it for editing, for example:
- Role:
kubectl -n <namespace> edit role <name>
- ClusterRole:
kubectl edit clusterrole <name>
2. In .rules[], replace any "*" in:
- verbs (e.g., ["get","list","watch"] instead of ["*"])
- resources (e.g., ["pods","deployments"] instead of ["*"])
- apiGroups (e.g., ["","apps"] instead of ["*"])
with the minimum specific values needed by the workloads.
3. Save and exit the editor to apply the updated RBAC objects.
This process is intentionally manual because the correct least-privilege set of
verbs/resources/apiGroups depends on your applications and policies.
EOF
echo
echo "=== Verification: checking for remaining wildcard usage (same logic as audit) ==="
wildcards=$(kubectl get roles --all-namespaces -o json | jq '
.items[] | select(
.rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*")
)' | wc -l | tr -d ' ')
wildcards_clusterroles=$(kubectl get clusterroles -o json | jq '
.items[] | select(
.rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*")
)' | wc -l | tr -d ' ')
total=$((wildcards + wildcards_clusterroles))
if [ "$total" -gt 0 ]; then
echo "wildcards_present: ${total} Role(s)/ClusterRole(s) still contain wildcards."
echo "Review and edit remaining items until this reports zero."
else
echo "No wildcard usage detected in Roles or ClusterRoles."
fi