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.