> ## Documentation Index
> Fetch the complete documentation index at: https://cloudanix.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 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

* CIS Kubernetes

### Triage and Remediation

<Tabs>
  <Tab title="Remediation">
    ### Remediation

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. Identify all noncompliant Roles and ClusterRoles (run on any machine with kubectl access):
           ```bash theme={null}
           # Roles
           kubectl get roles --all-namespaces -o custom-columns=ROLE_NAMESPACE:.metadata.namespace,ROLE_NAME:.metadata.name --no-headers | \
           while read -r role_namespace role_name; do
             role_rules=$(kubectl get role -n "${role_namespace}" "${role_name}" -o=json | jq -c '.rules')
             if echo "${role_rules}" | grep -q "\[\"\*\"\]"; then
               echo "NONCOMPLIANT ROLE: ${role_namespace}/${role_name}"
               echo "  rules: ${role_rules}"
             fi
           done

           # ClusterRoles
           kubectl get clusterroles -o custom-columns=CLUSTERROLE_NAME:.metadata.name --no-headers | \
           while read -r clusterrole_name; do
             clusterrole_rules=$(kubectl get clusterrole "${clusterrole_name}" -o=json | jq -c '.rules')
             if echo "${clusterrole_rules}" | grep -q "\[\"\*\"\]"; then
               echo "NONCOMPLIANT CLUSTERROLE: ${clusterrole_name}"
               echo "  rules: ${clusterrole_rules}"
             fi
           done
           ```

        2. For each NONCOMPLIANT Role, review who uses it and what it truly needs (run on any machine with kubectl access):
           ```bash theme={null}
           # Example: inspect bindings for a given role
           kubectl get rolebindings --all-namespaces -o yaml | \
             grep -A5 "name: <ROLE_NAME>" | sed -n '1,10p'

           # Show full definition of the role
           kubectl get role -n <ROLE_NAMESPACE> <ROLE_NAME> -o yaml
           ```
           Decide, based on actual application requirements, which `resources`, `resourceNames`, and `verbs` are needed instead of `"*"`.

        3. Edit each NONCOMPLIANT Role to replace `"*"` with specific resources/verbs (run on any machine with kubectl access):
           ```bash theme={null}
           kubectl edit role -n <ROLE_NAMESPACE> <ROLE_NAME>
           ```
           In the editor, locate `rules:` and replace fields like:
           ```yaml theme={null}
           resources: ["*"]
           verbs: ["*"]
           apiGroups: ["*"]
           ```
           with the minimal specific lists required, for example:
           ```yaml theme={null}
           apiGroups: [""]
           resources: ["pods", "services"]
           verbs: ["get", "list", "watch"]
           ```
           Save and exit to apply the changes.

        4. For each NONCOMPLIANT ClusterRole, review usage and scope (run on any machine with kubectl access):
           ```bash theme={null}
           # See which subjects are bound to a ClusterRole
           kubectl get clusterrolebindings -o yaml | \
             grep -A5 "name: <CLUSTERROLE_NAME>" | sed -n '1,10p'

           # Show full definition
           kubectl get clusterrole <CLUSTERROLE_NAME> -o yaml
           ```
           Decide the minimal `apiGroups`, `resources`, `resourceNames`, and `verbs` needed instead of `"*"`.

        5. Edit each NONCOMPLIANT ClusterRole to remove wildcards where possible (run on any machine with kubectl access):
           ```bash theme={null}
           kubectl edit clusterrole <CLUSTERROLE_NAME>
           ```
           In the editor, under `rules:`, replace any `"*"` values with specific items as in step 3. If a particular wildcard is truly required (e.g., an administrative role), document the justification outside the manifest for security review.

        6. Verify that Roles and ClusterRoles no longer contain wildcard-only lists (run on any machine with kubectl access):
           ```bash theme={null}
           # Verify Roles
           kubectl get roles --all-namespaces -o custom-columns=ROLE_NAMESPACE:.metadata.namespace,ROLE_NAME:.metadata.name --no-headers | \
           while read -r role_namespace role_name; do
             role_rules=$(kubectl get role -n "${role_namespace}" "${role_name}" -o=json | jq -c '.rules')
             if echo "${role_rules}" | grep -q "\[\"\*\"\]"; then
               echo "STILL NONCOMPLIANT ROLE: ${role_namespace}/${role_name}"
             fi
           done

           # Verify ClusterRoles
           kubectl get clusterroles -o custom-columns=CLUSTERROLE_NAME:.metadata.name --no-headers | \
           while read -r clusterrole_name; do
             clusterrole_rules=$(kubectl get clusterrole "${clusterrole_name}" -o=json | jq -c '.rules')
             if echo "${clusterrole_rules}" | grep -q "\[\"\*\"\]"; then
               echo "STILL NONCOMPLIANT CLUSTERROLE: ${clusterrole_name}"
             fi
           done
           ```
           The configuration is compliant when no Roles or ClusterRoles you intend to harden are reported as still noncompliant.
      </Accordion>

      <Accordion title="Using kubectl">
        On any machine with kubectl access:

        1. Identify the non‑compliant Roles and ClusterRoles

        ```bash theme={null}
        # Roles with wildcards
        kubectl get roles --all-namespaces -o json | jq -r '
          .items[]
          | select(.rules[]? | tostring | test("\\[\"\\*\"\\]"))
          | "\(.metadata.namespace) \(.metadata.name)"
        '

        # ClusterRoles with wildcards
        kubectl get clusterroles -o json | jq -r '
          .items[]
          | select(.rules[]? | tostring | test("\\[\"\\*\"\\]"))
          | .metadata.name
        '
        ```

        2. Export each non‑compliant object and edit it locally to remove `"*"` and replace with the minimum required verbs/resources (this is a manual, least‑privilege design decision):

        ```bash theme={null}
        # Example: export a Role
        kubectl get role -n NAMESPACE ROLE_NAME -o yaml > role-ROLE_NAME.yaml

        # Example: export a ClusterRole
        kubectl get clusterrole CLUSTERROLE_NAME -o yaml > clusterrole-CLUSTERROLE_NAME.yaml
        ```

        3. In each exported YAML:

        * For `rules[].verbs`, replace `- "*" ` with explicit verbs, e.g.:

        ```yaml theme={null}
        rules:
          - apiGroups: [""]
            resources:
              - pods
            verbs:
              - get
              - list
              - watch
        ```

        * For `rules[].resources`, replace `- "*" ` with explicit resources, e.g.:

        ```yaml theme={null}
        rules:
          - apiGroups: ["apps"]
            resources:
              - deployments
              - statefulsets
            verbs:
              - get
              - list
              - watch
              - update
        ```

        * For `rules[].apiGroups` / `rules[].resourceNames`, similarly avoid `"*"` and specify concrete values when possible.

        4. Apply the edited manifests back to the cluster

        ```bash theme={null}
        # Role
        kubectl apply -f role-ROLE_NAME.yaml

        # ClusterRole
        kubectl apply -f clusterrole-CLUSTERROLE_NAME.yaml
        ```

        Repeat for each affected Role and ClusterRole.

        5. Verification

        Re‑run the audit and confirm all `role_is_compliant` and `clusterrole_is_compliant` values are `true`:

        ```bash theme={null}
        # Roles
        kubectl get roles --all-namespaces -o custom-columns=ROLE_NAMESPACE:.metadata.namespace,ROLE_NAME:.metadata.name --no-headers | while read -r role_namespace role_name
        do
          role_rules=$(kubectl get role -n "${role_namespace}" "${role_name}" -o=json | jq -c '.rules')
          if echo "${role_rules}" | grep -q "\[\"\*\"\]"; then
            role_is_compliant="false"
          else
            role_is_compliant="true"
          fi
          echo "**role_name: ${role_name} role_namespace: ${role_namespace} role_rules: ${role_rules} role_is_compliant: ${role_is_compliant}"
        done

        # ClusterRoles
        kubectl get clusterroles -o custom-columns=CLUSTERROLE_NAME:.metadata.name --no-headers | while read -r clusterrole_name
        do
          clusterrole_rules=$(kubectl get clusterrole "${clusterrole_name}" -o=json | jq -c '.rules')
          if echo "${clusterrole_rules}" | grep -q "\[\"\*\"\]"; then
            clusterrole_is_compliant="false"
          else
            clusterrole_is_compliant="true"
          fi
          echo "**clusterrole_name: ${clusterrole_name} clusterrole_rules: ${clusterrole_rules} clusterrole_is_compliant: ${clusterrole_is_compliant}"
        done
        ```
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Purpose:
        #   Report and interactively remediate wildcard ("*") usage in Roles and ClusterRoles.
        #   This script does NOT auto-decide replacements; an operator must choose specific
        #   verbs/resources/fields per case, as required by the benchmark (MANUAL).
        #
        # Usage:
        #   Run on any machine with kubectl and jq installed and a kubeconfig context to the cluster.
        #
        #   ./minimize-wildcards-rbac.sh
        #
        # Behavior:
        #   - Lists all Roles and ClusterRoles that contain ["*"] in .rules.
        #   - For each, prompts whether you want to edit it manually (opens in editor).
        #   - After edits, re-checks and prints a compliance report.
        #   - Safe to re-run; already-clean objects are skipped automatically.
        #

        set -euo pipefail

        # Ensure required tools
        for bin in kubectl jq; do
          if ! command -v "$bin" >/dev/null 2>&1; then
            echo "ERROR: $bin is required but not found in PATH" >&2
            exit 1
          fi
        done

        EDITOR_CMD="${EDITOR:-vi}"

        echo "=== Scanning for wildcard usage in Roles and ClusterRoles ==="

        non_compliant_found=false

        ############################################
        # Function: scan_roles
        ############################################
        scan_roles() {
          echo
          echo "--- Checking Roles ---"
          kubectl get roles --all-namespaces -o json \
            | jq -r '.items[] | [.metadata.namespace, .metadata.name, (.rules // [])] | @base64' \
            | while read -r item_b64; do
                _jq() { echo "$item_b64" | base64 --decode | jq -r "$1"; }
                ns=$(_jq '.[0]')
                name=$(_jq '.[1]')
                rules_json=$(_jq '.[2]')

                if echo "$rules_json" | grep -q '\["\*"\]'; then
                  non_compliant_found=true
                  echo "NON-COMPLIANT Role: namespace=${ns} name=${name}"
                  echo "  Current rules snippet (truncated to 400 chars):"
                  echo "  $(echo "$rules_json" | head -c 400)"
                  echo

                  while true; do
                    read -r -p "Edit this Role now to replace \"*\" with specific values? [y/N]: " ans
                    ans=${ans:-N}
                    case "$ans" in
                      [yY])
                        # open in editor using kubectl edit; user must replace wildcards manually
                        kubectl edit role "$name" -n "$ns"
                        break
                        ;;
                      [nN])
                        echo "  Skipping edit for Role ${ns}/${name}"
                        break
                        ;;
                      *)
                        echo "  Please answer y or n."
                        ;;
                    esac
                  done
                fi
              done
        }

        ############################################
        # Function: scan_clusterroles
        ############################################
        scan_clusterroles() {
          echo
          echo "--- Checking ClusterRoles ---"
          kubectl get clusterroles -o json \
            | jq -r '.items[] | [.metadata.name, (.rules // [])] | @base64' \
            | while read -r item_b64; do
                _jq() { echo "$item_b64" | base64 --decode | jq -r "$1"; }
                name=$(_jq '.[0]')
                rules_json=$(_jq '.[1]')

                if echo "$rules_json" | grep -q '\["\*"\]'; then
                  non_compliant_found=true
                  echo "NON-COMPLIANT ClusterRole: name=${name}"
                  echo "  Current rules snippet (truncated to 400 chars):"
                  echo "  $(echo "$rules_json" | head -c 400)"
                  echo

                  while true; do
                    read -r -p "Edit this ClusterRole now to replace \"*\" with specific values? [y/N]: " ans
                    ans=${ans:-N}
                    case "$ans" in
                      [yY])
                        kubectl edit clusterrole "$name"
                        break
                        ;;
                      [nN])
                        echo "  Skipping edit for ClusterRole ${name}"
                        break
                        ;;
                      *)
                        echo "  Please answer y or n."
                        ;;
                    esac
                  done
                fi
              done
        }

        scan_roles
        scan_clusterroles

        echo
        echo "=== Post-remediation verification (CIS-style) ==="

        # Verification for Roles
        echo
        echo "--- Verifying Roles ---"
        role_non_compliant=false
        kubectl get roles --all-namespaces -o custom-columns=ROLE_NAMESPACE:.metadata.namespace,ROLE_NAME:.metadata.name --no-headers \
          | while read -r role_namespace role_name; do
              role_rules=$(kubectl get role -n "${role_namespace}" "${role_name}" -o=json | jq -c '.rules')
              if echo "${role_rules}" | grep -q '\["\*"\]'; then
                role_is_compliant="false"
                role_non_compliant=true
              else
                role_is_compliant="true"
              fi
              echo "**role_name: ${role_name} role_namespace: ${role_namespace} role_rules: ${role_rules} role_is_compliant: ${role_is_compliant}"
            done

        # Verification for ClusterRoles
        echo
        echo "--- Verifying ClusterRoles ---"
        clusterrole_non_compliant=false
        kubectl get clusterroles -o custom-columns=CLUSTERROLE_NAME:.metadata.name --no-headers \
          | while read -r clusterrole_name; do
              clusterrole_rules=$(kubectl get clusterrole "${clusterrole_name}" -o=json | jq -c '.rules')
              if echo "${clusterrole_rules}" | grep -q '\["\*"\]'; then
                clusterrole_is_compliant="false"
                clusterrole_non_compliant=true
              else
                clusterrole_is_compliant="true"
              fi
              echo "**clusterrole_name: ${clusterrole_name} clusterrole_rules: ${clusterrole_rules} clusterrole_is_compliant: ${clusterrole_is_compliant}"
            done

        echo
        echo "=== Summary ==="
        if $non_compliant_found; then
          echo "Some Roles or ClusterRoles contained wildcards. Review the verification output above:"
          echo "  - role_is_compliant / clusterrole_is_compliant should be \"true\""
          echo "  - If any are still \"false\", reopen them with:"
          echo "      kubectl edit role <name> -n <namespace>"
          echo "      kubectl edit clusterrole <name>"
        else
          echo "No Roles or ClusterRoles were found with wildcard-only entries [\"*\"]."
        fi
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
