Ensure Client Cert Auth Argument Is Enabled
More Info:
Enable client authentication on etcd service.
Risk Level
Medium
Address
Security
Compliance Standards
- CIS Kubernetes
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
On every etcd (control plane) node, open the etcd static pod manifest for editing:
sudo vi /etc/kubernetes/manifests/etcd.yaml -
In the
spec.containers[0].command(orargs) list for theetcdcontainer, add or update the client auth flag so it is exactly:- --client-cert-auth=trueEnsure there is no conflicting
--client-cert-authentry with a different value. -
Save and exit the editor. The kubelet will automatically detect the change to
/etc/kubernetes/manifests/etcd.yamland restart the etcd static pod; expect a brief etcd interruption while it restarts. -
Wait for etcd to come back up and confirm the etcd pod is running (on a control plane node that has
crictlordocker, as appropriate):sudo crictl ps | grep etcd || sudo docker ps | grep etcd -
Verify that the etcd process is now running with
--client-cert-auth=trueon each etcd node:/bin/ps -ef | /bin/grep etcd | /bin/grep -v grepConfirm the output includes
--client-cert-auth=trueand no occurrence of--client-cert-auth=false.
Using kubectl
kubectl cannot modify the etcd static pod manifest or its process flags; this setting must be changed directly on each etcd node by editing /etc/kubernetes/manifests/etcd.yaml. Refer to the Manual Steps section for the required host-level changes and verification commands.
Automation
#!/usr/bin/env bash
#
# Enable etcd --client-cert-auth="true" in /etc/kubernetes/manifests/etcd.yaml
# Scope: run on every etcd (control plane) node
# Impact: editing the static pod manifest will cause the etcd pod to restart.
set -euo pipefail
ETCD_MANIFEST="/etc/kubernetes/manifests/etcd.yaml"
TMP_MANIFEST="/tmp/etcd.yaml.$$"
echo "[INFO] Starting etcd --client-cert-auth remediation"
if [[ ! -f "${ETCD_MANIFEST}" ]]; then
echo "[ERROR] ${ETCD_MANIFEST} not found on this node; is this an etcd/control-plane node?"
exit 1
fi
# Backup once per host (idempotent: do not overwrite an existing backup)
BACKUP="${ETCD_MANIFEST}.bak"
if [[ ! -f "${BACKUP}" ]]; then
cp -p "${ETCD_MANIFEST}" "${BACKUP}"
echo "[INFO] Backup created at ${BACKUP}"
else
echo "[INFO] Backup already exists at ${BACKUP}, not overwriting"
fi
# Check if argument already present with value true
if grep -qE -- '--client-cert-auth(=|: )"?true"?' "${ETCD_MANIFEST}"; then
echo "[INFO] --client-cert-auth already set to true; no change required"
else
echo "[INFO] Ensuring --client-cert-auth=\"true\" in ${ETCD_MANIFEST}"
# Work on a temp copy
cp "${ETCD_MANIFEST}" "${TMP_MANIFEST}"
if grep -q -- '--client-cert-auth' "${TMP_MANIFEST}"; then
# Replace existing flag value (covers --client-cert-auth=false or different formatting)
sed -i -E 's#(--client-cert-auth)(=|: )"?[^" ]*"?#\1="true"#' "${TMP_MANIFEST}"
else
# Insert the flag under the etcd container args list
# This assumes a typical kubeadm-style manifest with 'containers:' and 'name: etcd'
# and an 'args:' list. If not found, we fall back to appending to args list line.
if grep -qE 'name: etcd' "${TMP_MANIFEST}" && grep -qE 'args:' "${TMP_MANIFEST}"; then
awk '
/name:[[:space:]]*etcd/ { in_etcd=1 }
in_etcd && /args:/ { in_args=1 }
in_args && /^\s*-[[:space:]]/ { last_arg_line=NR }
{ lines[NR]=$0 }
END {
for (i=1; i<=NR; i++) {
print lines[i]
if (i==last_arg_line) {
# indent to match other args (2 spaces more than "- " line is typical)
split(lines[i],a,"- ")
indent=index(lines[i],"-")-1
pad=""
for (j=0;j<indent;j++) pad=pad " "
print pad "- --client-cert-auth=\"true\""
}
}
}
' "${TMP_MANIFEST}" > "${TMP_MANIFEST}.new" && mv "${TMP_MANIFEST}.new" "${TMP_MANIFEST}"
else
echo "[WARN] Could not reliably locate etcd args list; attempting generic append"
# Generic append: add a new arg line under the first 'args:' we see
awk '
/args:/ && !done { print; print " - --client-cert-auth=\"true\""; done=1; next }
{ print }
' "${TMP_MANIFEST}" > "${TMP_MANIFEST}.new" && mv "${TMP_MANIFEST}.new" "${TMP_MANIFEST}"
fi
fi
# Move temp manifest into place (this will trigger kubelet to restart the etcd static pod)
mv "${TMP_MANIFEST}" "${ETCD_MANIFEST}"
echo "[INFO] Updated ${ETCD_MANIFEST} with --client-cert-auth=\"true\""
fi
# Verification: wait for etcd to be running, then check process args
echo "[INFO] Verifying etcd process has --client-cert-auth=true"
# Give kubelet some time in case the pod restarted
sleep 10
if /bin/ps -ef | /bin/grep etcd | /bin/grep -v grep | /bin/grep -q -- '--client-cert-auth=true'; then
echo "[SUCCESS] etcd is running with --client-cert-auth=true"
exit 0
fi
echo "[WARN] --client-cert-auth=true not yet visible in etcd process args; retrying verification..."
sleep 10
if /bin/ps -ef | /bin/grep etcd | /bin/grep -v grep | /bin/grep -q -- '--client-cert-auth=true'; then
echo "[SUCCESS] etcd is running with --client-cert-auth=true"
exit 0
else
echo "[ERROR] Verification failed: etcd process not showing --client-cert-auth=true"
/bin/ps -ef | /bin/grep etcd | /bin/grep -v grep || true
exit 2
fi