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

# No RoleBinding Should Grant Access To Anonymous Or Unauthenticated Users

### More Info:

Verifies no (Cluster)RoleBinding targets system:anonymous or system:unauthenticated. Such bindings grant access to unauthenticated callers.

### Risk Level

Critical

### Address

Security

### Compliance Standards

* Cloudanix Best Practice

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. On any machine with kubectl access, list all RoleBindings and ClusterRoleBindings that target `system:anonymous` or `system:unauthenticated` and review them to understand what they grant and whether they are truly needed:

           ```bash theme={null}
           kubectl get rolebindings,clusterrolebindings --all-namespaces -o json | jq -r '
             [ .items[]
               | .kind as $kind | .apiVersion as $api | .metadata as $m
               | ((.subjects // [])[] | select(.name == "system:anonymous" or .name == "system:unauthenticated"))
               | "kind=\($kind)"
                 + (if ($m.namespace // "") == "" then "" else " ns=\($m.namespace)" end)
                 + " name=\($m.name) uid=\($m.uid)"
                 + (if ($api // "") == "" then "" else " apiVersion=\($api)" end)
                 + (if ($m.creationTimestamp // "") == "" then "" else " created=\($m.creationTimestamp)" end)
                 + " subject=\(.name) is_compliant=false"
             ] as $rows
             | if ($rows | length) == 0 then "is_compliant=true" else $rows[] end'
           ```

        2. For each listed binding, fetch the full YAML and record it (for rollback or to recreate with a safer subject such as a specific Group, User, or ServiceAccount):

           ```bash theme={null}
           # Example for a namespaced RoleBinding
           kubectl get rolebinding <ROLEBINDING_NAME> -n <NAMESPACE> -o yaml > /tmp/<ROLEBINDING_NAME>.yaml

           # Example for a ClusterRoleBinding
           kubectl get clusterrolebinding <CLUSTERROLEBINDING_NAME> -o yaml > /tmp/<CLUSTERROLEBINDING_NAME>.yaml
           ```

        3. Decide whether each binding can simply be deleted (preferred), or whether you must instead rebind the same Role/ClusterRole to an authenticated subject (e.g., a specific service account or group). Document the chosen replacement subject for each binding that must be preserved.

        4. On any machine with kubectl access, delete each RoleBinding or ClusterRoleBinding whose subject is `system:anonymous` or `system:unauthenticated`:

           ```bash theme={null}
           # Namespaced RoleBinding
           kubectl delete rolebinding <ROLEBINDING_NAME> -n <NAMESPACE>

           # ClusterRoleBinding
           kubectl delete clusterrolebinding <CLUSTERROLEBINDING_NAME>
           ```

        5. If you need to preserve the permission but for an authenticated subject, recreate an equivalent binding that omits `system:anonymous` / `system:unauthenticated` and uses your chosen subject instead. For example:

           ```bash theme={null}
           cat << 'EOF' | kubectl apply -f -
           apiVersion: rbac.authorization.k8s.io/v1
           kind: RoleBinding
           metadata:
             name: <NEW_ROLEBINDING_NAME>
             namespace: <NAMESPACE>
           roleRef:
             apiGroup: rbac.authorization.k8s.io
             kind: Role
             name: <EXISTING_ROLE_NAME>
           subjects:
           - kind: ServiceAccount
             name: <SERVICEACCOUNT_NAME>
             namespace: <NAMESPACE>
           EOF
           ```

        6. Verification (on any machine with kubectl access): rerun the audit command and confirm that it returns only the compliance sentinel and no bindings with `system:anonymous` or `system:unauthenticated`:

           ```bash theme={null}
           kubectl get rolebindings,clusterrolebindings --all-namespaces -o json | jq -r '
             [ .items[]
               | .kind as $kind | .apiVersion as $api | .metadata as $m
               | ((.subjects // [])[] | select(.name == "system:anonymous" or .name == "system:unauthenticated"))
               | "kind=\($kind)"
                 + (if ($m.namespace // "") == "" then "" else " ns=\($m.namespace)" end)
                 + " name=\($m.name) uid=\($m.uid)"
                 + (if ($api // "") == "" then "" else " apiVersion=\($api)" end)
                 + (if ($m.creationTimestamp // "") == "" then "" else " created=\($m.creationTimestamp)" end)
                 + " subject=\(.name) is_compliant=false"
             ] as $rows
             | if ($rows | length) == 0 then "is_compliant=true" else $rows[] end'
           ```
      </Accordion>

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

        1. List offending RoleBindings and ClusterRoleBindings (review before deleting):

        ```bash theme={null}
        kubectl get rolebindings,clusterrolebindings --all-namespaces -o wide \
          | grep -E 'system:anonymous|system:unauthenticated' || true
        ```

        2. For each violating RoleBinding, delete it. Example commands (replace with the actual names/namespaces you saw):

        ```bash theme={null}
        # Example RoleBindings
        kubectl delete rolebinding rb-anon-access -n default
        kubectl delete rolebinding rb-unauthenticated-view -n kube-system

        # Example ClusterRoleBindings
        kubectl delete clusterrolebinding crb-anon-access
        kubectl delete clusterrolebinding crb-unauthenticated-view
        ```

        If you manage these via manifests (GitOps/IaC), also remove the corresponding `RoleBinding` or `ClusterRoleBinding` objects (those whose `subjects` have `name: system:anonymous` or `name: system:unauthenticated`) from your declarative configuration and apply:

        ```bash theme={null}
        kubectl apply -f <your-updated-manifests>.yaml
        ```

        3. Verification (same command as the audit):

        ```bash theme={null}
        kubectl get rolebindings,clusterrolebindings --all-namespaces -o json | jq -r '
          [ .items[]
            | .kind as $kind | .apiVersion as $api | .metadata as $m
            | ((.subjects // [])[] | select(.name == "system:anonymous" or .name == "system:unauthenticated"))
            | "kind=\($kind)"
              + (if ($m.namespace // "") == "" then "" else " ns=\($m.namespace)" end)
              + " name=\($m.name) uid=\($m.uid)"
              + (if ($api // "") == "" then "" else " apiVersion=\($api)" end)
              + (if ($m.creationTimestamp // "") == "" then "" else " created=\($m.creationTimestamp)" end)
              + " subject=\(.name) is_compliant=false"
          ] as $rows
          | if ($rows | length) == 0 then "is_compliant=true" else $rows[] end'
        ```
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Remove any RoleBinding or ClusterRoleBinding that grants access
        # to system:anonymous or system:unauthenticated.
        #
        # Run on: any machine with kubectl access and current context set.
        # Idempotent: safe to re-run; only currently offending bindings are deleted.

        set -euo pipefail

        # Fail fast if kubectl or jq are missing
        command -v kubectl >/dev/null 2>&1 || { echo "kubectl not found in PATH" >&2; exit 1; }
        command -v jq >/dev/null 2>&1 || { echo "jq not found in PATH" >&2; exit 1; }

        echo "Discovering RoleBindings and ClusterRoleBindings that target system:anonymous or system:unauthenticated..."

        # Get offending RoleBindings
        mapfile -t RB_TO_DELETE < <(
          kubectl get rolebindings --all-namespaces -o json \
          | jq -r '
              .items[]
              | select((.subjects // [])[]?.name == "system:anonymous"
                       or (.subjects // [])[]?.name == "system:unauthenticated")
              | "\(.metadata.namespace),\(.metadata.name)"
            ' \
          | sort -u
        )

        # Get offending ClusterRoleBindings
        mapfile -t CRB_TO_DELETE < <(
          kubectl get clusterrolebindings -o json \
          | jq -r '
              .items[]
              | select((.subjects // [])[]?.name == "system:anonymous"
                       or (.subjects // [])[]?.name == "system:unauthenticated")
              | .metadata.name
            ' \
          | sort -u
        )

        if [[ ${#RB_TO_DELETE[@]} -eq 0 && ${#CRB_TO_DELETE[@]} -eq 0 ]]; then
          echo "No offending RoleBindings or ClusterRoleBindings found."
        else
          echo "Deleting offending RoleBindings..."
          for entry in "${RB_TO_DELETE[@]}"; do
            ns="${entry%%,*}"
            name="${entry##*,}"
            if [[ -n "$ns" && -n "$name" ]]; then
              echo "  - Deleting RoleBinding '$name' in namespace '$ns'"
              kubectl delete rolebinding "$name" -n "$ns" --ignore-not-found
            fi
          done

          echo "Deleting offending ClusterRoleBindings..."
          for name in "${CRB_TO_DELETE[@]}"; do
            if [[ -n "$name" ]]; then
              echo "  - Deleting ClusterRoleBinding '$name'"
              kubectl delete clusterrolebinding "$name" --ignore-not-found
            fi
          done
        fi

        echo
        echo "Verifying compliance..."

        kubectl get rolebindings,clusterrolebindings --all-namespaces -o json | jq -r '
          [ .items[]
            | .kind as $kind | .apiVersion as $api | .metadata as $m
            | ((.subjects // [])[] | select(.name == "system:anonymous" or .name == "system:unauthenticated"))
            | "kind=\($kind)"
              + (if ($m.namespace // "") == "" then "" else " ns=\($m.namespace)" end)
              + " name=\($m.name) uid=\($m.uid)"
              + (if ($api // "") == "" then "" else " apiVersion=\($api)" end)
              + (if ($m.creationTimestamp // "") == "" then "" else " created=\($m.creationTimestamp)" end)
              + " subject=\(.name) is_compliant=false"
          ] as $rows
          | if ($rows | length) == 0 then "is_compliant=true" else $rows[] end
        '
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
