Skip to main content

Minimize Wildcard Use In Roles And ClusterRoles

More Info:

Wildcards in Roles and ClusterRoles grant unpredictable and often excessive permissions. Replace wildcards with explicit resources and verbs to enforce least privilege.

Risk Level

Critical

Address

Security

Compliance Standards

  • CIS OKE

Triage and Remediation

Remediation

Manual Steps
  1. List all Roles and ClusterRoles that use 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 --all-namespaces -o json | jq -r '
    .items[]
    | select(.rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*"))
    | "\(.metadata.namespace)/\(.metadata.name)"
    ' | sort -u
  2. Inspect each wildcarded Role/ClusterRole in detail

    • For each name from step 1, view the full spec:
    # ClusterRole example
    kubectl get clusterrole <clusterrole-name> -o yaml

    # Role example
    kubectl get role -n <namespace> <role-name> -o yaml
    • Record for each rule:
      • Which fields use * (verbs, resources, apiGroups, resourceNames, nonResourceURLs)
      • Which subjects are bound (via RoleBindings/ClusterRoleBindings).
  3. Determine intended access and justify or reject each wildcard
    For each Role/ClusterRole:

    • Identify business/operational purpose (who/what uses it, for what tasks).
      # Show bindings that use a ClusterRole
      kubectl get clusterrolebindings -o yaml | grep -A5 "name: <clusterrole-name>"

      # Show bindings that use a Role
      kubectl get rolebindings --all-namespaces -o yaml | grep -A5 "name: <role-name>"
    • With application owners / operators, decide for each wildcard:
      • Is the role truly generic/admin (e.g. cluster-admin) and intentionally broad? If yes, document the justification and leave as-is.
      • Otherwise, enumerate the specific resources and verbs actually needed.
  4. Design least-privilege replacement rules (on paper or in a draft file)
    For each wildcarded rule you plan to tighten:

    • Replace verbs: ["*"] with an explicit list (e.g. ["get","list","watch"] for read-only, or add create, update, etc. only if required).
    • Replace resources: ["*"] with only required resources per API group (e.g. ["pods","deployments","configmaps"]).
    • Replace apiGroups: ["*"] with specific groups (e.g. ["","apps","batch"]).
    • Save the revised spec to a file for review, e.g.:
      kubectl get clusterrole <clusterrole-name> -o yaml > /tmp/<clusterrole-name>.yaml
      # edit /tmp/<clusterrole-name>.yaml to remove wildcards and set explicit verbs/resources/apiGroups
  5. Apply tightened Roles/ClusterRoles carefully and validate workloads

    • After peer review/change control, apply the edited objects:
      kubectl apply -f /tmp/<clusterrole-name>.yaml
      # or for a Role
      kubectl apply -f /tmp/<namespace>-<role-name>.yaml
    • Coordinate with owners to run smoke tests for affected users/service accounts to confirm required operations still succeed and no critical functionality broke.
  6. Re-verify that wildcards are minimized

    • Re-run the discovery from step 1 to confirm only justified wildcarded Roles/ClusterRoles remain:
    kubectl get clusterroles -o json | jq -r '
    .items[]
    | select(.rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*"))
    | .metadata.name
    ' | sort -u

    kubectl get roles --all-namespaces -o json | jq -r '
    .items[]
    | select(.rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*"))
    | "\(.metadata.namespace)/\(.metadata.name)"
    ' | sort -u
    • For any remaining wildcard use, ensure there is a written justification (e.g. break-glass admin, temporary migration) and a plan/date to revisit if appropriate.
Using kubectl
# 1) List all ClusterRoles that contain any '*' wildcard
# Run on: any machine with kubectl access
kubectl get clusterroles -o json \
| jq -r '
.items[]
| select(
(.rules[]?.verbs[]? == "*" )
or (.rules[]?.resources[]? == "*" )
or (.rules[]?.apiGroups[]? == "*" )
or (.rules[]?.resourceNames[]? == "*" )
)
| .metadata.name
' | sort -u

Output to review:

  • Any name listed here is a ClusterRole that uses at least one wildcard and must be reviewed.

# 2) Inspect a specific ClusterRole in detail
# Replace CLUSTERROLE_NAME with a name from the previous command
kubectl get clusterrole CLUSTERROLE_NAME -o yaml

What indicates a problem:

  • In .rules:
    • verbs: ["*"] or verbs: - "*".
    • resources: ["*"] or resources: - "*".
    • apiGroups: ["*"] or apiGroups: - "*".
    • resourceNames: ["*"] or resourceNames: - "*".
  • Especially risky when combined, e.g.:
    • apiGroups: ["*"] and resources: ["*"] and verbs: ["*"] (effectively full admin).
    • Wildcards on sensitive resources like secrets, configmaps, roles, clusterroles, rolebindings, clusterrolebindings, or pods/exec.

You must decide, per ClusterRole:

  • Which resources it actually needs.
  • Which verbs are really required (e.g. get,list,watch vs create,update,patch,delete).
  • Whether wildcards can be replaced with explicit lists.

# 3) Find RoleBindings and ClusterRoleBindings that use a wildcard-heavy ClusterRole
# Replace CLUSTERROLE_NAME with the name under review
kubectl get clusterrolebindings -o wide \
| grep -E "(^NAME| CLUSTERROLE_NAME )"

kubectl get rolebindings --all-namespaces -o wide \
| grep -E "(^NAMESPACE| CLUSTERROLE_NAME )"

Output to review:

  • Which subjects (users, groups, service accounts) are granted the wildcarded ClusterRole.
  • Broader or more sensitive subjects (e.g. system:serviceaccounts, system:authenticated, production namespaces) indicate higher risk and increase the urgency to reduce wildcard use.

# 4) Quick cluster-wide overview of any wildcard usage in Roles (namespaced)
kubectl get roles --all-namespaces -o json \
| jq -r '
.items[]
| select(
(.rules[]?.verbs[]? == "*" )
or (.rules[]?.resources[]? == "*" )
or (.rules[]?.apiGroups[]? == "*" )
or (.rules[]?.resourceNames[]? == "*" )
)
| "\(.metadata.namespace)/\(.metadata.name)"
' | sort -u

Output to review:

  • Any namespace/name listed is a Role with wildcard usage; examine them with:
    kubectl get role -n NAMESPACE NAME -o yaml
  • The same indicators of problematic wildcards apply as for ClusterRoles.
Automation
#!/usr/bin/env bash
# Report Roles/ClusterRoles that use wildcards in rules.*
# Run on: any machine with kubectl access and current-context pointing at target cluster

set -euo pipefail

# You can change this to a specific namespace list if desired
NAMESPACE_SELECTOR="--all-namespaces"

echo "=== Checking ClusterRoles for wildcard usage ==="
kubectl get clusterroles -o json \
| jq -r '
.items[]
| {
kind,
name: .metadata.name,
rules: (
.rules[]
| select(
(.verbs[]? == "*" )
or (.resources[]? == "*" )
or (.apiGroups[]? == "*" )
or (.resourceNames[]? == "*" )
)
)
}
| select(.rules != null)
| "KIND: \(.kind)\nNAME: \(.name)\nOFFENDING_RULES:\n\(.rules | tojson)\n---"
'

echo
echo "=== Checking Namespaced Roles for wildcard usage ==="
kubectl get roles ${NAMESPACE_SELECTOR} -o json \
| jq -r '
.items[]
| {
kind,
name: .metadata.name,
namespace: .metadata.namespace,
rules: (
.rules[]
| select(
(.verbs[]? == "*" )
or (.resources[]? == "*" )
or (.apiGroups[]? == "*" )
or (.resourceNames[]? == "*" )
)
)
}
| select(.rules != null)
| "KIND: \(.kind)\nNAMESPACE: \(.namespace)\nNAME: \(.name)\nOFFENDING_RULES:\n\(.rules | tojson)\n---"
'

Explanation of output indicating a problem:

  • Any block printed by this script (separated by ---) represents a Role or ClusterRole that uses at least one wildcard in:
    • rules[].verbs (e.g., "*"),
    • rules[].resources (e.g., "*"),
    • rules[].apiGroups (e.g., "*"),
    • or rules[].resourceNames (e.g., "*").

Each such occurrence should be manually reviewed to determine whether you can replace the wildcard with a specific list of verbs, resources, API groups, or resource names to better enforce least privilege.