Skip to main content

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

Manual Steps
  1. List all Roles and ClusterRoles that use wildcards

    • Run on: any machine with kubectl access
    # ClusterRoles with any wildcard
    kubectl 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
  2. Review each identified Role/ClusterRole’s exact permissions and usage

    • Run on: any machine with kubectl access
    # Describe a ClusterRole
    kubectl describe clusterrole <clusterrole-name>

    # Describe a Role
    kubectl describe role -n <namespace> <role-name>

    # (Optional) See which subjects are bound to a given ClusterRole
    kubectl get clusterrolebindings -o wide | grep -w '<clusterrole-name>' || true

    # (Optional) See which subjects are bound to a given Role
    kubectl 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?
  3. 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).
    • Document these decisions per role so they are auditable.
  4. Edit Roles and ClusterRoles to remove wildcards and apply least privilege

    • Run on: any machine with kubectl access
    # Edit a ClusterRole
    kubectl edit clusterrole <clusterrole-name>

    # Edit a Role
    kubectl edit role -n <namespace> <role-name>
    • In the rules: section, replace * in verbs, resources, and apiGroups with 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.
  5. 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 Forbidden errors, reassess and minimally add only the missing verbs/resources/apiGroups.
  6. Re-run the discovery to confirm wildcards are eliminated or consciously accepted

    • Run on: any machine with kubectl access
    # Re-check for wildcards in ClusterRoles
    kubectl get clusterroles -o json | jq -r '
    .items[]
    | select(.rules[]?
    | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*"))
    | .metadata.name' | sort -u

    # Re-check for wildcards in Roles
    kubectl 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[].apiGroups
  • rules[].resources
  • rules[].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