Skip to main content

Kubelet Anonymous Auth Argument Set To False

More Info:

The kubelet --anonymous-auth argument must be set to false. Allowing anonymous authentication lets unauthenticated requests reach the kubelet API and gain access to the node.

Risk Level

Critical

Address

Security

Compliance Standards

  • CIS OKE

Triage and Remediation

Remediation

Manual Steps
  1. On every worker node, open the kubelet systemd drop‑in config for editing:

    sudo vi /etc/systemd/system/kubelet.service.d/00-default.conf
  2. In the ExecStart= line, ensure the --anonymous-auth flag is present and set to false (add it if missing), for example:

    ExecStart=... --anonymous-auth=false ...
  3. If the kubelet instead reads options from /etc/kubernetes/kubelet-config.json, open that file and set the authentication.anonymous.enabled field to false (create the hierarchy if needed):

    sudo vi /etc/kubernetes/kubelet-config.json

    Example snippet:

    {
    "authentication": {
    "anonymous": {
    "enabled": false
    }
    }
    }
  4. Reload systemd configuration on the same worker node:

    sudo systemctl daemon-reload
  5. Restart the kubelet on the same worker node and ensure it is running:

    sudo systemctl restart kubelet.service
    sudo systemctl status kubelet -l
  6. Verify on the same worker node that the kubelet process is running with --anonymous-auth=false:

    /bin/ps -fC kubelet

    Confirm the output contains --anonymous-auth=false and no conflicting --anonymous-auth=true.

Using kubectl

kubectl cannot modify kubelet process flags or host-level config files, so this setting cannot be fixed via the Kubernetes API. To remediate, you must change the kubelet configuration on every worker node (for example in /etc/systemd/system/kubelet.service.d/00-default.conf and /etc/kubernetes/kubelet-config.json), as described in the Manual Steps section.

Automation
#!/usr/bin/env bash
#
# Harden kubelet anonymous authentication on all worker nodes
# CIS OKE 3.2.1 – Ensure that the --anonymous-auth argument is set to false
#
# Usage:
# 1) Put worker node hostnames/IPs into /root/worker-nodes.txt (one per line), or
# set WORKER_NODES env var as a space‑separated list.
# 2) Run this script from an admin machine that has SSH access as root (or via sudo)
# to every worker node.
# 3) Script is idempotent and safe to re‑run.
#

set -euo pipefail

WORKER_NODES_FILE="/root/worker-nodes.txt"

if [[ -z "${WORKER_NODES:-}" ]]; then
if [[ -f "$WORKER_NODES_FILE" ]]; then
# shellcheck disable=SC2002
WORKER_NODES="$(cat "$WORKER_NODES_FILE" | awk 'NF')"
else
echo "ERROR: No worker nodes specified."
echo "Set WORKER_NODES env var (space‑separated) or create $WORKER_NODES_FILE."
exit 1
fi
fi

if [[ -z "$WORKER_NODES" ]]; then
echo "ERROR: Worker node list is empty."
exit 1
fi

echo "Target worker nodes:"
for n in $WORKER_NODES; do echo " - $n"; done
echo

REMOTE_SCRIPT='
set -euo pipefail

CONFIG_FILE="/etc/kubernetes/kubelet-config.json"
SYSTEMD_DIR="/etc/systemd/system/kubelet.service.d"
SYSTEMD_DROPIN="$SYSTEMD_DIR/00-default.conf"

echo "[INFO] Running on $(hostname)"

if [[ ! -f "$SYSTEMD_DROPIN" ]]; then
echo "[INFO] $SYSTEMD_DROPIN not found – creating drop‑in directory and file."
mkdir -p "$SYSTEMD_DIR"
cat > "$SYSTEMD_DROPIN" <<EOF
[Service]
ExecStart=
ExecStart=/usr/bin/kubelet
EOF
fi

if ! grep -q "ExecStart=" "$SYSTEMD_DROPIN"; then
echo "[INFO] No ExecStart line in $SYSTEMD_DROPIN – appending a basic ExecStart."
printf "\n[Service]\nExecStart=/usr/bin/kubelet\n" >> "$SYSTEMD_DROPIN"
fi

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

awk "
/^ExecStart=/ {
line=\$0
# Remove any existing --anonymous-auth flags
gsub(/--anonymous-auth(=([^ \\\\]+))?/, \"\", line)
# Ensure a single space between args
sub(/ +/, \" \", line)
# Ensure we end with a space before appending
if (line !~ / $/) { line=line\" \" }
# Append the desired flag
line=line\"--anonymous-auth=false\"
print line
next
}
{ print }
" "$SYSTEMD_DROPIN" > "$TMP_FILE"

if ! cmp -s "$TMP_FILE" "$SYSTEMD_DROPIN"; then
echo "[INFO] Updating $SYSTEMD_DROPIN with --anonymous-auth=false"
cp "$SYSTEMD_DROPIN" "$SYSTEMD_DROPIN.bak.$(date +%s)"
cp "$TMP_FILE" "$SYSTEMD_DROPIN"
else
echo "[INFO] $SYSTEMD_DROPIN already enforces --anonymous-auth=false"
fi

echo "[INFO] Reloading systemd and restarting kubelet (this will restart kubelet)."
systemctl daemon-reload
systemctl restart kubelet.service

echo "[INFO] Verifying kubelet status:"
systemctl status kubelet -l --no-pager || true

echo "[INFO] Verifying kubelet process flags for --anonymous-auth=false:"
/bin/ps -fC kubelet || true
if /bin/ps -fC kubelet | grep -q -- "--anonymous-auth=false"; then
echo "[INFO] SUCCESS: kubelet is running with --anonymous-auth=false"
else
echo "[WARN] kubelet process does not show --anonymous-auth=false – manual review required."
fi

echo
'

for NODE in $WORKER_NODES; do
echo "===== Processing worker node: $NODE ====="
ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new "root@$NODE" "$REMOTE_SCRIPT"
done

echo "All nodes processed."