Ensure Client Ca File Argument Is Appropriate
More Info:
Setup TLS connection on the API server.
Risk Level
Low
Address
Security
Compliance Standards
- CIS Kubernetes
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
On every control plane node, confirm the current kube-apiserver options and identify whether
--client-ca-fileis present and what it is set to:ps -ef | grep kube-apiserver | grep -v grepIf
--client-ca-fileis missing or incorrect, proceed. -
On the same control plane node, ensure you have (or create) a valid client CA file that will sign client certificates used to authenticate to the API server, for example:
ls -l /etc/kubernetes/pki/ca.crtIf you need a dedicated client CA, place it in a secure path such as
/etc/kubernetes/pki/client-ca.crtand ensure it is readable by the kube-apiserver process:chown root:root /etc/kubernetes/pki/client-ca.crtchmod 600 /etc/kubernetes/pki/client-ca.crt -
Edit the kube-apiserver static pod manifest on the control plane node:
sudo vi /etc/kubernetes/manifests/kube-apiserver.yamlIn the
spec.containers[0].commandlist, add or correct the flag so it points to your chosen client CA file, for example:- --client-ca-file=/etc/kubernetes/pki/client-ca.crtSave and exit. Editing this file will automatically restart the kube-apiserver static pod.
-
Still on the control plane node, ensure the path in
--client-ca-filematches an existing file and that the directory is not writable by non-privileged users:ls -l /etc/kubernetes/pki/client-ca.crtls -ld /etc/kubernetes/pki -
Wait for the kube-apiserver static pod to restart and become Ready:
crictl ps | grep kube-apiserver || docker ps | grep kube-apiserver -
Verification (on every control plane node): confirm the running kube-apiserver process includes the correct
--client-ca-fileargument and path:ps -ef | grep kube-apiserver | grep -v grep | grep -- '--client-ca-file='Ensure the printed value matches the intended client CA file path.
Using kubectl
kubectl cannot modify the kube-apiserver static pod manifest or its process flags, including --client-ca-file, because these are defined in /etc/kubernetes/manifests/kube-apiserver.yaml on each control plane node. To remediate this finding, make the changes directly on the node as described in the Manual Steps section.
Automation
#!/usr/bin/env bash
#
# Automation: Ensure kube-apiserver is started with a valid --client-ca-file
#
# Run on: every control plane node (with root privileges)
#
# Requirements:
# - bash
# - yq (v4) for safe YAML edits: https://github.com/mikefarah/yq
#
# Behavior:
# - Ensures /etc/kubernetes/pki/client-ca.crt exists (or create from cluster CA if appropriate)
# - Ensures kube-apiserver manifest has --client-ca-file set to that path
# - Relies on kubelet to restart kube-apiserver static pod
# - Idempotent: safe to re-run
set -euo pipefail
MANIFEST="/etc/kubernetes/manifests/kube-apiserver.yaml"
CLIENT_CA_DEFAULT="/etc/kubernetes/pki/client-ca.crt"
echo "[INFO] Starting remediation for --client-ca-file on kube-apiserver"
if [[ $EUID -ne 0 ]]; then
echo "[ERROR] This script must be run as root on each control plane node." >&2
exit 1
fi
if ! command -v yq >/dev/null 2>&1; then
echo "[ERROR] yq (v4) is required but not installed. Install yq and re-run." >&2
exit 1
fi
if [[ ! -f "$MANIFEST" ]]; then
echo "[ERROR] kube-apiserver manifest not found at $MANIFEST" >&2
exit 1
fi
backup_manifest() {
local ts
ts="$(date +%Y%m%d-%H%M%S)"
local backup="${MANIFEST}.${ts}.bak"
cp -p "$MANIFEST" "$backup"
echo "[INFO] Backup created at $backup"
}
ensure_client_ca_file() {
local ca_path="$1"
if [[ -f "$ca_path" ]]; then
echo "[INFO] Client CA file already exists at $ca_path"
return 0
fi
# Heuristic: if no dedicated client CA exists, reuse the main cluster CA if present.
# Adjust according to your security design before using in production.
local cluster_ca="/etc/kubernetes/pki/ca.crt"
if [[ -f "$cluster_ca" ]]; then
echo "[WARN] $ca_path not found; copying $cluster_ca as client CA. Review if this matches your design."
cp -p "$cluster_ca" "$ca_path"
return 0
fi
echo "[ERROR] Neither $ca_path nor $cluster_ca exist. Create an appropriate client CA certificate and place it at $ca_path, then re-run."
exit 1
}
set_client_ca_arg() {
local ca_path="$1"
# Detect if --client-ca-file already present in the manifest
if grep -q -- "--client-ca-file=" "$MANIFEST"; then
local current
current="$(grep -oE -- '--client-ca-file=[^[:space:]]+' "$MANIFEST" | head -n1 | cut -d= -f2 || true)"
if [[ "$current" == "$ca_path" ]]; then
echo "[INFO] --client-ca-file already set correctly to $ca_path in manifest"
return 0
fi
echo "[INFO] Updating existing --client-ca-file from $current to $ca_path in manifest"
backup_manifest
# Replace only the first occurrence
sed -i "0,/--client-ca-file=.*$/s//--client-ca-file=${ca_path}/" "$MANIFEST"
else
echo "[INFO] Adding --client-ca-file=${ca_path} to kube-apiserver manifest"
backup_manifest
# Use yq to append the argument to the containers[0].command list
yq -i '
.spec.containers[0].command += ["--client-ca-file='"$ca_path"'"]
' "$MANIFEST"
fi
}
verify_running_process() {
local ca_path="$1"
echo "[INFO] Waiting for kube-apiserver static pod restart (up to 120s)..."
# Wait up to 120 seconds for the process to reflect the new flag
local timeout=120
local elapsed=0
while (( elapsed < timeout )); do
if ps -ef | grep kube-apiserver | grep -v grep | grep -q -- "--client-ca-file=${ca_path}"; then
echo "[INFO] Verification succeeded: kube-apiserver running with --client-ca-file=${ca_path}"
return 0
fi
sleep 5
elapsed=$((elapsed + 5))
done
echo "[ERROR] Verification failed: kube-apiserver process does not show --client-ca-file=${ca_path} after ${timeout}s." >&2
echo "[INFO] Current kube-apiserver processes:"
ps -ef | grep kube-apiserver | grep -v grep || true
exit 1
}
main() {
local ca_path="$CLIENT_CA_DEFAULT"
echo "[INFO] Ensuring client CA file exists at $ca_path"
ensure_client_ca_file "$ca_path"
echo "[INFO] Ensuring kube-apiserver manifest has --client-ca-file=${ca_path}"
set_client_ca_arg "$ca_path"
echo "[INFO] Verifying running kube-apiserver process uses --client-ca-file=${ca_path}"
verify_running_process "$ca_path"
echo "[INFO] Remediation complete on this control plane node."
}
main "$@"