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
Remediation
Manual Steps
-
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) -
On every control plane node, edit the API server static pod manifest:
sudo vi /etc/kubernetes/manifests/kube-apiserver.yamlIn the
spec.containers[0].commandlist, ensure this flag is present:- --anonymous-auth=falseIf a
--anonymous-auth=flag already exists, change its value tofalse.Note: Saving this file causes the kubelet to automatically restart the kube-apiserver static pod.
-
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-apiserverif Docker is the runtime.) -
On every control plane node, verify the running process includes
--anonymous-auth=falseand no conflicting value:/bin/ps -ef | grep kube-apiserver | grep -v grepConfirm there is a
--anonymous-auth=falseargument present and no--anonymous-auth=trueargument.
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