Skip to main content

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​

Manual Steps
  1. List all ClusterRoles and Roles using wildcards

    • Run on: any machine with kubectl access.
    kubectl get clusterroles -o json | jq -r '
    .items[]
    | select(.rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*"))
    | .metadata.name
    ' | sort -u
    kubectl get roles -A -o json | jq -r '
    .items[]
    | select(.rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*"))
    | [.metadata.namespace, .metadata.name] | @tsv
    ' | sort -u
  2. Inspect each wildcarded role to understand its scope and usage

    • For each ClusterRole name from step 1:
      kubectl get clusterrole <clusterrole-name> -o yaml
      kubectl 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 yaml
      kubectl 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.
  3. 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: ["*"] or apiGroups: ["*"], 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.
  4. 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 * in verbs, resources, and apiGroups with 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.
  5. 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 yaml
      kubectl 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>
      # or
      kubectl delete rolebinding -n <namespace> <binding-name>
  6. 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 -u
      kubectl 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.
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: ["*"] or verbs: - "*"
  • resources: ["*"] or resources: - "*"
  • apiGroups: ["*"] or apiGroups: - "*"
  • nonResourceURLs: ["*"] or nonResourceURLs: - "*"

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_RULES entry:
    • verbs containing "*" → overly broad actions.
    • apiGroups containing "*" → all API groups allowed.
    • resources containing "*" → all resources in that API group allowed.
    • resourceNames containing "*" → all resource instances allowed.
    • nonResourceURLs containing "*" 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.