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

# Avoid Bindings To System:anonymous

### More Info:

ClusterRoleBindings or RoleBindings to the user system:anonymous grant permissions to unauthenticated callers. Such bindings should be removed or replaced with authenticated, least-privilege bindings.

### 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 bindings to `system:anonymous` and capture them for review:

           ```bash theme={null}
           kubectl get clusterrolebindings -o json | jq -r '
             .items[]
             | select((.subjects | length) > 0)
             | select(any(.subjects[]?;
                 .kind=="User" and .name=="system:anonymous"
               ))
             | "ClusterRoleBinding:\(.metadata.name):ROLE=\(.roleRef.kind)/\(.roleRef.name)"
           ' | tee /tmp/anonymous-clusterrolebindings.txt

           kubectl get rolebindings -A -o json | jq -r '
             .items[]
             | select((.subjects | length) > 0)
             | select(any(.subjects[]?;
                 .kind=="User" and .name=="system:anonymous"
               ))
             | "RoleBinding:\(.metadata.namespace):\(.metadata.name):ROLE=\(.roleRef.kind)/\(.roleRef.name)"
           ' | tee /tmp/anonymous-rolebindings.txt
           ```

        2. For each identified binding, inspect its full specification and permissions to understand what it allows and whether it is still needed. Replace the placeholder names with actual values from step 1:

           ```bash theme={null}
           # ClusterRoleBinding details
           kubectl get clusterrolebinding <CLUSTER_ROLE_BINDING_NAME> -o yaml

           # Namespaced RoleBinding details
           kubectl get rolebinding <ROLE_BINDING_NAME> -n <NAMESPACE> -o yaml

           # Inspect the referenced Role/ClusterRole
           kubectl get clusterrole <CLUSTER_ROLE_NAME> -o yaml
           kubectl get role <ROLE_NAME> -n <NAMESPACE> -o yaml
           ```

        3. Decide on safer access patterns based on your organization’s auth model. For each binding that must continue to exist in some form, choose or create an authenticated subject with least-privilege access (for example, a user-defined group like `my-anon-like-viewers`) and ensure that group is actually used by your authentication system. Create such a group or user in your IdP or GKE IAM configuration as appropriate before proceeding.

        4. For each unsafe binding you will replace, create a new binding to the authenticated, least-privilege subject. Example (adjust names, namespace, and role according to your review):

           ```bash theme={null}
           # Example: replace anonymous cluster-wide access with an authenticated group
           kubectl create clusterrolebinding crb-authenticated-viewers \
             --clusterrole=<EXISTING_OR_NEW_LEAST_PRIVILEGE_CLUSTERROLE> \
             --group=<AUTHENTICATED_GROUP_NAME>

           # Example: namespaced binding
           kubectl create rolebinding rb-authenticated-viewers \
             --namespace <NAMESPACE> \
             --role=<EXISTING_OR_NEW_LEAST_PRIVILEGE_ROLE> \
             --group=<AUTHENTICATED_GROUP_NAME>
           ```

        5. After confirming the new bindings work for intended users or groups, delete the unsafe bindings to `system:anonymous`. Replace names/namespaces with those found in step 1:

           ```bash theme={null}
           # Delete cluster-wide bindings
           kubectl delete clusterrolebinding <CLUSTER_ROLE_BINDING_NAME>

           # Delete namespaced bindings
           kubectl delete rolebinding <ROLE_BINDING_NAME> -n <NAMESPACE>
           ```

        6. Verification (on any machine with kubectl access): re-run the audit to confirm no bindings remain to `system:anonymous`:

           ```bash theme={null}
           (
             kubectl get clusterrolebindings -o json | jq -r '
               .items[]
               | select((.subjects | length) > 0)
               | select(any(.subjects[]?;
                   .kind=="User" and .name=="system:anonymous"
                 ))
               | "FOUND_ANONYMOUS:ClusterRoleBinding:\(.metadata.name):ROLE=\(.roleRef.kind)/\(.roleRef.name)"
             ';
             kubectl get rolebindings -A -o json | jq -r '
               .items[]
               | select((.subjects | length) > 0)
               | select(any(.subjects[]?;
                   .kind=="User" and .name=="system:anonymous"
                 ))
               | "FOUND_ANONYMOUS:RoleBinding:\(.metadata.namespace):\(.metadata.name):ROLE=\(.roleRef.kind)/\(.roleRef.name)"
             '
           ) | (grep -q '^FOUND_ANONYMOUS:' && cat || echo 'NO_ANONYMOUS_BINDINGS')
           ```
      </Accordion>

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

        1. List all bindings to `system:anonymous` (for review)

        ```bash theme={null}
        kubectl get clusterrolebindings -o json | jq -r '
          .items[]
          | select((.subjects | length) > 0)
          | select(any(.subjects[]?;
              .kind=="User" and .name=="system:anonymous"
            ))
          | "ClusterRoleBinding:\(.metadata.name):ROLE=\(.roleRef.kind)/\(.roleRef.name)"
        '

        kubectl get rolebindings -A -o json | jq -r '
          .items[]
          | select((.subjects | length) > 0)
          | select(any(.subjects[]?;
              .kind=="User" and .name=="system:anonymous"
            ))
          | "RoleBinding:\(.metadata.namespace):\(.metadata.name):ROLE=\(.roleRef.kind)/\(.roleRef.name)"
        '
        ```

        2. After deciding which bindings are unsafe and can be removed, delete them

        Replace the placeholder names with the exact ones from step 1.

        ```bash theme={null}
        # Example for cluster-wide bindings
        kubectl delete clusterrolebinding <CLUSTER_ROLE_BINDING_NAME_1>
        kubectl delete clusterrolebinding <CLUSTER_ROLE_BINDING_NAME_2>
        ```

        ```bash theme={null}
        # Example for namespace-scoped bindings
        kubectl delete rolebinding <ROLE_BINDING_NAME_1> -n <NAMESPACE_1>
        kubectl delete rolebinding <ROLE_BINDING_NAME_2> -n <NAMESPACE_2>
        ```

        3. (Optional) Replace with least-privilege, authenticated bindings

        Example: bind a specific group `my-authenticated-users` to an appropriate Role/ClusterRole you have defined.

        ClusterRoleBinding example (cluster-wide):

        ```yaml theme={null}
        apiVersion: rbac.authorization.k8s.io/v1
        kind: ClusterRoleBinding
        metadata:
          name: my-authenticated-users-view
        roleRef:
          apiGroup: rbac.authorization.k8s.io
          kind: ClusterRole
          name: view
        subjects:
          - kind: Group
            name: my-authenticated-users
            apiGroup: rbac.authorization.k8s.io
        ```

        Apply:

        ```bash theme={null}
        kubectl apply -f my-authenticated-users-view-clusterrolebinding.yaml
        ```

        RoleBinding example (namespace-scoped):

        ```yaml theme={null}
        apiVersion: rbac.authorization.k8s.io/v1
        kind: RoleBinding
        metadata:
          name: ns-readers
          namespace: my-namespace
        roleRef:
          apiGroup: rbac.authorization.k8s.io
          kind: Role
          name: ns-read-only
        subjects:
          - kind: Group
            name: my-authenticated-users
            apiGroup: rbac.authorization.k8s.io
        ```

        Apply:

        ```bash theme={null}
        kubectl apply -f ns-readers-rolebinding.yaml
        ```

        4. Verification (same command as audit)

        ```bash theme={null}
        (
          kubectl get clusterrolebindings -o json | jq -r '
            .items[]
            | select((.subjects | length) > 0)
            | select(any(.subjects[]?;
                .kind=="User" and .name=="system:anonymous"
              ))
            | "FOUND_ANONYMOUS:ClusterRoleBinding:\(.metadata.name):ROLE=\(.roleRef.kind)/\(.roleRef.name)"
          ';
          kubectl get rolebindings -A -o json | jq -r '
            .items[]
            | select((.subjects | length) > 0)
            | select(any(.subjects[]?;
                .kind=="User" and .name=="system:anonymous"
              ))
            | "FOUND_ANONYMOUS:RoleBinding:\(.metadata.namespace):\(.metadata.name):ROLE=\(.roleRef.kind)/\(.roleRef.name)"
          '
        ) | (grep -q '^FOUND_ANONYMOUS:' && cat || echo 'NO_ANONYMOUS_BINDINGS')
        ```
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        # Remediation for CIS GKE 4.1.8 – Remove bindings to user "system:anonymous"
        # Runs on: any machine with kubectl, jq, and access to the cluster.

        set -euo pipefail

        # 1) Safety checks
        if ! command -v kubectl >/dev/null 2>&1; then
          echo "ERROR: kubectl not found in PATH" >&2
          exit 1
        fi

        if ! command -v jq >/dev/null 2>&1; then
          echo "ERROR: jq not found in PATH" >&2
          exit 1
        fi

        if ! kubectl version --request-timeout=5s >/dev/null 2>&1; then
          echo "ERROR: Unable to talk to the Kubernetes API with current kubectl context" >&2
          exit 1
        fi

        echo "=== Detecting ClusterRoleBindings and RoleBindings that target user \"system:anonymous\" ==="

        # 2) Discover offending ClusterRoleBindings
        mapfile -t CRB_TO_DELETE < <(
          kubectl get clusterrolebindings -o json | jq -r '
            .items[]
            | select((.subjects // []) | length > 0)
            | select(any(.subjects[]?;
                .kind=="User" and .name=="system:anonymous"
              ))
            | .metadata.name
          '
        )

        # 3) Discover offending RoleBindings (name + namespace)
        # Format: "<namespace> <name>"
        mapfile -t RB_TO_DELETE < <(
          kubectl get rolebindings -A -o json | jq -r '
            .items[]
            | select((.subjects // []) | length > 0)
            | select(any(.subjects[]?;
                .kind=="User" and .name=="system:anonymous"
              ))
            | "\(.metadata.namespace) \(.metadata.name)"
          '
        )

        if [[ ${#CRB_TO_DELETE[@]} -eq 0 && ${#RB_TO_DELETE[@]} -eq 0 ]]; then
          echo "No bindings to user system:anonymous found. Nothing to do."
        else
          echo "The following ClusterRoleBindings reference user system:anonymous:"
          for crb in "${CRB_TO_DELETE[@]}"; do
            echo "  ClusterRoleBinding: ${crb}"
          done

          echo
          echo "The following RoleBindings reference user system:anonymous:"
          for rb in "${RB_TO_DELETE[@]}"; do
            ns="${rb%% *}"
            name="${rb#* }"
            echo "  RoleBinding: ${name} (namespace: ${ns})"
          done

          echo
          echo "WARNING: Deleting these bindings may impact unauthenticated access patterns."
          echo "Ensure you have reviewed their necessity and implemented safer, authenticated alternatives if needed."
          read -r -p "Type 'yes' to proceed with deletion, or anything else to abort: " CONFIRM
          if [[ "${CONFIRM}" != "yes" ]]; then
            echo "Aborting without changes."
            exit 0
          fi

          # 4) Delete offending ClusterRoleBindings
          if [[ ${#CRB_TO_DELETE[@]} -gt 0 ]]; then
            echo "=== Deleting ClusterRoleBindings bound to system:anonymous ==="
            for crb in "${CRB_TO_DELETE[@]}"; do
              echo "Deleting ClusterRoleBinding/${crb} ..."
              # Idempotent: if already gone, ignore error
              kubectl delete clusterrolebinding "${crb}" --ignore-not-found
            done
          fi

          # 5) Delete offending RoleBindings
          if [[ ${#RB_TO_DELETE[@]} -gt 0 ]]; then
            echo "=== Deleting RoleBindings bound to system:anonymous ==="
            for rb in "${RB_TO_DELETE[@]}"; do
              ns="${rb%% *}"
              name="${rb#* }"
              echo "Deleting RoleBinding/${name} in namespace ${ns} ..."
              kubectl delete rolebinding "${name}" --namespace "${ns}" --ignore-not-found
            done
          fi
        fi

        echo
        echo "=== Verification (CIS GKE 4.1.8 audit) ==="
        (
          kubectl get clusterrolebindings -o json | jq -r '
            .items[]
            | select((.subjects | length) > 0)
            | select(any(.subjects[]?;
                .kind=="User" and .name=="system:anonymous"
              ))
            | "FOUND_ANONYMOUS:ClusterRoleBinding:\(.metadata.name):ROLE=\(.roleRef.kind)/\(.roleRef.name)"
          ';
          kubectl get rolebindings -A -o json | jq -r '
            .items[]
            | select((.subjects | length) > 0)
            | select(any(.subjects[]?;
                .kind=="User" and .name=="system:anonymous"
              ))
            | "FOUND_ANONYMOUS:RoleBinding:\(.metadata.namespace):\(.metadata.name):ROLE=\(.roleRef.kind)/\(.roleRef.name)"
          '
        ) | (grep -q '^FOUND_ANONYMOUS:' && cat || echo 'NO_ANONYMOUS_BINDINGS')

        echo "Done."
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
