Skip to main content

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

Manual Steps
  1. 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
  2. On every etcd (control plane) node, edit the etcd static pod manifest:

    sudo vi /etc/kubernetes/manifests/etcd.yaml

    In the spec.containers[0].command (or args) section, add or adjust the flag so it appears exactly as:

    - --peer-client-cert-auth=true

    Ensure there is no other --peer-client-cert-auth= flag with a different value.

  3. Save the file and exit the editor. The kubelet will automatically detect the change to /etc/kubernetes/manifests/etcd.yaml and restart the etcd static pod. This causes a brief etcd/control-plane disruption; perform during a maintenance window if needed.

  4. 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.)

  5. 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=true and 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

Additional Reading: