> ## 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.

# Ensure Cluster-Admin Role Is Only Used Where Required

### More Info:

The cluster-admin ClusterRole grants superuser access over the entire cluster. Bindings to it should be restricted to the minimum set of principals that strictly require it.

### Risk Level

Critical

### Address

Security

### Compliance Standards

* CIS GKE

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. On any machine with kubectl access, list all ClusterRoleBindings that use the cluster-admin role and see their subjects:
           ```sh theme={null}
           kubectl get clusterrolebindings -o=custom-columns=NAME:.metadata.name,ROLE:.roleRef.name,SUBJECTS:.subjects[*].name | grep cluster-admin
           ```

        2. For each binding identified in step 1, inspect full details (including subject kinds and namespaces):
           ```sh theme={null}
           kubectl get clusterrolebinding <binding-name> -o yaml
           ```
           Manually determine whether each non-system subject (Users, Groups, ServiceAccounts) truly requires cluster-wide superuser rights. Do not modify bindings whose name or subjects are system-prefixed (e.g., starting with `system:`) and are required for core components.

        3. For each subject that does not strictly require cluster-admin, design or select a least-privileged Role/ClusterRole that covers only the permissions it needs. For example, create a custom ClusterRole on any machine with kubectl access:
           ```sh theme={null}
           cat << 'EOF' | kubectl apply -f -
           apiVersion: rbac.authorization.k8s.io/v1
           kind: ClusterRole
           metadata:
             name: limited-admin-example
           rules:
             - apiGroups: [""]
               resources: ["pods"]
               verbs: ["get", "list", "watch"]
           EOF
           ```

        4. Rebind each affected subject to the least-privileged (Cluster)Role instead of cluster-admin, using a new (Cluster)RoleBinding. Example for a ClusterRole and a user:
           ```sh theme={null}
           cat << 'EOF' | kubectl apply -f -
           apiVersion: rbac.authorization.k8s.io/v1
           kind: ClusterRoleBinding
           metadata:
             name: limited-admin-example-binding
           subjects:
             - kind: User
               name: alice@example.com
               apiGroup: rbac.authorization.k8s.io
           roleRef:
             apiGroup: rbac.authorization.k8s.io
             kind: ClusterRole
             name: limited-admin-example
           EOF
           ```

        5. After confirming that alternative bindings are in place and tested for each subject, remove the excessive cluster-admin bindings that are no longer required:
           ```sh theme={null}
           kubectl delete clusterrolebinding <binding-name>
           ```

        6. Verify that no non-system principals remain bound to cluster-admin, on any machine with kubectl access:
           ```sh theme={null}
           kubectl get clusterrolebindings -o json | jq -r '
             [
               .items[]
               | select(.roleRef.name == "cluster-admin")
               | .subjects[]?
               | select(.kind != "Group" or .name != "system:masters")
             ]
             | if length == 0
               then "NO_CLUSTER_ADMIN_BINDINGS"
               else "FOUND_CLUSTER_ADMIN_BINDING"
               end
           '
           ```
      </Accordion>

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

        1. List all ClusterRoleBindings that use `cluster-admin` and review subjects

        ```bash theme={null}
        kubectl get clusterrolebindings -o=custom-columns=NAME:.metadata.name,ROLE:.roleRef.name,SUBJECTS:.subjects[*].name \
          | grep 'cluster-admin'
        ```

        2. For each non‑system binding you determine does NOT strictly require `cluster-admin`, remove the binding\
           (Example using a placeholder name; replace with the real binding name you decided to remove.)

        ```bash theme={null}
        kubectl delete clusterrolebinding <binding-name-to-remove>
        ```

        3. (Optional) Create a least‑privilege ClusterRole and bind it instead of `cluster-admin`\
           Example: read‑only access to pods in all namespaces.

        Create a manifest file, e.g. `readonly-pods-clusterrole.yaml`:

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

        Apply it:

        ```bash theme={null}
        kubectl apply -f readonly-pods-clusterrole.yaml
        ```

        Then bind it to the principal that previously had `cluster-admin`, for example a user:

        ```bash theme={null}
        kubectl create clusterrolebinding readonly-pods-binding \
          --clusterrole=readonly-pods \
          --user=<user-identifier>
        ```

        (or use `--group` or `--serviceaccount <namespace>:<sa-name>` as appropriate.)

        4. Verification (on any machine with kubectl access)

        ```bash theme={null}
        kubectl get clusterrolebindings -o json | jq -r '
          [
            .items[]
            | select(.roleRef.name == "cluster-admin")
            | .subjects[]?
            | select(.kind != "Group" or .name != "system:masters")
          ]
          | if length == 0
            then "NO_CLUSTER_ADMIN_BINDINGS"
            else "FOUND_CLUSTER_ADMIN_BINDING"
            end
        '
        ```
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Purpose:
        #   Audit and interactively clean up non-system ClusterRoleBindings
        #   that grant the "cluster-admin" ClusterRole.
        #
        # Scope:
        #   Run on any machine with kubectl access to the cluster and
        #   appropriate permissions to list and delete ClusterRoleBindings.
        #
        # Idempotency:
        #   - Read‑only until you confirm deletions.
        #   - Deleting an already‑deleted binding is not attempted.
        #   - Safe to re‑run; it will only act on currently existing bindings.
        #
        # IMPORTANT:
        #   - This script CANNOT know which principals truly require cluster-admin.
        #   - For each non‑system binding it shows details and asks you to decide.
        #   - Before confirming deletion, ensure an appropriate least‑privilege
        #     Role/ClusterRoleBinding has been created separately.

        set -euo pipefail

        # Ensure needed tools are present
        for cmd in kubectl jq; do
          if ! command -v "$cmd" >/dev/null 2>&1; then
            echo "ERROR: Required command '$cmd' not found in PATH." >&2
            exit 1
          fi
        done

        echo "=== Step 1: Discover ClusterRoleBindings to 'cluster-admin' ==="

        # List all ClusterRoleBindings that reference cluster-admin
        kubectl get clusterrolebindings -o json | jq -r '
          .items[]
          | select(.roleRef.name == "cluster-admin")
          | .metadata.name
        ' | sort -u > /tmp/clusteradmin_bindings.$$ || true

        if [[ ! -s /tmp/clusteradmin_bindings.$$ ]]; then
          echo "No ClusterRoleBindings found that reference ClusterRole 'cluster-admin'."
          rm -f /tmp/clusteradmin_bindings.$$
          exit 0
        fi

        echo "ClusterRoleBindings referencing 'cluster-admin':"
        cat /tmp/clusteradmin_bindings.$$
        echo

        echo "=== Step 2: Exclude required system bindings (system:*) from modification ==="
        echo "NOTE: Bindings whose name starts with 'system:' will be SKIPPED."

        to_review=()

        while read -r crb; do
          [[ -z "$crb" ]] && continue

          if [[ "$crb" == system:* ]]; then
            echo "Skipping system binding: $crb"
            continue
          fi

          to_review+=("$crb")
        done < /tmp/clusteradmin_bindings.$$

        if [[ ${#to_review[@]} -eq 0 ]]; then
          echo
          echo "All ClusterRoleBindings to cluster-admin are system:* bindings."
          echo "No non-system principals to remediate."
          rm -f /tmp/clusteradmin_bindings.$$
          exit 0
        fi

        echo
        echo "Non-system ClusterRoleBindings to review:"
        for crb in "${to_review[@]}"; do
          echo "  - $crb"
        done
        echo

        echo "=== Step 3: Review each non-system binding and decide whether to delete ==="
        echo "For each binding you will see its subjects. You must decide if it should"
        echo "continue to have cluster-admin, or be removed (after ensuring a suitable"
        echo "least-privilege Role/ClusterRole exists and is bound)."
        echo

        deleted=()

        for crb in "${to_review[@]}"; do
          echo "------------------------------------------------------------"
          echo "Binding: $crb"
          echo

          # Show full YAML for detailed inspection
          kubectl get clusterrolebinding "$crb" -o yaml

          echo
          echo "This binding grants ClusterRole 'cluster-admin' to the above subjects."
          echo "If these subjects do NOT strictly require cluster-admin, you should:"
          echo "  1) Create/assign a more limited Role/ClusterRoleBinding separately."
          echo "  2) Then remove this excessive binding."
          echo

          # Prompt for action
          while true; do
            read -r -p "Delete this ClusterRoleBinding '$crb'? [y/N] " ans
            ans=${ans:-n}
            case "$ans" in
              [Yy]*)
                echo "Deleting ClusterRoleBinding '$crb'..."
                if kubectl delete clusterrolebinding "$crb"; then
                  deleted+=("$crb")
                else
                  echo "WARN: Failed to delete ClusterRoleBinding '$crb' (it may already be gone or you lack permissions)." >&2
                fi
                break
                ;;
              [Nn]*)
                echo "Keeping ClusterRoleBinding '$crb'."
                break
                ;;
              *)
                echo "Please answer y or n."
                ;;
            esac
          done
          echo
        done

        rm -f /tmp/clusteradmin_bindings.$$

        echo "=== Step 4: Verification (re-run audit logic) ==="
        echo "Running the benchmark audit expression to confirm remaining bindings..."

        audit_result="$(
        kubectl get clusterrolebindings -o json | jq -r '
          [
            .items[]
            | select(.roleRef.name == "cluster-admin")
            | .subjects[]?
            | select(.kind != "Group" or .name != "system:masters")
          ]
          | if length == 0
            then "NO_CLUSTER_ADMIN_BINDINGS"
            else "FOUND_CLUSTER_ADMIN_BINDING"
            end
        '
        )"

        echo "Audit result: $audit_result"
        echo

        if [[ "$audit_result" == "NO_CLUSTER_ADMIN_BINDINGS" ]]; then
          echo "SUCCESS: No non-system principals are currently bound to ClusterRole 'cluster-admin'."
        else
          echo "NOTICE: There are still non-system principals bound to 'cluster-admin'."
          echo "Review remaining ClusterRoleBindings and repeat this script as needed."
        fi

        if [[ ${#deleted[@]} -gt 0 ]]; then
          echo
          echo "Bindings deleted in this run:"
          for d in "${deleted[@]}"; do
            echo "  - $d"
          done
        fi
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
