> ## 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 access to the entire cluster. It should only be bound to principals that strictly require full administrative control.

### Risk Level

Critical

### Address

Security

### Compliance Standards

* CIS AKS

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. **List all cluster-admin bindings and their subjects**
           * Run on: any machine with kubectl access
           * Command:
             ```bash theme={null}
             kubectl get clusterrolebindings -o wide | grep 'cluster-admin'
             kubectl get clusterrolebindings -o yaml | grep -A10 -B2 'name: cluster-admin'
             ```
           * Purpose: identify every `ClusterRoleBinding` that grants `cluster-admin` and who/what it is bound to (users, groups, service accounts).

        2. **For each binding, understand what is using it and why**
           * For each binding name found (e.g. `cluster-admin`, `aks-cluster-admin-binding`, etc.), inspect details:
             ```bash theme={null}
             kubectl get clusterrolebinding <binding-name> -o yaml
             ```
           * Map each subject to:
             * Human user / group (e.g. corporate IdP group)
             * Service account (note its namespace and owning deployment/workload)
             * System or add-on component (e.g. CNI, Ingress, monitoring)
           * Check your internal documentation, IaC (Helm, Terraform, etc.), or platform docs to see why this binding was created.

        3. **Decide if full cluster-admin is strictly necessary for each subject**\
           For each subject in each binding, ask:
           * Does it require cluster-wide, unrestricted access (e.g. break-glass admin, platform SRE)?
           * Is its actual function limited (e.g. namespaced app, read-only monitor, single-namespace operator)?
           * Is there a documented support / vendor requirement for `cluster-admin`, or can it be scoped down (namespace-scoped or specific API groups/resources/verbs)?
           * If multiple subjects are in one binding, evaluate each individually; you may need to split them into separate bindings with different roles.

        4. **Design and apply least-privilege alternatives where possible**
           * If `cluster-admin` is not strictly required, create or reuse a less-privileged `ClusterRole`/`Role` that matches the real needs. Examples (adapt to your case):
             ```bash theme={null}
             # Example: read-only cluster-wide role
             kubectl apply -f - <<'EOF'
             apiVersion: rbac.authorization.k8s.io/v1
             kind: ClusterRole
             metadata:
               name: readonly-cluster
             rules:
               - apiGroups: [""]
                 resources: ["pods","services","configmaps","namespaces"]
                 verbs: ["get","list","watch"]
             EOF
             ```
           * Bind that role to the subject instead of `cluster-admin` (adjust `kind`, `name`, `namespace` as identified in step 2):
             ```bash theme={null}
             kubectl apply -f - <<'EOF'
             apiVersion: rbac.authorization.k8s.io/v1
             kind: ClusterRoleBinding
             metadata:
               name: readonly-cluster-binding
             subjects:
               - kind: User
                 name: <user-identifier>
             roleRef:
               apiGroup: rbac.authorization.k8s.io
               kind: ClusterRole
               name: readonly-cluster
             EOF
             ```
           * For service accounts that only need namespace access, prefer `Role` + `RoleBinding` in that namespace.

        5. **Remove or narrow the cluster-admin bindings**
           * After confirming the replacement access works (functional tests, user confirmation, or workload logs), remove or adjust the `cluster-admin` binding:
             * To completely remove a no-longer-needed binding:
               ```bash theme={null}
               kubectl delete clusterrolebinding <binding-name>
               ```
             * To keep the binding but drop unnecessary subjects, edit it interactively:
               ```bash theme={null}
               kubectl edit clusterrolebinding <binding-name>
               ```
               Remove only the subjects that no longer require `cluster-admin`, then save.
           * For bindings managed by GitOps/IaC, make the equivalent changes in the source manifests instead of editing live objects directly, then apply/sync.

        6. **Verify remaining usage of cluster-admin is minimal and intentional**
           * Run on: any machine with kubectl access
           * Command:
             ```bash theme={null}
             kubectl get clusterrolebindings --no-headers | grep 'cluster-admin' || echo "No cluster-admin bindings found"
             ```
           * For any remaining bindings, ensure you have documented justification (who, why, and approval) and that they are periodically re-reviewed.
      </Accordion>

      <Accordion title="Using kubectl">
        #### Using kubectl

        Run these commands from any machine with kubectl access.

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

        ```bash theme={null}
        kubectl get clusterrolebindings -o wide | grep 'cluster-admin'
        ```

        If you get no output, there are no current bindings to `cluster-admin` (no problem for this check).\
        Any lines returned indicate a binding that must be reviewed.

        2. View full details of each binding found:

        ```bash theme={null}
        # Example: replace <binding-name> with each name from step 1
        kubectl get clusterrolebinding <binding-name> -o yaml
        ```

        Focus on:

        * `.roleRef.name` – must be `cluster-admin` for this control.
        * `.subjects` – which `User`, `Group`, or `ServiceAccount` is getting cluster-admin.

        Problem indicators:

        * Bindings to broad identities such as:
          * `system:authenticated`, `system:unauthenticated`, or other large groups
          * Wildcard-like groups used by your IdP (e.g., “AllEmployees”)
        * ServiceAccounts in application namespaces (e.g., `default`, `dev-*`, `prod-*`) that do not clearly require full cluster control.
        * External users or groups where a more specific, least-privilege ClusterRole could be used instead.

        3. (Optional) Quickly list just the subjects of all `cluster-admin` bindings:

        ```bash theme={null}
        kubectl get clusterrolebindings -o json \
          | jq -r '.items[]
            | select(.roleRef.kind=="ClusterRole" and .roleRef.name=="cluster-admin")
            | .metadata.name as $b
            | .subjects[]? 
            | [$b, .kind, .name, (.namespace // "-")] 
            | @tsv'
        ```

        Output columns:

        1. ClusterRoleBinding name
        2. Subject kind (`User`, `Group`, `ServiceAccount`)
        3. Subject name
        4. Namespace (`-` for non-namespaced subjects)

        Problem indicators here:

        * Many different subjects listed, especially generic groups.
        * Any entry where you cannot clearly justify why that subject needs unrestricted cluster-wide admin access.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        # Report all uses of the cluster-admin ClusterRole and highlight likely risks.
        # Run on: any machine with kubectl access and current-context set to target cluster.

        set -euo pipefail

        echo "== ClusterRoleBindings that grant cluster-admin =="
        kubectl get clusterrolebindings -o json \
          | jq -r '
            .items[]
            | select(.roleRef.kind == "ClusterRole" and .roleRef.name == "cluster-admin")
            | [
                .metadata.name,
                .subjects // [] | map(.kind + "/" + .name + (if .namespace then " (ns:" + .namespace + ")" else "" end)) | join(", ")
              ]
            | @tsv
          ' \
          | awk 'BEGIN { printf "%-40s %-60s\n", "CLUSTERROLEBINDING", "SUBJECTS"; print gensub(/./,"-","g",sprintf("%-40s %-60s"," "," ")); } { printf "%-40s %-60s\n", $1, substr($0, index($0,$2)) }'

        echo
        echo "== ClusterRoleBindings with cluster-admin bound to ServiceAccounts (detail) =="
        kubectl get clusterrolebindings -o json \
          | jq -r '
            .items[]
            | select(.roleRef.kind == "ClusterRole" and .roleRef.name == "cluster-admin")
            | {
                name: .metadata.name,
                subjects: (.subjects // [])
              }
            | . as $b
            | $b.subjects[]
            | select(.kind == "ServiceAccount")
            | [
                $b.name,
                .name,
                (.namespace // "<none>")
              ]
            | @tsv
          ' \
          | awk 'BEGIN { printf "%-40s %-40s %-20s\n", "CLUSTERROLEBINDING", "SERVICEACCOUNT", "NAMESPACE"; print gensub(/./,"-","g",sprintf("%-40s %-40s %-20s"," "," "," ")); } { printf "%-40s %-40s %-20s\n", $1, $2, $3 }'

        echo
        echo "== ClusterRoleBindings with cluster-admin bound to Users/Groups (detail) =="
        kubectl get clusterrolebindings -o json \
          | jq -r '
            .items[]
            | select(.roleRef.kind == "ClusterRole" and .roleRef.name == "cluster-admin")
            | {
                name: .metadata.name,
                subjects: (.subjects // [])
              }
            | . as $b
            | $b.subjects[]
            | select(.kind == "User" or .kind == "Group")
            | [
                $b.name,
                .kind,
                .name
              ]
            | @tsv
          ' \
          | awk 'BEGIN { printf "%-40s %-10s %-60s\n", "CLUSTERROLEBINDING", "KIND", "IDENTITY"; print gensub(/./,"-","g",sprintf("%-40s %-10s %-60s"," "," "," ")); } { printf "%-40s %-10s %-60s\n", $1, $2, $3 }'

        echo
        echo "== Summary counts =="
        kubectl get clusterrolebindings -o json \
          | jq '
            .items
            | map(select(.roleRef.kind=="ClusterRole" and .roleRef.name=="cluster-admin")) as $b
            | {
                total_clusterrolebindings_using_cluster_admin: ($b | length),
                total_subjects: ($b | map(.subjects // []) | add | length),
                by_kind: ($b | map(.subjects // []) | add | group_by(.kind) | map({kind: .[0].kind, count: length}))
              }
          '
        ```

        How to interpret the output (what indicates a problem):

        * Any entry in “ClusterRoleBindings that grant cluster-admin” is potentially risky and must be reviewed.
        * Especially suspicious:
          * Bindings where `SUBJECTS` includes generic or shared identities such as:
            * `Group/system:authenticated`, `Group/system:serviceaccounts`, `Group/system:masters` (or similar broad groups).
            * User or group names that look like teams (`devs`, `qa`, `ops`, `developers`, etc.) instead of specific admin identities.
          * ServiceAccounts in application namespaces (e.g., `default`, `prod`, `staging`, `app-*`) rather than a dedicated admin namespace.
        * The JSON “Summary counts” at the end:
          * A `total_clusterrolebindings_using_cluster_admin` greater than a very small number (commonly >1–3) warrants closer review.
          * A large `total_subjects` or `by_kind` entries with many `User`/`Group` subjects indicate overuse of cluster-admin.

        Use this report to decide, per binding, whether the subject truly needs full cluster-admin. If not, remove that ClusterRoleBinding and replace it with a narrower ClusterRole/RoleBinding as appropriate.
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
