> ## 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 The Cluster-Admin Role Is Only Used Where Required

### More Info:

The cluster-admin role grants unrestricted access across the cluster. It should only be bound to subjects that genuinely require full administrative privileges.

### 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. On any machine with kubectl access, list all ClusterRoleBindings that grant `cluster-admin` and see which subjects they bind:
           ```bash theme={null}
           kubectl get clusterrolebindings -o wide
           kubectl get clusterrolebindings -o yaml | grep -A5 "roleRef:\s*name: cluster-admin"
           ```

        2. For each such ClusterRoleBinding, inspect full details and note the subjects (Users/Groups/ServiceAccounts):
           ```bash theme={null}
           kubectl get clusterrolebinding <binding-name> -o yaml
           ```
           Decide, with your application/cluster owners, which subjects truly require full cluster-wide admin rights and which can be reduced to more limited roles (for example, namespace‑scoped admin or a custom Role/ClusterRole).

        3. For subjects that do not require full `cluster-admin`, either:
           * Rebind them to an existing less‑privileged ClusterRole:
             ```bash theme={null}
             kubectl create clusterrolebinding <new-binding-name> \
               --clusterrole=<less-privileged-clusterrole> \
               --user=<user-name>
             ```
             or for a ServiceAccount:
             ```bash theme={null}
             kubectl create clusterrolebinding <new-binding-name> \
               --clusterrole=<less-privileged-clusterrole> \
               --serviceaccount=<namespace>:<sa-name>
             ```
           * Or, if appropriate, bind them only within a namespace using a Role/RoleBinding instead of a ClusterRoleBinding.

        4. Once a subject has suitable alternative permissions, remove unnecessary ClusterRoleBindings to `cluster-admin` as recommended:
           ```bash theme={null}
           kubectl delete clusterrolebinding <binding-name>
           ```
           Only delete after confirming no remaining operational dependency on that binding.

        5. Ensure that only the intended high‑privilege groups remain bound to `cluster-admin` (typically `system:masters` or other tightly controlled admin groups), and avoid binding arbitrary users, service accounts, or broad groups (like `system:authenticated`) to this role.

        6. Verification (on any machine with kubectl access): confirm no unexpected subjects are bound to `cluster-admin`:
           ```bash theme={null}
           kubectl get clusterrolebindings -o json | jq -r '
             .items[]
             | select(.roleRef.name == "cluster-admin")
             | .subjects[]?
             | select(.kind != "Group" or (.name != "system:masters" and .name != "system:nodes"))
             | "FOUND_CLUSTER_ADMIN_BINDING"
           ' || echo "NO_CLUSTER_ADMIN_BINDINGS"
           ```
           If the output is only `NO_CLUSTER_ADMIN_BINDINGS`, all non‑approved `cluster-admin` bindings have been removed.
      </Accordion>

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

        1. List all ClusterRoleBindings that grant `cluster-admin`:

        ```bash theme={null}
        kubectl get clusterrolebindings -o wide
        ```

        2. Inspect each binding’s subjects to decide who truly needs full admin:

        ```bash theme={null}
        kubectl get clusterrolebindings -o yaml | less
        ```

        3. For each subject that should have reduced privileges, create or bind a lower-privilege role (example: namespace-scoped admin instead of cluster-admin).

        Example: create a namespace admin Role and RoleBinding (adjust `metadata.name`, `metadata.namespace`, and `subjects` as needed):

        ```bash theme={null}
        cat << 'EOF' | kubectl apply -f -
        apiVersion: rbac.authorization.k8s.io/v1
        kind: Role
        metadata:
          name: ns-admin
          namespace: default
        rules:
          - apiGroups: ["*"]
            resources: ["*"]
            verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
        EOF
        ```

        ```bash theme={null}
        cat << 'EOF' | kubectl apply -f -
        apiVersion: rbac.authorization.k8s.io/v1
        kind: RoleBinding
        metadata:
          name: ns-admin-binding
          namespace: default
        subjects:
          - kind: User
            name: alice@example.com
            apiGroup: rbac.authorization.k8s.io
        roleRef:
          kind: Role
          name: ns-admin
          apiGroup: rbac.authorization.k8s.io
        EOF
        ```

        4. After validating that the alternative access works, delete unnecessary `cluster-admin` ClusterRoleBindings (do NOT delete those you still need, and typically retain default system bindings such as for `system:masters`):

        ```bash theme={null}
        kubectl delete clusterrolebinding NAME_OF_BINDING_TO_REMOVE
        ```

        5. Verification (expected output is `NO_CLUSTER_ADMIN_BINDINGS` or only system groups excluded by the query):

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

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        set -euo pipefail

        # Automation for: CISEKS 4.1.1
        # Scope: run on any machine with kubectl access and appropriate RBAC privileges.

        # This script:
        # 1. Lists all ClusterRoleBindings to "cluster-admin" excluding:
        #    - Groups: system:masters, system:nodes (as per audit)
        # 2. Prints them for human review and confirmation.
        # 3. Optionally deletes selected ClusterRoleBindings.
        # 4. Verifies the result using the benchmark audit logic.
        #
        # Idempotent: re-running will skip already-deleted bindings.

        # Requirements: kubectl, jq
        command -v kubectl >/dev/null 2>&1 || { echo "kubectl not found in PATH"; exit 1; }
        command -v jq >/dev/null 2>&1 || { echo "jq not found in PATH"; exit 1; }

        echo "Discovering ClusterRoleBindings referencing cluster-admin..."

        # Collect all ClusterRoleBindings that reference cluster-admin and have at least
        # one subject that is NOT the exempted system groups.
        mapfile -t CRBS < <(
          kubectl get clusterrolebindings -o json | jq -r '
            .items[]
            | select(.roleRef.name == "cluster-admin")
            | select(
                (.subjects // [])[]
                | ( .kind != "Group"
                    or ( .name != "system:masters" and .name != "system:nodes")
                  )
              )
            | .metadata.name
          ' | sort -u
        )

        if [[ ${#CRBS[@]} -eq 0 ]]; then
          echo "No non-system ClusterRoleBindings to cluster-admin found."
        else
          echo
          echo "The following ClusterRoleBindings reference cluster-admin and have non-exempt subjects:"
          for crb in "${CRBS[@]}"; do
            echo "---------------------------------------------------------------------"
            echo "ClusterRoleBinding: ${crb}"
            kubectl get clusterrolebinding "${crb}" -o yaml
          done

          echo
          echo "Review the above bindings. For each, decide if full cluster-admin is truly required."
          echo "Recommendation: create or bind to a lower-privilege Role/ClusterRole first where possible."
          echo

          read -r -p "Proceed to select and delete ClusterRoleBindings from the above list? (yes/no): " CONFIRM
          if [[ "${CONFIRM}" == "yes" ]]; then
            echo
            echo "Enter names to delete, space-separated, or 'all' to delete all listed:"
            echo "Available: ${CRBS[*]}"
            read -r -p "Delete: " TO_DELETE

            DELETE_LIST=()
            if [[ "${TO_DELETE}" == "all" ]]; then
              DELETE_LIST=("${CRBS[@]}")
            else
              # Validate user input against discovered CRBs
              for item in ${TO_DELETE}; do
                if printf '%s\n' "${CRBS[@]}" | grep -qx "${item}"; then
                  DELETE_LIST+=("${item}")
                else
                  echo "Skipping unknown ClusterRoleBinding: ${item}"
                fi
              done
            fi

            if [[ ${#DELETE_LIST[@]} -eq 0 ]]; then
              echo "No valid ClusterRoleBinding selected for deletion. Exiting without changes."
            else
              echo
              echo "About to delete the following ClusterRoleBindings:"
              printf '  %s\n' "${DELETE_LIST[@]}"
              read -r -p "Confirm deletion (yes/no): " DEL_CONFIRM
              if [[ "${DEL_CONFIRM}" == "yes" ]]; then
                for crb in "${DELETE_LIST[@]}"; do
                  echo "Deleting ClusterRoleBinding: ${crb}"
                  kubectl delete clusterrolebinding "${crb}" || {
                    echo "Warning: failed to delete ${crb} (may already be removed or access denied)."
                  }
                done
              else
                echo "Deletion canceled. No changes made."
              fi
            fi
          else
            echo "No deletions performed."
          fi
        fi

        echo
        echo "Verification (benchmark-style audit):"
        kubectl get clusterrolebindings -o json | jq -r '
          .items[]
          | select(.roleRef.name == "cluster-admin")
          | .subjects[]?
          | select(.kind != "Group" or (.name != "system:masters" and .name != "system:nodes"))
          | "FOUND_CLUSTER_ADMIN_BINDING"
        ' || echo "NO_CLUSTER_ADMIN_BINDINGS"
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
