> ## 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 That Anonymous Auth Is Not Enabled

### More Info:

Anonymous authentication allows unauthenticated requests to the kubelet API. Disabling it ensures every request is authenticated, preventing anonymous access to node and workload data.

### Risk Level

Critical

### Address

Security

### Compliance Standards

* CIS EKS

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. On every worker node, SSH in and confirm how kubelet is configured and where its config file is:
           ```bash theme={null}
           ps -ef | grep kubelet
           ```
           If you see a `--config=` argument, note the full path (for example, `/var/lib/kubelet/config.yaml` or `/etc/kubernetes/kubelet.conf`). If there is no `--config` argument, you will use the systemd unit/args file instead.

        2. If kubelet uses a config file (Method 1), edit it to disable anonymous auth (example uses `/var/lib/kubelet/config.yaml`; replace with the actual path you found):
           ```bash theme={null}
           sudo vi /var/lib/kubelet/config.yaml
           ```
           Under the `authentication:` section, ensure it contains:
           ```yaml theme={null}
           authentication:
             anonymous:
               enabled: false
           ```
           If the `authentication` or `anonymous` sections are missing, add them as above, respecting YAML indentation.

        3. If kubelet instead uses executable arguments (Method 2), edit the systemd drop‑in on each worker node (EKS-optimized and similar systems):
           ```bash theme={null}
           sudo vi /etc/systemd/system/kubelet.service.d/10-kubelet-args.conf
           ```
           In the line defining kubelet arguments (often `KUBELET_ARGS=` or inside `ExecStart=`), ensure `--anonymous-auth=false` is present. For example:
           ```ini theme={null}
           Environment="KUBELET_ARGS=... --anonymous-auth=false ..."
           ```
           or in `ExecStart=`:
           ```ini theme={null}
           ExecStart=/usr/bin/kubelet ... --anonymous-auth=false ...
           ```

        4. On every worker node, reload systemd configuration and restart kubelet (this restarts the kubelet and may briefly impact node status/workload reporting):
           ```bash theme={null}
           sudo systemctl daemon-reload
           sudo systemctl restart kubelet.service
           sudo systemctl status kubelet -l
           ```

        5. Verify on every worker node that the kubelet is running and the change is active:
           ```bash theme={null}
           /bin/ps -fC kubelet
           ```
           Inspect the output:
           * If using args, confirm `--anonymous-auth=false` appears.
           * If using a config file, confirm the `--config=` argument points to the file you edited.
      </Accordion>

      <Accordion title="Using kubectl">
        kubectl cannot change kubelet process flags or its on-node configuration file at `/var/lib/kubelet/config.yaml`, so this finding cannot be remediated via the Kubernetes API. Apply the fix directly on every worker node’s host OS as described in the Manual Steps section.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Disable anonymous authentication on kubelet via config file on every worker node.
        # Run this on each worker node over SSH (or via your automation tool of choice).
        # Idempotent: safe to re-run.

        set -euo pipefail

        KUBELET_CONFIG="/var/lib/kubelet/config.yaml"
        BACKUP_SUFFIX="$(date +%Y%m%d%H%M%S)"

        echo "[INFO] Checking for kubelet process..."
        if ! /bin/ps -fC kubelet >/dev/null 2>&1; then
          echo "[ERROR] kubelet process not found. Are you on a worker node?"
          exit 1
        fi

        if [ ! -f "$KUBELET_CONFIG" ]; then
          echo "[ERROR] Kubelet config file $KUBELET_CONFIG not found."
          echo "       This script only handles the config-file method."
          echo "       If your kubelet is configured via executable arguments, use:"
          echo "         sudo vi /etc/systemd/system/kubelet.service.d/10-kubelet-args.conf"
          echo "       and add: --anonymous-auth=false , then restart kubelet."
          exit 1
        fi

        echo "[INFO] Using kubelet config file: $KUBELET_CONFIG"

        # Create a timestamped backup once per run
        BACKUP_FILE="${KUBELET_CONFIG}.bak.${BACKUP_SUFFIX}"
        cp "$KUBELET_CONFIG" "$BACKUP_FILE"
        echo "[INFO] Backup created at $BACKUP_FILE"

        # Ensure authentication and anonymous blocks exist and set enabled: false
        # This edit is idempotent: repeated runs keep enabled: false.

        TMP_FILE="$(mktemp)"
        trap 'rm -f "$TMP_FILE"' EXIT

        awk '
          BEGIN {
            in_auth = 0;
            in_anon = 0;
          }
          /^authentication:/ {
            in_auth = 1;
            in_anon = 0;
          }
          in_auth && /^ *anonymous:/ {
            in_anon = 1;
          }
          in_auth && /^ *[^ #]/ && !/^authentication:/ && !/^ *anonymous:/ {
            # Leaving authentication block
            in_auth = 0;
            in_anon = 0;
          }

          {
            print $0;
          }

          # If we just printed "authentication:" line and there is no anonymous block yet,
          # we will add it later after scanning if needed (handled in END).
        ' "$KUBELET_CONFIG" > "$TMP_FILE"

        # Now enforce/insert the anonymous.enabled: false block using a second pass
        # to avoid complex single-pass logic.
        python3 - "$TMP_FILE" << 'PYEOF'
        import sys, io, re

        path = sys.argv[1]
        with open(path, "r", encoding="utf-8") as f:
            lines = f.readlines()

        out = []
        i = 0
        while i < len(lines):
            line = lines[i]
            # Detect "authentication:" at some indent
            m_auth = re.match(r'^(\s*)authentication:\s*$', line)
            if m_auth:
                indent_auth = m_auth.group(1)
                out.append(line)
                i += 1

                # Collect the block under authentication:
                block = []
                while i < len(lines):
                    l = lines[i]
                    # Next top-level or same/less indent non-empty key that is not part of this block
                    if re.match(r'^\S', l) and not l.startswith(indent_auth + " "):
                        break
                    # If indentation is less than auth indent and not blank/comment, we left the block
                    if (l.strip() and
                        len(l) - len(l.lstrip(" ")) < len(indent_auth)):
                        break
                    block.append(l)
                    i += 1

                # Process block: ensure anonymous.enabled: false exists
                block_text = "".join(block)
                # If anonymous section already exists, rewrite/force enabled: false
                if re.search(r'^\s*anonymous:\s*$', block_text, re.M):
                    new_block = []
                    j = 0
                    in_anon = False
                    anon_indent = ""
                    while j < len(block):
                        bl = block[j]
                        m_anon = re.match(r'^(\s*)anonymous:\s*$', bl)
                        if m_anon:
                            in_anon = True
                            anon_indent = m_anon.group(1)
                            new_block.append(bl)
                            j += 1
                            # Rewrite any enabled: line directly under this block
                            # and ensure one exists.
                            saw_enabled = False
                            sub = []
                            while j < len(block):
                                nl = block[j]
                                # Stop anon block when dedented or new sibling at same level
                                if (nl.strip() and
                                    len(nl) - len(nl.lstrip(" ")) <= len(anon_indent) and
                                    not re.match(r'^\s*#', nl)):
                                    break
                                # Replace enabled line if found
                                if re.match(r'^\s*enabled:\s*', nl):
                                    if not saw_enabled:
                                        sub.append(f"{anon_indent}  enabled: false\n")
                                        saw_enabled = True
                                else:
                                    sub.append(nl)
                                j += 1
                            if not saw_enabled:
                                sub.insert(0, f"{anon_indent}  enabled: false\n")
                            new_block.extend(sub)
                            continue

                        new_block.append(bl)
                        j += 1
                    block = new_block
                else:
                    # No anonymous: section; append one with enabled: false
                    # Place it at the end of the authentication block
                    if block and block[-1] and not block[-1].endswith("\n"):
                        block[-1] = block[-1] + "\n"
                    anon_indent = indent_auth + "  "
                    block.append(f"{anon_indent}anonymous:\n")
                    block.append(f"{anon_indent}  enabled: false\n")

                out.extend(block)
                continue

            out.append(line)
            i += 1

        with open(path, "w", encoding="utf-8") as f:
            f.writelines(out)
        PYEOF

        echo "[INFO] Updated $KUBELET_CONFIG to set authentication.anonymous.enabled: false"

        echo "[INFO] Reloading systemd and restarting kubelet (this will restart the kubelet and may briefly impact node readiness)..."
        if command -v systemctl >/dev/null 2>&1; then
          sudo systemctl daemon-reload
          sudo systemctl restart kubelet.service
          sudo systemctl status kubelet.service -l --no-pager
        else
          echo "[WARN] systemctl not found. Restart kubelet using your OS service manager."
        fi

        echo "[INFO] Verifying kubelet process is running..."
        /bin/ps -fC kubelet || {
          echo "[ERROR] kubelet not running after restart."
          exit 1
        }

        echo "[INFO] Verification: kubelet process details:"
        /bin/ps -fC kubelet

        echo "[INFO] Completed. Anonymous authentication is now disabled in $KUBELET_CONFIG."
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
