Minimize Wildcard Use Roles And Clusterroles
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 AKS
- CIS Critical Security Controls v8
- 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
# ClusterRoles with any wildcardkubectl get clusterroles -o json | jq -r '.items[]| select(.rules[]?| (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*"))| .metadata.name' | sort -u# Roles with any wildcard (across all namespaces)kubectl get roles --all-namespaces -o json | jq -r '.items[]| select(.rules[]?| (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*"))| [.metadata.namespace, .metadata.name] | @tsv' | sort -
Review each identified Role/ClusterRole’s exact permissions and usage
- Run on: any machine with kubectl access
# Describe a ClusterRolekubectl describe clusterrole <clusterrole-name># Describe a Rolekubectl describe role -n <namespace> <role-name># (Optional) See which subjects are bound to a given ClusterRolekubectl get clusterrolebindings -o wide | grep -w '<clusterrole-name>' || true# (Optional) See which subjects are bound to a given Rolekubectl get rolebindings -A -o wide | grep -w '<role-name>' || true- Decide for each:
- Who actually needs this access (service accounts, users, groups)?
- Is the wildcard needed for operations, or can permissions be narrowed?
-
Map required operations to specific verbs, resources, and apiGroups
- Run on: any machine with kubectl access (pure planning step)
- For each wildcarded entry, determine the minimal set:
- Replace
verbs: ["*"]with only needed verbs (e.g.get,list,watch,create,update,patch,delete). - Replace
resources: ["*"]with specific resources (e.g.pods,deployments,configmaps,secrets). - Replace
apiGroups: ["*"]with specific groups (e.g."",apps,batch,rbac.authorization.k8s.io).
- Replace
- Document these decisions per role so they are auditable.
-
Edit Roles and ClusterRoles to remove wildcards and apply least privilege
- Run on: any machine with kubectl access
# Edit a ClusterRolekubectl edit clusterrole <clusterrole-name># Edit a Rolekubectl edit role -n <namespace> <role-name>- In the
rules:section, replace*inverbs,resources, andapiGroupswith the minimal explicit lists from step 3. - Save and exit the editor to apply the changes.
- If these are managed by GitOps/IaC, make the same changes in the source manifests instead of (or in addition to) using
kubectl edit, then apply via your normal pipeline.
-
Validate that workloads still function with reduced permissions
- Run on: any machine with kubectl access
- For each changed role/clusterrole, coordinate with owners of affected workloads or users:
- Trigger typical operations (deploy, scale, read/write resources) to ensure no unexpected authorization failures.
- If you see
Forbiddenerrors, reassess and minimally add only the missing verbs/resources/apiGroups.
-
Re-run the discovery to confirm wildcards are eliminated or consciously accepted
- Run on: any machine with kubectl access
# Re-check for wildcards in ClusterRoleskubectl get clusterroles -o json | jq -r '.items[]| select(.rules[]?| (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*"))| .metadata.name' | sort -u# Re-check for wildcards in Roleskubectl get roles --all-namespaces -o json | jq -r '.items[]| select(.rules[]?| (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*"))| [.metadata.namespace, .metadata.name] | @tsv' | sort- Any remaining wildcard usage should be explicitly documented as an exception, with justification and periodic review.
Using kubectl
# 1) List all ClusterRoles that are using any wildcard
# Run on: any machine with kubectl access
kubectl get clusterroles -o jsonpath='{range .items[?(@.rules)]}{.metadata.name}{"\n"}{range .rules[*]}{.apiGroups}{" "}{.resources}{" "}{.verbs}{"\n"}{end}{"---\n"}{end}' \
| grep '\*'
Problem indication: Any line where apiGroups, resources, or verbs contains * shows a ClusterRole rule using a wildcard and needs review.
# 2) Show all ClusterRoles with their rules in a readable form
kubectl get clusterroles -o yaml > /tmp/clusterroles.yaml
Review /tmp/clusterroles.yaml and look for entries like:
rules:
- apiGroups: ["*"] # problem: wildcard apiGroups
resources: ["*"] # problem: wildcard resources
verbs: ["*"] # problem: wildcard verbs
Any * in these three fields is a potential least‑privilege issue and should be evaluated.
# 3) Focus review on non-system ClusterRoles (often most risky)
kubectl get clusterroles \
--no-headers \
-o custom-columns=NAME:.metadata.name \
| grep -vE '^(system:|cluster-admin$)' \
| xargs -I{} kubectl get clusterrole {} -o yaml > /tmp/clusterroles-non-system.yaml
Again, inspect /tmp/clusterroles-non-system.yaml for any * under:
rules[].apiGroupsrules[].resourcesrules[].verbs
Each wildcard found here requires human judgment: decide if it is strictly necessary or should be replaced with explicit values.
# 4) Optional: quickly see which non-system ClusterRoles have wildcard verbs
kubectl get clusterroles \
--no-headers \
-o custom-columns=NAME:.metadata.name \
| grep -vE '^(system:|cluster-admin$)' \
| xargs -I{} kubectl get clusterrole {} -o jsonpath='{.metadata.name}{" "}{range .rules[*]}{.verbs}{" "}{end}{"\n"}' \
| grep '\*'
Problem indication: Any listed ClusterRole name that has * in the verbs list has full verb access on at least some resources and should be reviewed for possible restriction.
Automation
#!/usr/bin/env bash
# Audit Roles and ClusterRoles for wildcard use in verbs, resources, or apiGroups.
# Run on any machine with kubectl access and current context pointing to the target cluster.
set -euo pipefail
echo "=== Wildcard check in ClusterRoles ==="
kubectl get clusterroles -o json \
| jq -r '
.items[]
| {kind, name: .metadata.name, rules: .rules}
| . as $role
| ($role.rules // [])
| map(
select(
(.verbs[]? | test("\\*")) or
(.resources[]? | test("\\*")) or
(.apiGroups[]? | test("\\*"))
)
)
| select(length > 0)
| $role.kind + " " + $role.name
' \
| sort | uniq
echo
echo "=== Wildcard check in Roles (all namespaces) ==="
kubectl get roles --all-namespaces -o json \
| jq -r '
.items[]
| {kind, namespace: .metadata.namespace, name: .metadata.name, rules: .rules}
| . as $role
| ($role.rules // [])
| map(
select(
(.verbs[]? | test("\\*")) or
(.resources[]? | test("\\*")) or
(.apiGroups[]? | test("\\*"))
)
)
| select(length > 0)
| $role.kind + " " + .namespace + "/" + .name
' \
| sort | uniq
cat <<'EOF'
Interpretation:
- Any line printed above represents a Role or ClusterRole that uses a wildcard (*)
in at least one of: verbs, resources, or apiGroups.
- Empty output for a section means no wildcard use was detected in that scope.
Next steps (manual review required):
1. For each listed ClusterRole:
- Inspect: kubectl get clusterrole <name> -o yaml
- Edit: kubectl edit clusterrole <name>
- Replace any '*' in verbs/resources/apiGroups with specific values.
2. For each listed Role:
- Inspect: kubectl get role -n <namespace> <name> -o yaml
- Edit: kubectl edit role -n <namespace> <name>
- Replace any '*' in verbs/resources/apiGroups with specific values.
Re-run this script after changes to confirm that only acceptable, well-justified
wildcard usages (if any) remain.
EOF