> ## 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 ClusterRole grants unrestricted superuser access. Bind it only to subjects that genuinely require full cluster control.

### Risk Level

Critical

### Address

Security

### Compliance Standards

* CIS Kubernetes

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. **List all ClusterRoleBindings to `cluster-admin`**
           * **Run on:** any machine with kubectl access
           ```bash theme={null}
           kubectl get clusterrolebindings -o yaml | grep -B5 -A5 "name: cluster-admin"
           kubectl get clusterrolebindings -o=custom-columns=NAME:.metadata.name,ROLE:.roleRef.name,SUBJECT:.subjects[*].name --no-headers
           ```

        2. **Review each subject’s actual access needs** (manual decision)
           * **Run on:** any machine with kubectl access\
             For each ClusterRoleBinding identified in step 1, inspect details and note the subjects:
           ```bash theme={null}
           kubectl get clusterrolebinding <clusterrolebinding-name> -o yaml
           ```
           Manually determine, based on your org’s policies and the subject’s responsibilities, whether they truly require full cluster-wide admin, or only subset permissions (e.g., namespace admin, read-only, ops).

        3. **Identify or design least-privilege roles for subjects that do NOT need cluster-admin**
           * **Run on:** any machine with kubectl access\
             If a subject should have reduced permissions, either use an existing ClusterRole/Role or draft one. For example, create a more limited ClusterRole manifest file (edit rules according to your needs):
           ```bash theme={null}
           cat > restricted-admin-clusterrole.yaml << 'EOF'
           apiVersion: rbac.authorization.k8s.io/v1
           kind: ClusterRole
           metadata:
             name: restricted-admin
           rules:
           # TODO: Fill in with the minimal set of resources, verbs, and API groups actually required
           # Example:
           # - apiGroups: [""]
           #   resources: ["pods","services","configmaps"]
           #   verbs: ["get","list","watch","create","update","delete"]
           EOF

           kubectl apply -f restricted-admin-clusterrole.yaml
           ```

        4. **Create appropriate RoleBindings/ClusterRoleBindings to the reduced-privilege role**
           * **Run on:** any machine with kubectl access\
             For each subject that should no longer use `cluster-admin`, bind them to the least-privilege role you chose or created. For example, to bind a user to the `restricted-admin` ClusterRole cluster-wide:
           ```bash theme={null}
           cat > restricted-admin-binding-<subject>.yaml << 'EOF'
           apiVersion: rbac.authorization.k8s.io/v1
           kind: ClusterRoleBinding
           metadata:
             name: restricted-admin-binding-<subject>
           subjects:
           - kind: User   # or ServiceAccount/Group as appropriate
             name: <subject-name>
             apiGroup: rbac.authorization.k8s.io
           roleRef:
             kind: ClusterRole
             name: restricted-admin
             apiGroup: rbac.authorization.k8s.io
           EOF

           kubectl apply -f restricted-admin-binding-<subject>.yaml
           ```
           Replace `<subject>` and `<subject-name>` with the actual subject identifier.

        5. **Remove unnecessary `cluster-admin` ClusterRoleBindings**
           * **Run on:** any machine with kubectl access\
             After confirming the subject has appropriate alternative access and no longer needs `cluster-admin`, delete the old binding:
           ```bash theme={null}
           kubectl delete clusterrolebinding <clusterrolebinding-name>
           ```
           Only retain `cluster-admin` bindings for subjects that you explicitly decided must keep full cluster control.

        6. **Verification**
           * **Run on:** any machine with kubectl access\
             Re-run the audit logic and confirm no non-`cluster-admin` role names are bound to `cluster-admin`:
           ```bash theme={null}
           kubectl get clusterrolebindings -o=custom-columns=NAME:.metadata.name,ROLE:.roleRef.name,SUBJECT:.subjects[*].name --no-headers | while read -r role_name role_binding subject
           do
             if [[ "${role_name}" != "cluster-admin" && "${role_binding}" == "cluster-admin" ]]; then
               is_compliant="false"
             else
               is_compliant="true"
             fi;
             echo "**role_name: ${role_name} role_binding: ${role_binding} subject: ${subject} is_compliant: ${is_compliant}"
           done
           ```
           Manually check that any remaining `cluster-admin` bindings are only for subjects you intentionally approved for full cluster-admin access.
      </Accordion>

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

        1. List all ClusterRoleBindings that reference `cluster-admin`

        ```sh theme={null}
        kubectl get clusterrolebindings -o wide
        kubectl get clusterrolebindings -o yaml | grep -C4 "name: cluster-admin"
        ```

        2. Inspect each non‑default binding to `cluster-admin` and its subjects

        ```sh theme={null}
        kubectl get clusterrolebinding <BINDING_NAME> -o yaml
        ```

        3. For each subject that does not truly need full cluster‑admin, create or use a less‑privileged ClusterRole/Role and bind that instead. Example – if a subject only needs namespace‑scoped access:

        Create a namespace Role (edit rules as needed):

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

        Bind the subject to the lower‑privileged Role (fill in actual subject kind/name):

        ```sh theme={null}
        cat << 'EOF' | kubectl apply -f -
        apiVersion: rbac.authorization.k8s.io/v1
        kind: RoleBinding
        metadata:
          name: app-namespace-admin-binding
          namespace: default
        subjects:
          - kind: User        # or Group/ServiceAccount
            name: alice       # replace with real subject
            apiGroup: rbac.authorization.k8s.io
        roleRef:
          kind: Role
          name: app-namespace-admin
          apiGroup: rbac.authorization.k8s.io
        EOF
        ```

        4. Once all necessary replacement bindings are in place and validated, delete the unneeded `cluster-admin` ClusterRoleBindings:

        ```sh theme={null}
        kubectl delete clusterrolebinding <BINDING_NAME_TO_REMOVE>
        ```

        Repeat for each unnecessary `cluster-admin` binding.

        5. Verification (adapted from the audit):

        ```sh theme={null}
        kubectl get clusterrolebindings -o=custom-columns=NAME:.metadata.name,ROLE:.roleRef.name,SUBJECT:.subjects[*].name --no-headers | while read -r role_name role_binding subject
        do
          if [[ "${role_name}" != "cluster-admin" && "${role_binding}" == "cluster-admin" ]]; then
            is_compliant="false"
          else
            is_compliant="true"
          fi
          echo "**role_name: ${role_name} role_binding: ${role_binding} subject: ${subject} is_compliant: ${is_compliant}"
        done
        ```
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Remediation for:
        # "Ensure The Cluster-Admin Role Is Only Used Where Required"
        #
        # Scope: any machine with kubectl access to the cluster
        #
        # This script:
        #   - Lists all ClusterRoleBindings that grant the cluster-admin ClusterRole
        #     to non-cluster-admin subjects.
        #   - For each, it INTERACTIVELY asks whether to delete the binding.
        #   - Optionally backs up each binding manifest before deletion.
        #   - Re-runs the audit logic at the end.
        #
        # Idempotent: safe to re-run; already-deleted bindings are skipped.

        set -euo pipefail

        BACKUP_DIR="./clusterrolebinding_backups_$(date +%Y%m%d_%H%M%S)"
        mkdir -p "${BACKUP_DIR}"

        echo "Finding ClusterRoleBindings that bind ClusterRole 'cluster-admin' to non-'cluster-admin' role names..."
        echo

        # Get all clusterrolebindings with their roleRef.name and subjects[*].name
        mapfile -t CRB_LINES < <(kubectl get clusterrolebindings -o=custom-columns=NAME:.metadata.name,ROLE:.roleRef.name,SUBJECT:.subjects[*].name --no-headers)

        if [ "${#CRB_LINES[@]}" -eq 0 ]; then
          echo "No ClusterRoleBindings found."
          exit 0
        fi

        # Track non-compliant bindings for summary and verification
        declare -a NON_COMPLIANT_BINDINGS=()

        for line in "${CRB_LINES[@]}"; do
          # shellcheck disable=SC2206
          arr=($line)
          crb_name="${arr[0]}"
          role_name="${arr[1]}"
          subject="${arr[@]:2}"

          # Condition from benchmark:
          # is_compliant is false if rolename is not cluster-admin and rolebinding is cluster-admin.
          if [[ "${role_name}" != "cluster-admin" ]]; then
            # This binding grants cluster-admin ClusterRole to a subject while the binding name is not 'cluster-admin'
            NON_COMPLIANT_BINDINGS+=("${crb_name}")

            echo "Non-compliant ClusterRoleBinding found:"
            echo "  NAME:    ${crb_name}"
            echo "  ROLE:    ${role_name} (grants ClusterRole 'cluster-admin')"
            echo "  SUBJECT: ${subject}"
            echo

            # Show full YAML for review
            echo "YAML definition:"
            kubectl get clusterrolebinding "${crb_name}" -o yaml
            echo

            # Confirm backup
            read -r -p "Backup this ClusterRoleBinding to ${BACKUP_DIR}/${crb_name}.yaml before any change? [y/N]: " backup_answer
            backup_answer="${backup_answer:-N}"
            if [[ "${backup_answer}" =~ ^[Yy]$ ]]; then
              kubectl get clusterrolebinding "${crb_name}" -o yaml > "${BACKUP_DIR}/${crb_name}.yaml"
              echo "  Backed up to ${BACKUP_DIR}/${crb_name}.yaml"
            fi

            echo
            echo "Review question:"
            echo "  Does this subject truly require full cluster-admin privileges?"
            echo "  If not, you should:"
            echo "    1) Create or bind a lower-privilege Role/ClusterRole as appropriate."
            echo "    2) Then delete this ClusterRoleBinding."
            echo

            read -r -p "Delete ClusterRoleBinding '${crb_name}' now? [y/N]: " delete_answer
            delete_answer="${delete_answer:-N}"
            if [[ "${delete_answer}" =~ ^[Yy]$ ]]; then
              echo "Deleting ClusterRoleBinding '${crb_name}'..."
              kubectl delete clusterrolebinding "${crb_name}"
              echo "  Deleted."
            else
              echo "  Skipping deletion of '${crb_name}'."
            fi

            echo "------------------------------------------------------------"
          fi
        done

        echo
        echo "Verification: re-running compliance evaluation..."
        echo

        kubectl get clusterrolebindings -o=custom-columns=NAME:.metadata.name,ROLE:.roleRef.name,SUBJECT:.subjects[*].name --no-headers | while read -r role_name role_binding subject
        do
          if [[ "${role_name}" != "cluster-admin" && "${role_binding}" == "cluster-admin" ]]; then
            is_compliant="false"
          else
            is_compliant="true"
          fi;
          echo "**role_name: ${role_name} role_binding: ${role_binding} subject: ${subject} is_compliant: ${is_compliant}"
        done

        echo
        echo "Review the lines above: any entry with 'is_compliant: false' still needs manual analysis and, if appropriate, further remediation."
        echo "Backups (if created) are stored in: ${BACKUP_DIR}"
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
