> ## 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 Anonymous Auth Argument Is False

### More Info:

Disable anonymous requests to the API server

### Risk Level

Low

### Address

Security

### Compliance Standards

* CIS Kubernetes

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. On every control plane node, back up the existing manifest:
           ```bash theme={null}
           sudo cp /etc/kubernetes/manifests/kube-apiserver.yaml /etc/kubernetes/manifests/kube-apiserver.yaml.bak.$(date +%F-%H%M%S)
           ```

        2. On every control plane node, edit the API server static pod manifest:

           ```bash theme={null}
           sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml
           ```

           In the `spec.containers[0].command` list, ensure this flag is present:

           ```yaml theme={null}
             - --anonymous-auth=false
           ```

           If a `--anonymous-auth=` flag already exists, change its value to `false`.

           Note: Saving this file causes the kubelet to automatically restart the kube-apiserver static pod.

        3. On every control plane node, wait 30–60 seconds for the kube-apiserver pod to restart, then verify it is running:
           ```bash theme={null}
           sudo crictl ps | grep kube-apiserver
           ```
           (or use `sudo docker ps | grep kube-apiserver` if Docker is the runtime.)

        4. On every control plane node, verify the running process includes `--anonymous-auth=false` and no conflicting value:
           ```bash theme={null}
           /bin/ps -ef | grep kube-apiserver | grep -v grep
           ```
           Confirm there is a `--anonymous-auth=false` argument present and no `--anonymous-auth=true` argument.
      </Accordion>

      <Accordion title="Using kubectl">
        `kubectl` cannot change the `--anonymous-auth` flag because it is configured in the static pod manifest on each control plane node, not via the Kubernetes API. To remediate this finding, edit `/etc/kubernetes/manifests/kube-apiserver.yaml` directly on every control plane node as described in the Manual Steps section.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Remediation: Ensure kube-apiserver is started with --anonymous-auth=false
        # Scope: Run on every control plane node
        # Effect: Editing /etc/kubernetes/manifests/kube-apiserver.yaml will restart the kube-apiserver static pod
        #

        set -euo pipefail

        MANIFEST="/etc/kubernetes/manifests/kube-apiserver.yaml"
        TMP_MANIFEST="/etc/kubernetes/manifests/kube-apiserver.yaml.tmp.$$"

        echo "==> Checking for kube-apiserver manifest at ${MANIFEST}"
        if [[ ! -f "${MANIFEST}" ]]; then
          echo "ERROR: ${MANIFEST} not found on this node. Is this a control plane node with static pods?"
          exit 1
        fi

        echo "==> Ensuring --anonymous-auth=false is configured"

        # Create a backup once per run if not already backed up
        BACKUP="${MANIFEST}.backup-$(date +%Y%m%d%H%M%S)"
        cp -p "${MANIFEST}" "${BACKUP}"
        echo "Backup created at ${BACKUP}"

        # Idempotent edit:
        # - If --anonymous-auth is already set, enforce value 'false'
        # - If not present, add it as a separate argument under the kube-apiserver command/args
        #
        # This uses yq v4 if available for robust YAML handling; otherwise falls back to a safe sed/awk-based edit.

        use_yq=false
        if command -v yq >/dev/null 2>&1; then
          use_yq=true
        fi

        if "${use_yq}"; then
          echo "==> Using yq for YAML-safe editing"
          # Detect if .spec.containers[0].command exists and contains --anonymous-auth=
          if yq '.spec.containers[0].command // [] | map(select(test("^--anonymous-auth="))) | length' "${MANIFEST}" | grep -q '1'; then
            # Update existing flag to false
            yq '(.spec.containers[0].command[] | select(test("^--anonymous-auth=")) ) = "--anonymous-auth=false"' \
              "${MANIFEST}" > "${TMP_MANIFEST}"
          elif yq '.spec.containers[0].args // [] | map(select(test("^--anonymous-auth="))) | length' "${MANIFEST}" | grep -q '1'; then
            # Update existing flag in args
            yq '(.spec.containers[0].args[] | select(test("^--anonymous-auth=")) ) = "--anonymous-auth=false"' \
              "${MANIFEST}" > "${TMP_MANIFEST}"
          else
            # No existing flag; append it to .spec.containers[0].command if present, else to args
            if yq '.spec.containers[0].command // [] | length' "${MANIFEST}" | grep -q '[1-9]'; then
              yq '.spec.containers[0].command += ["--anonymous-auth=false"]' \
                "${MANIFEST}" > "${TMP_MANIFEST}"
            else
              yq '.spec.containers[0].args += ["--anonymous-auth=false"]' \
                "${MANIFEST}" > "${TMP_MANIFEST}"
            fi
          fi
        else
          echo "==> yq not found; using text-based edit (assumes standard kube-apiserver static pod layout)"

          # Text-based method:
          # 1) If any existing --anonymous-auth=.* flag, normalize to --anonymous-auth=false
          # 2) If no flag at all, append it on its own line under 'command:' or 'args:' list

          cp -p "${MANIFEST}" "${TMP_MANIFEST}"

          if grep -q -- '--anonymous-auth=' "${TMP_MANIFEST}"; then
            # Normalize any existing value to false
            sed -i 's/--anonymous-auth=[^"][^ ]*/--anonymous-auth=false/g' "${TMP_MANIFEST}"
          else
            # Try to append under command: list first, then args:
            if grep -qE '^\s*command:\s*$' "${TMP_MANIFEST}"; then
              awk '
                /^\s*command:\s*$/ {
                  print
                  in_cmd=1
                  next
                }
                in_cmd && /^\s*-/ {
                  last_indent=substr($0, 1, match($0, /-/)-1)
                }
                in_cmd && !/^\s*-/ {
                  if (!added) {
                    if (last_indent == "") { last_indent="    " }
                    print last_indent "- --anonymous-auth=false"
                    added=1
                  }
                  in_cmd=0
                }
                { print }
                END {
                  if (in_cmd && !added) {
                    if (last_indent == "") { last_indent="    " }
                    print last_indent "- --anonymous-auth=false"
                  }
                }
              ' "${TMP_MANIFEST}" > "${TMP_MANIFEST}.new" && mv "${TMP_MANIFEST}.new" "${TMP_MANIFEST}"
            elif grep -qE '^\s*args:\s*$' "${TMP_MANIFEST}"; then
              awk '
                /^\s*args:\s*$/ {
                  print
                  in_args=1
                  next
                }
                in_args && /^\s*-/ {
                  last_indent=substr($0, 1, match($0, /-/)-1)
                }
                in_args && !/^\s*-/ {
                  if (!added) {
                    if (last_indent == "") { last_indent="    " }
                    print last_indent "- --anonymous-auth=false"
                    added=1
                  }
                  in_args=0
                }
                { print }
                END {
                  if (in_args && !added) {
                    if (last_indent == "") { last_indent="    " }
                    print last_indent "- --anonymous-auth=false"
                  }
                }
              ' "${TMP_MANIFEST}" > "${TMP_MANIFEST}.new" && mv "${TMP_MANIFEST}.new" "${TMP_MANIFEST}"
            else
              echo "WARNING: Could not find 'command:' or 'args:' section to append --anonymous-auth=false. Manifest left unchanged in ${TMP_MANIFEST}."
            fi
          fi
        fi

        # Replace the manifest atomically
        mv "${TMP_MANIFEST}" "${MANIFEST}"
        chmod --reference="${BACKUP}" "${MANIFEST}" || true
        chown --reference="${BACKUP}" "${MANIFEST}" || true

        echo "==> kube-apiserver manifest updated. The kubelet will restart the kube-apiserver static pod automatically."

        echo "==> Waiting for kube-apiserver process to reflect new flag (this may take up to 60 seconds)..."

        # Wait loop for the process to include the correct flag
        RETRIES=12
        SLEEP_SECONDS=5
        success=false

        for i in $(seq 1 "${RETRIES}"); do
          if /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -q -- '--anonymous-auth=false'; then
            success=true
            break
          fi
          sleep "${SLEEP_SECONDS}"
        done

        echo "==> Verification:"
        /bin/ps -ef | grep kube-apiserver | grep -v grep || true

        if "${success}"; then
          echo "PASS: kube-apiserver is running with --anonymous-auth=false on this control plane node."
          exit 0
        else
          echo "WARNING: kube-apiserver process did not show --anonymous-auth=false within the wait period."
          echo "Please check kubelet and kube-apiserver pod status (e.g. with: crictl ps or docker ps, and journalctl -u kubelet)."
          exit 1
        fi
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>

### Additional Reading:

* [https://kubernetes.io/docs/admin/authentication/#anonymous-requests](https://kubernetes.io/docs/admin/authentication/#anonymous-requests)
