Ensure Peer Client Cert Auth Argument Is Enabled
More Info:
etcd should be configured for peer authentication
Risk Level
Medium
Address
Security
Compliance Standards
- CIS Kubernetes
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
On every etcd (control plane) node, back up the existing manifest:
sudo cp -a /etc/kubernetes/manifests/etcd.yaml /etc/kubernetes/manifests/etcd.yaml.bak -
On every etcd (control plane) node, edit the etcd static pod manifest:
sudo vi /etc/kubernetes/manifests/etcd.yamlIn the
spec.containers[0].command(orargs) section, add or adjust the flag so it appears exactly as:- --peer-client-cert-auth=trueEnsure there is no other
--peer-client-cert-auth=flag with a different value. -
Save the file and exit the editor. The kubelet will automatically detect the change to
/etc/kubernetes/manifests/etcd.yamland restart the etcd static pod. This causes a brief etcd/control-plane disruption; perform during a maintenance window if needed. -
On every etcd (control plane) node, wait for the etcd container to restart and become running:
sudo crictl ps | grep etcd || sudo docker ps | grep etcd(Use the appropriate container runtime command for your nodes.)
-
On every etcd (control plane) node, verify the flag is now set:
/bin/ps -ef | /bin/grep etcd | /bin/grep -v grep | /bin/grep -- '--peer-client-cert-auth=true'The command should return the etcd process line containing
--peer-client-cert-auth=trueand no occurrences with=false.
Using kubectl
kubectl cannot modify the etcd static pod manifest or its process flags, so this finding cannot be fixed via the Kubernetes API. To remediate, you must edit /etc/kubernetes/manifests/etcd.yaml directly on every etcd node; follow the guidance in the Manual Steps section.
Automation
#!/usr/bin/env bash
#
# Enable etcd --peer-client-cert-auth on all control plane nodes.
# Usage: run on each control plane node with sudo/root.
#
# Operational impact:
# - Editing /etc/kubernetes/manifests/etcd.yaml will cause the etcd static pod
# to be recreated automatically by the kubelet on this node.
set -euo pipefail
ETCD_MANIFEST="/etc/kubernetes/manifests/etcd.yaml"
BACKUP_DIR="/etc/kubernetes/manifests/backup-peer-client-cert-auth"
TMP_MANIFEST="/tmp/etcd.yaml.$$"
if [[ $EUID -ne 0 ]]; then
echo "ERROR: Run this script as root (sudo) on the control plane node."
exit 1
fi
if [[ ! -f "$ETCD_MANIFEST" ]]; then
echo "ERROR: etcd manifest not found at $ETCD_MANIFEST"
exit 1
fi
mkdir -p "$BACKUP_DIR"
# Backup once per day (idempotent enough; keep history)
BACKUP_FILE="$BACKUP_DIR/etcd.yaml.$(date +%Y%m%d_%H%M%S)"
cp "$ETCD_MANIFEST" "$BACKUP_FILE"
echo "Backup created at $BACKUP_FILE"
# Ensure the --peer-client-cert-auth flag is present and set to true.
#
# This is a YAML-aware-ish edit using awk/sed that:
# - If a line containing --peer-client-cert-auth exists, sets it to true.
# - Otherwise, adds a new line under the etcd container args section.
#
# Assumptions:
# - The container is named "etcd".
# - There is an args: list for the etcd container (common in kubeadm setups).
awk '
BEGIN {
in_etcd_container = 0
in_args = 0
done_flag = 0
}
/name: etcd/ {
in_etcd_container = 1
}
in_etcd_container == 1 && /^[[:space:]]*name:/ && $2 != "etcd" {
in_etcd_container = 0
in_args = 0
}
in_etcd_container == 1 && /^[[:space:]]*args:/ {
in_args = 1
}
in_args == 1 && /^[[:space:]]*-[[:space:]]*["'\'']?--peer-client-cert-auth=/ {
sub(/--peer-client-cert-auth=.*/, "--peer-client-cert-auth=true")
done_flag = 1
}
{
print
}
# If we are in args list for etcd and reach the end of the args block
# without having added the flag, append it before leaving.
in_etcd_container == 1 && in_args == 1 && /^[[:space:]]*-[[:space:]]*["'\'']?--/ && done_flag == 0 {
# no-op; handled below based on lookahead
}
' "$ETCD_MANIFEST" > "$TMP_MANIFEST"
# If we did not manage to modify or add via awk (e.g., no existing flag),
# append the flag under the etcd container args section using a simpler sed pass.
if ! grep -q -- "--peer-client-cert-auth=true" "$TMP_MANIFEST"; then
# Try to insert after the args: line of etcd container
# This is best-effort and idempotent (we already checked final presence).
mv "$TMP_MANIFEST" "${TMP_MANIFEST}.tmp"
awk '
BEGIN {
in_etcd_container = 0
inserted = 0
}
/name: etcd/ {
in_etcd_container = 1
}
in_etcd_container == 1 && /^[[:space:]]*name:/ && $2 != "etcd" {
in_etcd_container = 0
}
{
print
if (in_etcd_container == 1 && /^[[:space:]]*args:/ && inserted == 0) {
# Determine indentation from next line or default to 4 spaces + "- "
getline nextline
if (nextline ~ /^[[:space:]]*-[[:space:]]*"/) {
match(nextline, /^([[:space:]]*)-[[:space:]]*"/, m)
indent = m[1]
} else {
indent = " "
}
print nextline
print indent "- --peer-client-cert-auth=true"
inserted = 1
next
}
}
' "${TMP_MANIFEST}.tmp" > "$TMP_MANIFEST"
fi
# If we still do not have the flag, fail safely.
if ! grep -q -- "--peer-client-cert-auth=true" "$TMP_MANIFEST"; then
echo "ERROR: Failed to ensure --peer-client-cert-auth=true in $ETCD_MANIFEST"
rm -f "$TMP_MANIFEST" "${TMP_MANIFEST}.tmp" 2>/dev/null || true
exit 1
fi
# Deploy the updated manifest
mv "$TMP_MANIFEST" "$ETCD_MANIFEST"
chmod 600 "$ETCD_MANIFEST"
echo "Updated $ETCD_MANIFEST with --peer-client-cert-auth=true."
echo "Kubelet will restart the etcd static pod automatically."
# Wait for etcd to restart and then verify.
echo "Waiting up to 60 seconds for etcd to restart..."
sleep 10
# Simple loop to give the process time to come back
for i in {1..10}; do
if /bin/ps -ef | /bin/grep "[e]tcd" >/dev/null 2>&1; then
break
fi
sleep 5
done
echo "Verifying etcd process flags..."
/bin/ps -ef | /bin/grep etcd | /bin/grep -v grep | grep -- "--peer-client-cert-auth=true" >/dev/null 2>&1 && {
echo "SUCCESS: etcd is running with --peer-client-cert-auth=true"
exit 0
}
echo "WARNING: etcd process is running but --peer-client-cert-auth=true not found in flags."
/bin/ps -ef | /bin/grep etcd | /bin/grep -v grep
exit 1