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

### More Info:

The RBAC role cluster-admin provides wide-ranging powers over the environment and should be used only where and when needed.

### Risk Level

Critical

### Address

Security

### Compliance Standards

* APRA CPS 234 (Australia)
* BSI C5 (Germany)
* Brazil LGPD
* CCPA / CPRA (California)
* CIS Critical Security Controls v8
* CIS GKE
* CMMC 2.0
* CSA Cloud Controls Matrix v4
* DPDPA
* Digital Operational Resilience Act (EU)
* Essential 8
* ISO/IEC 27017
* ISO/IEC 27018
* ISO/IEC 27701
* KSA PDPL
* MAS Technology Risk Management (Singapore)
* MITRE ATT\&CK (Cloud)
* NIS2 Directive
* NIST SP 800-171
* NYDFS 23 NYCRR 500
* SWIFT Customer Security Controls Framework
* Sarbanes-Oxley IT General Controls
* Securities and Exchange Board of India (SEBI) - Cloud Security Adoption Framework
* UK NCSC Cyber Assessment Framework

### 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 who they bind to:
           ```bash theme={null}
           kubectl get clusterrolebindings \
             -o=custom-columns=NAME:.metadata.name,ROLE:.roleRef.name,SUBJECTS_KIND:.subjects[*].kind,SUBJECTS_NAME:.subjects[*].name \
           | grep 'cluster-admin'
           ```

        2. For each binding you found, display full details (to distinguish system vs non-system subjects):
           ```bash theme={null}
           kubectl get clusterrolebinding <binding-name> -o yaml
           ```
           Manually review each subject; plan to keep bindings only if they are:
           * `Group` with name `system:masters`, or
           * other `system:` prefixed subjects that are required for core components.

        3. For any non-system user/group/service account that does not strictly require `cluster-admin`, design or select a least-privileged `Role`/`ClusterRole` that matches its actual needs. For example, to create a narrower `ClusterRole` for read-only access to pods and services:
           ```bash theme={null}
           cat << 'EOF' > readonly-pods-services-clusterrole.yaml
           apiVersion: rbac.authorization.k8s.io/v1
           kind: ClusterRole
           metadata:
             name: readonly-pods-services
           rules:
             - apiGroups: [""]
               resources: ["pods", "services"]
               verbs: ["get", "list", "watch"]
           EOF

           kubectl apply -f readonly-pods-services-clusterrole.yaml
           ```

        4. Bind the least-privileged role to the principal instead of `cluster-admin`, adjusting kind/name/namespace as appropriate:
           * Example for a user:
             ```bash theme={null}
             cat << 'EOF' > readonly-binding-user.yaml
             apiVersion: rbac.authorization.k8s.io/v1
             kind: ClusterRoleBinding
             metadata:
               name: readonly-pods-services-user-alice
             subjects:
               - kind: User
                 name: alice@example.com
             roleRef:
               apiGroup: rbac.authorization.k8s.io
               kind: ClusterRole
               name: readonly-pods-services
             EOF

             kubectl apply -f readonly-binding-user.yaml
             ```
           * Example for a service account:
             ```bash theme={null}
             cat << 'EOF' > readonly-binding-sa.yaml
             apiVersion: rbac.authorization.k8s.io/v1
             kind: ClusterRoleBinding
             metadata:
               name: readonly-pods-services-sa-myapp
             subjects:
               - kind: ServiceAccount
                 name: myapp
                 namespace: default
             roleRef:
               apiGroup: rbac.authorization.k8s.io
               kind: ClusterRole
               name: readonly-pods-services
             EOF

             kubectl apply -f readonly-binding-sa.yaml
             ```

        5. After confirming that the replacement binding(s) exist and are correct, remove the excessive `cluster-admin` binding(s), being careful not to delete required `system:` bindings or the `system:masters` mapping:
           ```bash theme={null}
           kubectl delete clusterrolebinding <binding-name>
           ```

        6. Verification (on any machine with kubectl access): rerun the audit, which should now return `NO_CLUSTER_ADMIN_BINDINGS` or only allowlist subjects:
           ```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="Using kubectl">
        On any machine with kubectl access:

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

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

        For deeper inspection of a specific binding:

        ```bash theme={null}
        kubectl get clusterrolebinding <binding-name> -o yaml
        ```

        2. For each non-system subject that does not truly require `cluster-admin`, create or select a least‑privileged (Cluster)Role and bind to that instead.

        Example: create a narrowly scoped ClusterRole (edit as appropriate):

        ```bash theme={null}
        cat << 'EOF' | kubectl apply -f -
        apiVersion: rbac.authorization.k8s.io/v1
        kind: ClusterRole
        metadata:
          name: app-ops-readonly
        rules:
          - apiGroups: [""]
            resources: ["pods","services","configmaps"]
            verbs: ["get","list","watch"]
        EOF
        ```

        Bind the principal to this least‑privileged ClusterRole:

        ```bash theme={null}
        cat << 'EOF' | kubectl apply -f -
        apiVersion: rbac.authorization.k8s.io/v1
        kind: ClusterRoleBinding
        metadata:
          name: app-ops-readonly-binding
        roleRef:
          apiGroup: rbac.authorization.k8s.io
          kind: ClusterRole
          name: app-ops-readonly
        subjects:
          - kind: User
            name: user@example.com
            apiGroup: rbac.authorization.k8s.io
        EOF
        ```

        3. Remove excessive `cluster-admin` bindings for non-system principals (do NOT delete any `system:` bindings or the `system:masters` group):

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

        Repeat for each binding you have replaced with a least‑privileged alternative.

        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: Assist review of cluster-admin bindings and optionally remove non-required ones.
        # Scope:   Run on any machine with kubectl access and correct context.
        # Notes:   This is a MANUAL control. This script does NOT auto-delete anything without confirmation.

        set -euo pipefail

        echo "=== Discovering all ClusterRoleBindings to role 'cluster-admin' ==="
        kubectl get clusterrolebindings -o=custom-columns=NAME:.metadata.name,ROLE:.roleRef.name,SUBJECTS:.subjects[*].name \
          | grep 'cluster-admin' || true

        echo
        echo "=== Detailed JSON view of non-system 'cluster-admin' subjects (for review) ==="
        kubectl get clusterrolebindings -o json | jq '
          [
            .items[]
            | select(.roleRef.name == "cluster-admin")
            | {
                name: .metadata.name,
                subjects: [
                  .subjects[]?
                  | select(.kind != "Group" or .name != "system:masters")
                ]
              }
          ]
          | map(select(.subjects | length > 0))
        '

        echo
        echo "======================================================================"
        echo "MANUAL REVIEW REQUIRED:"
        echo " 1. For each binding above, decide if the subjects truly require full"
        echo "    cluster-admin. If not, design a least-privileged (Cluster)Role."
        echo " 2. Create that Role/ClusterRole and bind subjects to it BEFORE removal."
        echo " 3. Do NOT modify or delete any 'system:' prefixed bindings."
        echo "======================================================================"
        echo

        read -r -p "List candidate ClusterRoleBindings (excluding 'system:' prefixes) for deletion? [y/N]: " LIST_CAND
        if [[ "${LIST_CAND:-N}" =~ ^[Yy]$ ]]; then
          echo
          echo "=== Candidate ClusterRoleBindings (roleRef.name == 'cluster-admin', name does NOT start with 'system:') ==="
          kubectl get clusterrolebindings -o json | jq -r '
            .items[]
            | select(.roleRef.name == "cluster-admin")
            | select(.metadata.name | startswith("system:") | not)
            | .metadata.name
          '
        fi

        read -r -p "Enter a ClusterRoleBinding name to DELETE (or leave blank to skip deletion): " CRB_NAME
        if [[ -n "${CRB_NAME}" ]]; then
          echo
          echo "You are about to DELETE ClusterRoleBinding: ${CRB_NAME}"
          echo "Ensure you have already created replacement least-privileged bindings as needed."
          read -r -p "Type the binding name again to confirm deletion: " CRB_CONFIRM
          if [[ "${CRB_CONFIRM}" == "${CRB_NAME}" ]]; then
            echo "Deleting ClusterRoleBinding '${CRB_NAME}'..."
            kubectl delete clusterrolebinding "${CRB_NAME}"
          else
            echo "Confirmation did not match. Skipping deletion."
          fi
        else
          echo "No deletion requested. Proceeding to verification."
        fi

        echo
        echo "=== Verification: re-running benchmark audit logic ==="
        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>
    </AccordionGroup>
  </Tab>
</Tabs>

### Additional Reading:

* [https://kubernetes.io/docs/admin/authorization/rbac/#user-facing-roles](https://kubernetes.io/docs/admin/authorization/rbac/#user-facing-roles)
