> ## 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 Non-Default Bindings To System:unauthenticated

### More Info:

Non-default bindings to the group system:unauthenticated grant permissions to any unauthenticated caller. They 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. List all non-default bindings to `system:unauthenticated` (run on any machine with kubectl access):
           ```bash theme={null}
           kubectl get clusterrolebindings -o json | jq -r '
             .items[]
             | select(.metadata.name != "system:public-info-viewer")
             | select((.subjects | length) > 0)
             | select(any(.subjects[]?;
                 .kind=="Group" and .name=="system:unauthenticated"
               ))
             | "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=="Group" and .name=="system:unauthenticated"
               ))
             | "RoleBinding \(.metadata.namespace)/\(.metadata.name): ROLE=\(.roleRef.kind)/\(.roleRef.name)"
           '
           ```

        2. For each listed binding, inspect its current permissions to understand the impact of removal (any machine with kubectl access):
           ```bash theme={null}
           # Example for a ClusterRoleBinding named "public-view":
           kubectl get clusterrolebinding public-view -o yaml

           # Example for a RoleBinding "ns1/read-public" in namespace "ns1":
           kubectl get rolebinding read-public -n ns1 -o yaml

           # Inspect the referenced Role/ClusterRole to see granted permissions:
           # Suppose roleRef is ClusterRole "view" and Role "ns1-reader":
           kubectl get clusterrole view -o yaml
           kubectl get role ns1-reader -n ns1 -o yaml
           ```

        3. Decide whether each binding is necessary. For any binding that must remain functionally, design a safer alternative:
           * Identify or create an authenticated, user-defined group (for example `myorg-public-viewers`) outside the cluster.
           * Plan to bind that group to the same Role/ClusterRole instead of `system:unauthenticated`, and, if possible, reduce the role’s permissions to least privilege.

        4. Create replacement bindings using authenticated groups where needed (any machine with kubectl access). Example YAML for a replacement `ClusterRoleBinding`:
           ```bash theme={null}
           cat << 'EOF' > safer-public-view-binding.yaml
           apiVersion: rbac.authorization.k8s.io/v1
           kind: ClusterRoleBinding
           metadata:
             name: safer-public-view-binding
           roleRef:
             apiGroup: rbac.authorization.k8s.io
             kind: ClusterRole
             name: view
           subjects:
           - kind: Group
             name: myorg-public-viewers
             apiGroup: rbac.authorization.k8s.io
           EOF

           kubectl apply -f safer-public-view-binding.yaml
           ```
           Adjust names, kind, and namespace for RoleBinding cases:
           ```bash theme={null}
           cat << 'EOF' > safer-ns1-read-binding.yaml
           apiVersion: rbac.authorization.k8s.io/v1
           kind: RoleBinding
           metadata:
             name: safer-ns1-read-binding
             namespace: ns1
           roleRef:
             apiGroup: rbac.authorization.k8s.io
             kind: Role
             name: ns1-reader
           subjects:
           - kind: Group
             name: myorg-ns1-readers
             apiGroup: rbac.authorization.k8s.io
           EOF

           kubectl apply -f safer-ns1-read-binding.yaml
           ```

        5. After confirming that the replacement bindings satisfy your operational requirements (for example by testing access with an account in the new group), delete the unsafe bindings that reference `system:unauthenticated` (any machine with kubectl access):
           ```bash theme={null}
           # Delete each offending ClusterRoleBinding (replace names with those from step 1):
           kubectl delete clusterrolebinding <UNSAFE_CLUSTERROLEBINDING_NAME>

           # Delete each offending RoleBinding (replace namespace/name with those from step 1):
           kubectl delete rolebinding <UNSAFE_ROLEBINDING_NAME> -n <NAMESPACE>
           ```

        6. Verification (any machine with kubectl access):
           ```bash theme={null}
           (
             kubectl get clusterrolebindings -o json | jq -r '
               .items[]
               | select(.metadata.name != "system:public-info-viewer")
               | select((.subjects | length) > 0)
               | select(any(.subjects[]?;
                   .kind=="Group" and .name=="system:unauthenticated"
                 ))
               | "FOUND_UNAUTH: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=="Group" and .name=="system:unauthenticated"
                 ))
               | "FOUND_UNAUTH:RoleBinding:\(.metadata.namespace):\(.metadata.name):ROLE=\(.roleRef.kind)/\(.roleRef.name)"
             '
           ) | (grep -q "^FOUND_UNAUTH:" && cat || echo "NO_NON_DEFAULT_UNAUTH_BINDINGS")
           ```
           Confirm that the output is:
           ```text theme={null}
           NO_NON_DEFAULT_UNAUTH_BINDINGS
           ```
      </Accordion>

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

        1. List all non-default bindings to `system:unauthenticated` (review targets before deleting):

        ```bash theme={null}
        kubectl get clusterrolebindings -o json | jq -r '
          .items[]
          | select(.metadata.name != "system:public-info-viewer")
          | select((.subjects | length) > 0)
          | select(any(.subjects[]?;
              .kind=="Group" and .name=="system:unauthenticated"
            ))
          | .metadata.name
        '

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

        Optionally inspect each binding and its permissions before removal, for example:

        ```bash theme={null}
        # Example for a ClusterRoleBinding
        kubectl get clusterrolebinding <BINDING_NAME> -o yaml

        # Example for a RoleBinding
        kubectl get rolebinding <BINDING_NAME> -n <NAMESPACE> -o yaml
        ```

        2. Delete unsafe ClusterRoleBindings that bind `system:unauthenticated` (after review):

        ```bash theme={null}
        # Replace with each binding name you decide to remove
        kubectl delete clusterrolebinding <CLUSTER_ROLE_BINDING_NAME_1>
        kubectl delete clusterrolebinding <CLUSTER_ROLE_BINDING_NAME_2>
        ```

        3. Delete unsafe RoleBindings that bind `system:unauthenticated` (after review):

        ```bash theme={null}
        # Replace with each namespace/name pair you decide to remove
        kubectl delete rolebinding <ROLE_BINDING_NAME_1> -n <NAMESPACE_1>
        kubectl delete rolebinding <ROLE_BINDING_NAME_2> -n <NAMESPACE_2>
        ```

        4. (Optional) Create safer, authenticated bindings instead of `system:unauthenticated`:

        Example manifest to replace a deleted ClusterRoleBinding, binding to a user-defined group:

        ```yaml theme={null}
        apiVersion: rbac.authorization.k8s.io/v1
        kind: ClusterRoleBinding
        metadata:
          name: example-authenticated-binding
        roleRef:
          apiGroup: rbac.authorization.k8s.io
          kind: ClusterRole
          name: view
        subjects:
          - kind: Group
            apiGroup: rbac.authorization.k8s.io
            name: my-authenticated-group   # non-default, user-defined group
        ```

        Apply it:

        ```bash theme={null}
        kubectl apply -f example-authenticated-binding.yaml
        ```

        5. Verification (rerun the benchmark audit command):

        ```bash theme={null}
        (
          kubectl get clusterrolebindings -o json | jq -r '
            .items[]
            | select(.metadata.name != "system:public-info-viewer")
            | select((.subjects | length) > 0)
            | select(any(.subjects[]?;
                .kind=="Group" and .name=="system:unauthenticated"
              ))
            | "FOUND_UNAUTH: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=="Group" and .name=="system:unauthenticated"
              ))
            | "FOUND_UNAUTH:RoleBinding:\(.metadata.namespace):\(.metadata.name):ROLE=\(.roleRef.kind)/\(.roleRef.name)"
          '
        ) | (grep -q "^FOUND_UNAUTH:" && cat || echo "NO_NON_DEFAULT_UNAUTH_BINDINGS")
        ```
      </Accordion>

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

        # This script removes all non-default RBAC bindings to the group "system:unauthenticated",
        # except the default ClusterRoleBinding "system:public-info-viewer".
        # Run on any machine with kubectl access and appropriate cluster-admin privileges.

        echo "[INFO] Checking for non-default bindings to group system:unauthenticated..."

        # Capture findings from the audit command
        AUDIT_OUTPUT="$(
          (
            kubectl get clusterrolebindings -o json | jq -r '
              .items[]
              | select(.metadata.name != "system:public-info-viewer")
              | select((.subjects | length) > 0)
              | select(any(.subjects[]?;
                  .kind=="Group" and .name=="system:unauthenticated"
                ))
              | "FOUND_UNAUTH: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=="Group" and .name=="system:unauthenticated"
                ))
              | "FOUND_UNAUTH:RoleBinding:\(.metadata.namespace):\(.metadata.name):ROLE=\(.roleRef.kind)/\(.roleRef.name)"
            '
          ) | (grep -q "^FOUND_UNAUTH:" && cat || echo "NO_NON_DEFAULT_UNAUTH_BINDINGS")
        )"

        echo "$AUDIT_OUTPUT"

        if [[ "$AUDIT_OUTPUT" == "NO_NON_DEFAULT_UNAUTH_BINDINGS" ]]; then
          echo "[INFO] No non-default bindings to system:unauthenticated found. Nothing to do."
          exit 0
        fi

        # Parse and remove each offending binding
        echo "[INFO] Removing non-default bindings to system:unauthenticated (after prior operator review)."

        while IFS= read -r line; do
          [[ -z "$line" ]] && continue
          if [[ "$line" == NO_NON_DEFAULT_UNAUTH_BINDINGS* ]]; then
            continue
          fi

          # Expected formats:
          # FOUND_UNAUTH:ClusterRoleBinding:<name>:ROLE=<kind>/<roleName>
          # FOUND_UNAUTH:RoleBinding:<namespace>:<name>:ROLE=<kind>/<roleName>
          IFS=':' read -r _ prefix type_or_ns name rest <<< "$line"

          if [[ "$line" == FOUND_UNAUTH:ClusterRoleBinding:* ]]; then
            crb_name="$name"
            echo "[INFO] Deleting ClusterRoleBinding ${crb_name}"
            kubectl delete clusterrolebinding "${crb_name}" --ignore-not-found
          elif [[ "$line" == FOUND_UNAUTH:RoleBinding:* ]]; then
            rb_namespace="$type_or_ns"
            rb_name="$name"
            echo "[INFO] Deleting RoleBinding ${rb_namespace}/${rb_name}"
            kubectl delete rolebinding "${rb_name}" --namespace "${rb_namespace}" --ignore-not-found
          else
            echo "[WARN] Unrecognized line format, skipping: $line"
          fi
        done <<< "$AUDIT_OUTPUT"

        echo "[INFO] Re-running audit to verify remediation..."

        VERIFY_OUTPUT="$(
          (
            kubectl get clusterrolebindings -o json | jq -r '
              .items[]
              | select(.metadata.name != "system:public-info-viewer")
              | select((.subjects | length) > 0)
              | select(any(.subjects[]?;
                  .kind=="Group" and .name=="system:unauthenticated"
                ))
              | "FOUND_UNAUTH: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=="Group" and .name=="system:unauthenticated"
                ))
              | "FOUND_UNAUTH:RoleBinding:\(.metadata.namespace):\(.metadata.name):ROLE=\(.roleRef.kind)/\(.roleRef.name)"
            '
          ) | (grep -q "^FOUND_UNAUTH:" && cat || echo "NO_NON_DEFAULT_UNAUTH_BINDINGS")
        )"

        echo "$VERIFY_OUTPUT"

        if [[ "$VERIFY_OUTPUT" == "NO_NON_DEFAULT_UNAUTH_BINDINGS" ]]; then
          echo "[INFO] Verification succeeded: no non-default bindings to system:unauthenticated remain."
          exit 0
        else
          echo "[ERROR] Verification failed: some non-default bindings to system:unauthenticated still exist."
          exit 1
        fi
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
