> ## 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 In Roles And ClusterRoles

### More Info:

Wildcards in verbs, resources, or apiGroups grant overly broad permissions that violate least privilege. Replace them with explicitly scoped objects and actions.

### Risk Level

Critical

### Address

Security

### Compliance Standards

* CIS EKS

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. List Roles/ClusterRoles using wildcards (run on any machine with kubectl access):
           ```bash theme={null}
           kubectl get roles --all-namespaces -o json | jq '
             .items[] | select(
               .rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*")
             ) | {kind, metadata:{name,namespace}}'
           kubectl get clusterroles -o json | jq '
             .items[] | select(
               .rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*")
             ) | {kind, metadata:{name}}'
           ```

        2. For each offending Role/ClusterRole, export its definition for review/edit (example for a ClusterRole named `example-role`):
           ```bash theme={null}
           kubectl get clusterrole example-role -o yaml > /tmp/example-role.yaml
           # or for a namespaced Role
           kubectl get role example-role -n example-namespace -o yaml > /tmp/example-role.yaml
           ```

        3. Manually edit the exported file to replace wildcards with explicit values (run on the machine where the file is saved):
           * Replace `verbs: ["*"]` or `verbs: - "*"` with only the needed verbs, e.g.:
             ```yaml theme={null}
             verbs:
               - get
               - list
               - watch
             ```
           * Replace `resources: ["*"]` or `resources: - "*"` with specific resources, e.g.:
             ```yaml theme={null}
             resources:
               - pods
               - services
             ```
           * Replace `apiGroups: ["*"]` or `apiGroups: - "*"` with required API groups, e.g.:
             ```yaml theme={null}
             apiGroups:
               - ""
               - apps
             ```
           * Remove any rule entries that are not actually needed. Save the file.

        4. Apply the edited Role/ClusterRole back to the cluster (run on any machine with kubectl access):
           ```bash theme={null}
           kubectl apply -f /tmp/example-role.yaml
           ```

        5. If these objects are managed by GitOps or other IaC, update the source manifests similarly (edit the Role/ClusterRole definitions in your Git/IaC repo to match the changes above and run your usual deployment pipeline) to prevent them from being reverted.

        6. Verify no Roles/ClusterRoles still use wildcards (run on any machine with kubectl access):
           ```bash theme={null}
           wildcards=$(kubectl get roles --all-namespaces -o json | jq '
             .items[] | select(
               .rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*")
             )' | wc -l)

           wildcards_clusterroles=$(kubectl get clusterroles -o json | jq '
             .items[] | select(
               .rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*")
             )' | wc -l)

           total=$((wildcards + wildcards_clusterroles))
           if [ "$total" -eq 0 ]; then
             echo "no_wildcards_present"
           else
             echo "wildcards_present ($total)"
           fi
           ```
      </Accordion>

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

        1. Identify ClusterRoles using wildcards

        ```bash theme={null}
        kubectl get clusterroles -o json | jq -r '
          .items[]
          | select(
              .rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*")
            )
          | .metadata.name' \
        | sort -u
        ```

        For a single ClusterRole, inspect details:

        ```bash theme={null}
        kubectl get clusterrole <CLUSTERROLE_NAME> -o yaml
        ```

        2. Edit an existing ClusterRole to remove wildcards

        For each listed ClusterRole, replace `*` in `verbs`, `resources`, and `apiGroups` with explicit entries based on actual needs.

        Interactive edit:

        ```bash theme={null}
        kubectl edit clusterrole <CLUSTERROLE_NAME>
        ```

        Example change (illustrative only; adjust to your requirements):

        ```yaml theme={null}
        # BEFORE
        rules:
          - apiGroups: ["*"]
            resources: ["*"]
            verbs: ["*"]

        # AFTER
        rules:
          - apiGroups: [""]              # core API group
            resources:
              - pods
              - services
            verbs:
              - get
              - list
              - watch
          - apiGroups:
              - apps
            resources:
              - deployments
            verbs:
              - get
              - list
        ```

        Save and exit the editor to apply.

        3. Apply a declarative manifest (preferred for GitOps/IaC-managed roles)

        If your ClusterRole is managed via manifests, update the manifest and re-apply it instead of using `kubectl edit`.

        Example manifest snippet:

        ```yaml theme={null}
        apiVersion: rbac.authorization.k8s.io/v1
        kind: ClusterRole
        metadata:
          name: <CLUSTERROLE_NAME>
        rules:
          - apiGroups: [""]
            resources:
              - pods
              - configmaps
            verbs:
              - get
              - list
              - watch
        ```

        Apply:

        ```bash theme={null}
        kubectl apply -f <path-to-updated-clusterrole-manifest>.yaml
        ```

        Repeat for each ClusterRole using wildcards.

        4. Verification

        Re-run the wildcard check to confirm there are no remaining wildcards in Roles or ClusterRoles:

        ```bash theme={null}
        wildcards=$(kubectl get roles --all-namespaces -o json | jq '
          .items[] | select(
            .rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*")
          )' | wc -l)

        wildcards_clusterroles=$(kubectl get clusterroles -o json | jq '
          .items[] | select(
            .rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*")
          )' | wc -l)

        total=$((wildcards + wildcards_clusterroles))

        if [ "$total" -gt 0 ]; then
          echo "wildcards_present"
        else
          echo "no_wildcards_in_roles_or_clusterroles"
        fi
        ```
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        # Automation for CISEKS 4.1.3 – Minimize wildcard use in ClusterRoles and Roles
        # Run on: any machine with kubectl access and jq installed.
        # WARNING: This script CANNOT safely auto-resolve wildcards without human input.
        # It will:
        #   - Detect Roles/ClusterRoles using wildcards
        #   - Export them to YAML files for review
        #   - (Optionally) apply edited manifests
        #   - Re-run the audit to verify
        # This is safe to re-run; it only overwrites the export directory and reapplies your edited YAML.

        set -euo pipefail

        EXPORT_DIR="${EXPORT_DIR:-./rbac-wildcards-export}"
        TIMESTAMP="$(date +%Y%m%d-%H%M%S)"
        WORK_DIR="${EXPORT_DIR}/${TIMESTAMP}"

        mkdir -p "${WORK_DIR}/roles" "${WORK_DIR}/clusterroles"

        echo "=== [1/4] Discovering Roles with wildcards ==="
        kubectl get roles --all-namespaces -o json | jq -c '
          .items[]
          | select(
              .rules[]? |
              (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*")
            )
          | {ns: .metadata.namespace, name: .metadata.name}
        ' | while read -r item; do
          ns=$(echo "${item}" | jq -r '.ns')
          name=$(echo "${item}" | jq -r '.name')
          echo "Exporting Role ${ns}/${name}"
          kubectl get role "${name}" -n "${ns}" -o yaml > "${WORK_DIR}/roles/${ns}__${name}.yaml"
        done

        echo "=== [2/4] Discovering ClusterRoles with wildcards ==="
        kubectl get clusterroles -o json | jq -c '
          .items[]
          | select(
              .rules[]? |
              (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*")
            )
          | {name: .metadata.name}
        ' | while read -r item; do
          name=$(echo "${item}" | jq -r '.name')
          echo "Exporting ClusterRole ${name}"
          kubectl get clusterrole "${name}" -o yaml > "${WORK_DIR}/clusterroles/${name}.yaml"
        done

        echo
        echo "=== Manual remediation required ==="
        echo "Directory with exported RBAC objects: ${WORK_DIR}"
        echo "For each YAML file:"
        echo "  - Edit .rules[*].verbs, .resources, and .apiGroups"
        echo "  - Replace any \"*\" with the minimal explicit values needed."
        echo
        echo "Example (conceptual only):"
        echo "  verbs: [\"*\"]        -> verbs: [\"get\", \"list\"]"
        echo "  resources: [\"*\"]    -> resources: [\"pods\", \"pods/log\"]"
        echo "  apiGroups: [\"*\"]    -> apiGroups: [\"\", \"apps\"]"
        echo
        echo "Do NOT change the metadata.name or metadata.namespace fields."

        read -rp "Have you finished editing YAML files under ${WORK_DIR} and want to apply them now? (y/N): " APPLY_ANSWER
        APPLY_ANSWER=${APPLY_ANSWER:-n}

        if [[ "${APPLY_ANSWER}" =~ ^[Yy]$ ]]; then
          echo "=== [3/4] Applying edited Roles ==="
          if compgen -G "${WORK_DIR}/roles/*.yaml" > /dev/null; then
            for f in "${WORK_DIR}/roles/"*.yaml; do
              echo "Applying Role from ${f}"
              kubectl apply -f "${f}"
            done
          else
            echo "No Role YAML files found to apply."
          fi

          echo "=== [3/4] Applying edited ClusterRoles ==="
          if compgen -G "${WORK_DIR}/clusterroles/*.yaml" > /dev/null; then
            for f in "${WORK_DIR}/clusterroles/"*.yaml; do
              echo "Applying ClusterRole from ${f}"
              kubectl apply -f "${f}"
            done
          else
            echo "No ClusterRole YAML files found to apply."
          fi
        else
          echo "Skipping kubectl apply. You can manually run:"
          echo "  kubectl apply -f ${WORK_DIR}/roles/"
          echo "  kubectl apply -f ${WORK_DIR}/clusterroles/"
        fi

        echo
        echo "=== [4/4] Verification (re-running wildcard audit) ==="
        wildcards=$(kubectl get roles --all-namespaces -o json | jq '
          .items[] | select(
            .rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*")
          )' | wc -l | tr -d ' ')

        wildcards_clusterroles=$(kubectl get clusterroles -o json | jq '
          .items[] | select(
            .rules[]? | (.verbs[]? == "*" or .resources[]? == "*" or .apiGroups[]? == "*")
          )' | wc -l | tr -d ' ')

        total=$((wildcards + wildcards_clusterroles))

        if [ "${total}" -gt 0 ]; then
          echo "Result: wildcards_present"
          echo "  Remaining Roles with wildcards : ${wildcards}"
          echo "  Remaining ClusterRoles with wildcards: ${wildcards_clusterroles}"
          echo "Inspect remaining offenders with:"
          echo "  kubectl get roles --all-namespaces -o json | jq -r '.items[] | select(.rules[]? | (.verbs[]? == \"*\" or .resources[]? == \"*\" or .apiGroups[]? == \"*\")) | \"Role \\(.metadata.namespace)/\\(.metadata.name)\"'"
          echo "  kubectl get clusterroles -o json | jq -r '.items[] | select(.rules[]? | (.verbs[]? == \"*\" or .resources[]? == \"*\" or .apiGroups[]? == \"*\")) | \"ClusterRole \\(.metadata.name)\"'"
          exit 1
        else
          echo "Result: no RBAC wildcards detected in Roles or ClusterRoles."
        fi
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
