Skip to main content

Ensure Etcd Cafile Argument Is Appropriate

More Info:​

etcd should be configured to make use of TLS encryption for client connections.

Risk Level​

Low

Address​

Security

Compliance Standards​

  • CIS Kubernetes

Triage and Remediation​

Remediation​

Manual Steps
  1. On every control plane node, confirm the current kube-apiserver manifest and running args:

    sudo cat /etc/kubernetes/manifests/kube-apiserver.yaml
    /bin/ps -ef | grep kube-apiserver | grep -v grep
  2. Ensure you have a CA file that issued the etcd server/client certificates (replace the path below with the actual CA if different):

    ls -l /etc/kubernetes/pki/etcd/ca.crt
    sudo chmod 600 /etc/kubernetes/pki/etcd/ca.crt
    sudo chown root:root /etc/kubernetes/pki/etcd/ca.crt
  3. Edit the kube-apiserver static pod manifest on every control plane node to add or correct the --etcd-cafile flag (this edit will automatically restart the kube-apiserver container when the file is saved):

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

    Under spec.containers[0].command, ensure there is a line similar to:

    - --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt

    Save and exit the editor.

  4. (If etcd is external and using different CA) Adjust the path in step 3 to the correct etcd CA file, and make sure the file exists and is readable by root:

    ls -l /path/to/etcd-ca.crt
    sudo chmod 600 /path/to/etcd-ca.crt
    sudo chown root:root /path/to/etcd-ca.crt
  5. Wait for the kubelet to detect the manifest change and restart the kube-apiserver pod. Confirm the pod is running:

    sudo crictl ps | grep kube-apiserver || sudo docker ps | grep kube-apiserver
  6. Verify the kube-apiserver is now started with the correct --etcd-cafile argument on every control plane node:

    /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -- '--etcd-cafile='
Using kubectl

kubectl cannot modify the kube-apiserver static pod manifest or its process flags, so it cannot be used to set the --etcd-cafile argument. To remediate this finding, you must 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
#
# Fix: Ensure kube-apiserver is configured with --etcd-cafile
# Scope: every control plane node
#
# Requirements:
# - Run as root on each control plane node
# - Static pod manifest at /etc/kubernetes/manifests/kube-apiserver.yaml
# - etcd CA file present at /etc/kubernetes/pki/etcd/ca.crt (adjust ETCD_CA_FILE below if different)

set -euo pipefail

MANIFEST="/etc/kubernetes/manifests/kube-apiserver.yaml"
BACKUP_DIR="/etc/kubernetes/manifests/backup-$(date +%Y%m%d)"
ETCD_CA_FILE="/etc/kubernetes/pki/etcd/ca.crt"

echo "[INFO] Verifying prerequisites..."

if [[ $EUID -ne 0 ]]; then
echo "[ERROR] This script must be run as root." >&2
exit 1
fi

if [[ ! -f "$MANIFEST" ]]; then
echo "[ERROR] kube-apiserver manifest not found at $MANIFEST" >&2
exit 1
fi

if [[ ! -f "$ETCD_CA_FILE" ]]; then
echo "[ERROR] Etcd CA file not found at $ETCD_CA_FILE" >&2
echo "[HINT] Place the correct etcd CA file on this node and update ETCD_CA_FILE in this script if needed." >&2
exit 1
fi

mkdir -p "$BACKUP_DIR"
BACKUP_FILE="$BACKUP_DIR/kube-apiserver.yaml.$(date +%H%M%S)"
cp -p "$MANIFEST" "$BACKUP_FILE"
echo "[INFO] Backup created at $BACKUP_FILE"

echo "[INFO] Ensuring --etcd-cafile is configured in kube-apiserver manifest..."

# If argument already present, update its value in-place; otherwise, add it.
if grep -q -- "--etcd-cafile=" "$MANIFEST"; then
# Idempotent replacement of existing value
sed -i "s#--etcd-cafile=.*#--etcd-cafile=${ETCD_CA_FILE}#g" "$MANIFEST"
else
# Insert argument under the 'command:' section for kube-apiserver
# This keeps the YAML valid and is safe to re-run (guarded by grep above).
awk -v cafile="$ETCD_CA_FILE" '
$0 ~ /- kube-apiserver$/ && in_cmd == 0 {
print $0
in_cmd=1
next
}
in_cmd == 1 && $0 ~ /^ *-/ {
# First argument line after the binary; insert our flag before it once
if (!inserted) {
print " - --etcd-cafile=" cafile
inserted=1
}
print $0
next
}
{ print $0 }
END {
if (!inserted) {
# If we never saw arguments, append the flag at the end of the file
print " - --etcd-cafile=" cafile
}
}
' "$MANIFEST" > "${MANIFEST}.tmp" && mv "${MANIFEST}.tmp" "$MANIFEST"
fi

echo "[INFO] Manifest updated. kube-apiserver static pod will be restarted automatically by kubelet."

echo "[INFO] Waiting for kube-apiserver process to reflect new flag..."
# Give kubelet time to restart the static pod
sleep 20

# Verification: confirm kube-apiserver is running with the correct --etcd-cafile argument
echo "[INFO] Verifying kube-apiserver process flags..."
if /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -q -- "--etcd-cafile=${ETCD_CA_FILE}"; then
echo "[SUCCESS] kube-apiserver is running with --etcd-cafile=${ETCD_CA_FILE}"
exit 0
else
echo "[ERROR] kube-apiserver is NOT running with the expected --etcd-cafile flag." >&2
echo "[INFO] Current kube-apiserver process line(s):" >&2
/bin/ps -ef | grep kube-apiserver | grep -v grep >&2
exit 1
fi

Additional Reading:​