Minimize Wildcard Use In Roles And Cluster Roles
More Info:
Where possible replace any use of wildcards in clusterroles and roles with specific objects or actions.
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 OKE
- 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 ClusterRoles and Roles using wildcards
- Run on: any machine with
kubectlaccess.
kubectl get clusterroles -o json | jq -r '.items[]| select(.rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*"))| .metadata.name' | sort -ukubectl get roles -A -o json | jq -r '.items[]| select(.rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*"))| [.metadata.namespace, .metadata.name] | @tsv' | sort -u - Run on: any machine with
-
Inspect each wildcarded role to understand its scope and usage
- For each ClusterRole name from step 1:
kubectl get clusterrole <clusterrole-name> -o yamlkubectl get clusterrolebinding -o yaml \| yq '.items[] | select(.roleRef.kind=="ClusterRole" and .roleRef.name=="<clusterrole-name>")'
- For each Role (namespace, name) from step 1:
kubectl get role -n <namespace> <role-name> -o yamlkubectl get rolebinding -n <namespace> -o yaml \| yq '.items[] | select(.roleRef.kind=="Role" and .roleRef.name=="<role-name>")'
- Decide for each rule: which subjects (users/groups/serviceaccounts) actually require which resources and verbs.
- For each ClusterRole name from step 1:
-
Identify which wildcards can be safely restricted
- For each rule with
verbs: ["*"], list the minimum verbs really needed (e.g.get,list,watch,create,update,patch,delete). - For each rule with
resources: ["*"]orapiGroups: ["*"], enumerate the specific resources and API groups in use by the bound subjects’ workloads (from deployment manifests, operators’ docs, etc.). - Document any wildcard that is currently required (e.g. third‑party operators that explicitly need broad access) and justify it.
- For each rule with
-
Create or update least‑privilege role definitions
- For roles you can tighten, edit manifests locally (recommended) or directly via
kubectl edit. Example to export, edit, and apply:kubectl get clusterrole <clusterrole-name> -o yaml > /tmp/clusterrole-<clusterrole-name>.yaml - In the exported YAML, replace
*inverbs,resources, andapiGroupswith the specific values identified in step 3, keeping only rules actually required. - Apply the updated definitions:
kubectl apply -f /tmp/clusterrole-<clusterrole-name>.yaml
- For built‑in or vendor‑managed roles where direct modification is not appropriate, instead create new, more restrictive Roles/ClusterRoles and update corresponding RoleBindings/ClusterRoleBindings to reference them.
- For roles you can tighten, edit manifests locally (recommended) or directly via
-
Adjust bindings to avoid unnecessary exposure
- For any broad role that must remain wildcarded, ensure it is bound only to tightly scoped subjects:
kubectl get clusterrolebinding <binding-name> -o yamlkubectl get rolebinding -n <namespace> <binding-name> -o yaml
- Where feasible, replace bindings to wildcarded roles with bindings to your new least‑privilege roles created in step 4, then remove obsolete bindings:
kubectl delete clusterrolebinding <binding-name># orkubectl delete rolebinding -n <namespace> <binding-name>
- For any broad role that must remain wildcarded, ensure it is bound only to tightly scoped subjects:
-
Re‑verify and document accepted exceptions
- Re‑run the discovery commands from step 1 to confirm wildcard usage has been reduced to the minimum:
kubectl get clusterroles -o json | jq -r '.items[]| select(.rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*"))| .metadata.name' | sort -ukubectl get roles -A -o json | jq -r '.items[]| select(.rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*"))| [.metadata.namespace, .metadata.name] | @tsv' | sort -u
- For any remaining wildcarded rules, record the justification, owner, and a review date so that their necessity is periodically reassessed.
- Re‑run the discovery commands from step 1 to confirm wildcard usage has been reduced to the minimum:
Using kubectl
Using kubectl
Run these commands from any machine with kubectl access.
1. List ClusterRoles that use wildcards
kubectl get clusterroles -o json | jq -r '
.items[]
| select(
(.rules[]?.verbs[]? == "*" )
or (.rules[]?.resources[]? == "*" )
or (.rules[]?.apiGroups[]? == "*" )
or (.rules[]?.nonResourceURLs[]? == "*" )
)
| .metadata.name
' | sort -u
Problem indication: Any name in the output is a ClusterRole that uses at least one wildcard and needs human review.
To see full details for a specific ClusterRole:
kubectl get clusterrole <clusterrole-name> -o yaml
In the YAML, look for:
verbs: ["*"]orverbs: - "*"resources: ["*"]orresources: - "*"apiGroups: ["*"]orapiGroups: - "*"nonResourceURLs: ["*"]ornonResourceURLs: - "*"
These indicate broad permissions that should be evaluated and, where possible, replaced with specific values.
2. List Namespaced Roles that use wildcards
kubectl get roles --all-namespaces -o json | jq -r '
.items[]
| select(
(.rules[]?.verbs[]? == "*" )
or (.rules[]?.resources[]? == "*" )
or (.rules[]?.apiGroups[]? == "*" )
or (.rules[]?.nonResourceURLs[]? == "*" )
)
| "\(.metadata.namespace)/\(.metadata.name)"
' | sort -u
Problem indication: Any namespace/name in the output is a Role that uses at least one wildcard and needs human review.
View a specific Role:
kubectl get role <role-name> -n <namespace> -o yaml
Review the same fields (verbs, resources, apiGroups, nonResourceURLs) for * as above.
3. Check which subjects are using risky roles
For each identified ClusterRole:
kubectl get clusterrolebindings -o yaml | \
yq '.items[] | select(.roleRef.kind == "ClusterRole" and .roleRef.name == "<clusterrole-name>")'
For each identified Role:
kubectl get rolebindings --all-namespaces -o yaml | \
yq '.items[] | select(.roleRef.kind == "Role" and .roleRef.name == "<role-name>")'
Problem indication: Bindings that attach wildcard-heavy roles to:
system:serviceaccounts(all service accounts),- Broad groups like
system:authenticated, - User or group identities that don’t clearly require cluster‑wide power,
are higher risk and are priority candidates for tightening.
4. Re-verify after manual changes
After you manually edit and apply updated Role/ClusterRole manifests, re-run:
kubectl get clusterroles -o json | jq -r '
.items[]
| select(
(.rules[]?.verbs[]? == "*" )
or (.rules[]?.resources[]? == "*" )
or (.rules[]?.apiGroups[]? == "*" )
or (.rules[]?.nonResourceURLs[]? == "*" )
)
| .metadata.name
' | sort -u
and
kubectl get roles --all-namespaces -o json | jq -r '
.items[]
| select(
(.rules[]?.verbs[]? == "*" )
or (.rules[]?.resources[]? == "*" )
or (.rules[]?.apiGroups[]? == "*" )
or (.rules[]?.nonResourceURLs[]? == "*" )
)
| "\(.metadata.namespace)/\(.metadata.name)"
' | sort -u
Any remaining entries still require human judgement on whether the wildcard is strictly necessary.
Automation
#!/usr/bin/env bash
# Report wildcard use in Roles and ClusterRoles
# Run on: any machine with kubectl access and current context set
set -euo pipefail
echo "Scanning ClusterRoles for wildcard use..."
kubectl get clusterroles -o json | jq -r '
.items[]
| {
kind,
name: .metadata.name,
rules: (
.rules[]?
| select(
(.verbs[]? == "*" )
or (.apiGroups[]? == "*")
or (.resources[]? == "*")
or (.resourceNames[]? == "*")
or (.nonResourceURLs[]? == "*" or .nonResourceURLs[]? == "/*")
)
)
}
| select(.rules != null)
| "KIND:\(.kind)\nNAME:\(.name)\nWILDCARD_RULES:\n\(.rules | tojson)\n---"
'
echo
echo "Scanning Roles for wildcard use in all namespaces..."
kubectl get roles --all-namespaces -o json | jq -r '
.items[]
| {
kind,
namespace: .metadata.namespace,
name: .metadata.name,
rules: (
.rules[]?
| select(
(.verbs[]? == "*" )
or (.apiGroups[]? == "*")
or (.resources[]? == "*")
or (.resourceNames[]? == "*")
or (.nonResourceURLs[]? == "*" or .nonResourceURLs[]? == "/*")
)
)
}
| select(.rules != null)
| "KIND:\(.kind)\nNAMESPACE:\(.namespace)\nNAME:\(.name)\nWILDCARD_RULES:\n\(.rules | tojson)\n---"
'
Explanation of output indicating a problem:
- Any printed block indicates a Role or ClusterRole that uses one or more wildcards and should be reviewed.
- Fields to look at in each
WILDCARD_RULESentry:verbscontaining"*"→ overly broad actions.apiGroupscontaining"*"→ all API groups allowed.resourcescontaining"*"→ all resources in that API group allowed.resourceNamescontaining"*"→ all resource instances allowed.nonResourceURLscontaining"*"or"/*"→ all non-resource endpoints allowed.
- Roles/ClusterRoles not shown by the script have no wildcard entries and are not in scope for this finding.