Kubelet Client CA File Argument Set As Appropriate
More Info:
The --client-ca-file enables the kubelet to authenticate client certificates against a trusted CA. Setting it ensures client certificate authentication is enforced.
Risk Level
High
Address
Security
Compliance Standards
- CIS Kubernetes
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
On every control plane node, confirm the API server is running as a static pod and locate its manifest:
ps -ef | grep kube-apiserver | grep -v grepls -l /etc/kubernetes/manifests/kube-apiserver.yaml -
On every control plane node, identify (or create if needed) the client CA file you want the API server to trust (replace the path below if your CA is elsewhere):
ls -l /etc/kubernetes/pki/ca.crt -
On every control plane node, edit the API server manifest to add or correct the
--client-ca-fileflag, pointing to your chosen CA file:sudo sed -i 's#^\(\s*-\s*--client-ca-file=\).*#\1/etc/kubernetes/pki/ca.crt#' /etc/kubernetes/manifests/kube-apiserver.yaml || \sudo sed -i '/- --tls-cert-file=/a\ - --client-ca-file=/etc/kubernetes/pki/ca.crt' /etc/kubernetes/manifests/kube-apiserver.yamlSaving this file causes the kubelet to restart the
kube-apiserverstatic pod; expect a brief control-plane disruption while it restarts. -
On every control plane node, wait for the API server container to be recreated and become Ready:
sudo crictl ps | grep kube-apiserver || sudo docker ps | grep kube-apiserver -
On any machine with
kubectlaccess, confirm the API server is responding again:kubectl get --raw=/healthz -
Verification (on every control plane node): confirm the
--client-ca-fileargument is present and set as intended:ps -ef | grep kube-apiserver | grep -v grep | grep -- '--client-ca-file=/etc/kubernetes/pki/ca.crt'
Using kubectl
kubectl cannot configure the kube-apiserver process flags or edit the static pod manifest on the host. To remediate this finding, you must modify /etc/kubernetes/manifests/kube-apiserver.yaml directly on every control plane node; see the Manual Steps section for exact host-level instructions.
Automation
#!/usr/bin/env bash
#
# Automation: Ensure kube-apiserver is started with --client-ca-file on every control plane node
#
# Usage:
# 1. Run on each control plane node with sudo/root.
# 2. Adjust CA_PATH below if your client CA is at a different location.
# 3. Re‑run safely; script is idempotent.
set -euo pipefail
CA_PATH="/etc/kubernetes/pki/ca.crt"
APISERVER_MANIFEST="/etc/kubernetes/manifests/kube-apiserver.yaml"
TMP_MANIFEST="/etc/kubernetes/manifests/kube-apiserver.yaml.tmp"
echo "[*] Running on control plane node: $(hostname)"
# Basic prechecks
if [[ ! -f "${APISERVER_MANIFEST}" ]]; then
echo "ERROR: ${APISERVER_MANIFEST} not found. This script expects a static pod apiserver manifest."
exit 1
fi
if [[ ! -f "${CA_PATH}" ]]; then
echo "WARNING: Client CA file ${CA_PATH} not found."
echo "Create/populate the appropriate client CA at this path before relying on certificate authentication."
# We still proceed to set the flag to this path so it's wired consistently.
fi
echo "[*] Ensuring --client-ca-file is configured in ${APISERVER_MANIFEST}"
# Backup manifest once
BACKUP="${APISERVER_MANIFEST}.$(date +%Y%m%d%H%M%S).bak"
cp -n "${APISERVER_MANIFEST}" "${BACKUP}" || true
# Idempotently ensure the flag exists and points to CA_PATH.
# Strategy:
# - If any --client-ca-file appears, normalize it to the desired path.
# - If none appears, add it to the command line args for kube-apiserver.
if grep -q -- "--client-ca-file" "${APISERVER_MANIFEST}"; then
# Normalize existing flag(s) to the desired path
sed -E "s#(--client-ca-file=)[^[:space:]]*#\1${CA_PATH}#g" "${APISERVER_MANIFEST}" > "${TMP_MANIFEST}"
else
# Insert flag into args list. We try to add a new '- --client-ca-file=...' line
# after the first '- --secure-port=' or similar existing arg, falling back to
# appending inside the args list.
if grep -qE '^\s*- --secure-port=' "${APISERVER_MANIFEST}"; then
awk -v ca="--client-ca-file=${CA_PATH}" '
/^\s*- --secure-port=/ && !added {
print
print " - " ca
added=1
next
}
{ print }
' "${APISERVER_MANIFEST}" > "${TMP_MANIFEST}"
else
# Generic append inside args: block
awk -v ca="--client-ca-file=${CA_PATH}" '
$0 ~ /^\s*args:\s*$/ && !added {
print
getline
print
print " - " ca
added=1
next
}
{ print }
' "${APISERVER_MANIFEST}" > "${TMP_MANIFEST}"
fi
fi
mv "${TMP_MANIFEST}" "${APISERVER_MANIFEST}"
echo "[*] Updated ${APISERVER_MANIFEST}. kubelet will restart the kube-apiserver static pod automatically."
echo " NOTE: This restarts the API server on this control plane node."
# Wait briefly for kube-apiserver to restart and stabilize
sleep 15
echo "[*] Verifying kube-apiserver process has --client-ca-file=${CA_PATH}"
if /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -q -- "--client-ca-file=${CA_PATH}"; then
echo "[OK] kube-apiserver is running with --client-ca-file=${CA_PATH}"
exit 0
else
echo "ERROR: kube-apiserver is not running with the expected --client-ca-file flag."
echo "Current kube-apiserver command line:"
/bin/ps -ef | grep kube-apiserver | grep -v grep || true
exit 1
fi