Skip to main content

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

Remediation

Manual Steps
  1. On every control plane node, back up the existing manifest:

    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:

    sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml

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

    - --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:

    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:

    /bin/ps -ef | grep kube-apiserver | grep -v grep

    Confirm there is a --anonymous-auth=false argument present and no --anonymous-auth=true argument.

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.

Automation
#!/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

Additional Reading: