Ensure Client Ca File Argument Is Appropriate
More Info:
Enable Kubelet authentication using certificates.
Risk Level
Low
Address
Security
Compliance Standards
- CIS Kubernetes
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
On every control plane node, identify the API server static pod manifest and current flags:
sudo ls -l /etc/kubernetes/manifests/kube-apiserver.yamlsudo grep -n 'client-ca-file' /etc/kubernetes/manifests/kube-apiserver.yaml || echo "no client-ca-file set"Also confirm you have (or create) a suitable client CA file (typically the cluster CA):
sudo ls -l /etc/kubernetes/pki/ca.crt -
On every control plane node, back up the API server manifest before editing:
sudo cp /etc/kubernetes/manifests/kube-apiserver.yaml /etc/kubernetes/manifests/kube-apiserver.yaml.bak.$(date +%F-%H%M%S) -
On every control plane node, edit
/etc/kubernetes/manifests/kube-apiserver.yamland add or adjust the--client-ca-fileargument under the containercommandlist to point to your CA file (example uses/etc/kubernetes/pki/ca.crt):sudo sed -i '/kube-apiserver/,$ s#\(\s*-\s*--client-ca-file=\).*#\1/etc/kubernetes/pki/ca.crt#' /etc/kubernetes/manifests/kube-apiserver.yamlIf the flag does not exist yet, append a new line under the other
--flags (edit with an editor such asvi):sudo vi /etc/kubernetes/manifests/kube-apiserver.yamlAdd, aligned with the other args:
- --client-ca-file=/etc/kubernetes/pki/ca.crtSaving this file will cause the kube-apiserver static pod to restart automatically.
-
On every control plane node, ensure the CA file is readable by the kube-apiserver process (usually runs as root, so default permissions are fine). For standard kubeadm layouts:
sudo chmod 600 /etc/kubernetes/pki/ca.crtsudo chown root:root /etc/kubernetes/pki/ca.crt -
On every control plane node, wait for the kube-apiserver pod to restart and become Ready:
sudo crictl ps | grep kube-apiserver || sudo docker ps | grep kube-apiserver -
Verification on every control plane node: confirm the running kube-apiserver process now has the expected
--client-ca-fileargument set:/bin/ps -ef | grep kube-apiserver | grep -v grep | grep -- '--client-ca-file='You should see an argument like:
--client-ca-file=/etc/kubernetes/pki/ca.crt.
Using kubectl
kubectl cannot change the kube-apiserver’s --client-ca-file setting or any other host-level flags; this must be fixed by editing /etc/kubernetes/manifests/kube-apiserver.yaml directly on every control plane node. Refer to the Manual Steps section for the exact on-node configuration changes and verification commands.
Automation
#!/usr/bin/env bash
#
# Automation: Ensure kube-apiserver is started with --client-ca-file on every control plane node.
#
# Usage:
# 1) Copy this script to each CONTROL PLANE node.
# 2) Run as root: bash ./fix-kube-apiserver-client-ca.sh
#
# Idempotent: safe to re-run. It will:
# - Ensure the chosen client CA file exists.
# - Ensure --client-ca-file=<path> is present (and unique) in /etc/kubernetes/manifests/kube-apiserver.yaml
# - Trigger kube-apiserver static pod restart via manifest edit.
# - Verify via process inspection.
set -euo pipefail
# ---------------- CONFIGURATION (EDIT AS NEEDED) ----------------
# Path to the client CA file that the API server should trust for client cert auth.
# This must be a valid CA bundle that signs Kubelet client certificates.
CLIENT_CA_FILE="/etc/kubernetes/pki/apiserver-client-ca.crt"
# Path to the kube-apiserver static pod manifest.
APISERVER_MANIFEST="/etc/kubernetes/manifests/kube-apiserver.yaml"
# ---------------- HELPER FUNCTIONS ----------------
log() {
printf '[%s] %s\n' "$(date -u +'%Y-%m-%dT%H:%M:%SZ')" "$*" >&2
}
fail() {
log "ERROR: $*"
exit 1
}
require_root() {
if [[ "$(id -u)" -ne 0 ]]; then
fail "This script must be run as root."
fi
}
backup_file() {
local file="$1"
if [[ -f "$file" ]]; then
local ts
ts="$(date -u +'%Y%m%dT%H%M%SZ')"
local backup="${file}.bak.${ts}"
cp -p "$file" "$backup"
log "Backup created: $backup"
fi
}
ensure_client_ca_file_exists() {
if [[ -f "$CLIENT_CA_FILE" ]]; then
log "Client CA file already exists at: $CLIENT_CA_FILE"
return 0
fi
log "Client CA file not found at: $CLIENT_CA_FILE"
log "You must provision a proper client CA bundle that signs kubelet client certificates."
log "For now, creating a placeholder that will NOT enable real authentication."
mkdir -p "$(dirname "$CLIENT_CA_FILE")"
# Placeholder self-signed root CA (dummy). Replace with your real CA.
cat >"$CLIENT_CA_FILE" <<'EOF'
-----BEGIN CERTIFICATE-----
MIIBszCCAVmgAwIBAgIUYJ5vjHZyN+dummy-placeholder-CA-cert-ONLYwCgYIKoZIzj0EAwIw
EjEQMA4GA1UEAwwHRE9OT1RVUzAeFw0yMDAxMDEwMDAwMDBaFw00OTEyMzEyMzU5NTlaMBIxEDAO
BgNVBAMMB0RPTk9UVVMwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
o1MwUTAdBgNVHQ4EFgQUdummy-placeholder-CA-key-ONLYhEoU06YfBgNVHSMEEDAOmAwh
dummy-placeholder-CA-subject-ONLYMA8GA1UdEwEB/wQFMAMBAf8wCgYIKoZIzj0EAwIDSAAw
RQIhAJy4dummyplaceholderSigONLY1zq2dGJSou1qg7Z+R7B9xEQAiAF+d
-----END CERTIFICATE-----
EOF
chmod 0644 "$CLIENT_CA_FILE"
log "Placeholder client CA file created at $CLIENT_CA_FILE"
log "IMPORTANT: Replace this placeholder with your real client CA as per your PKI design."
}
update_apiserver_manifest() {
if [[ ! -f "$APISERVER_MANIFEST" ]]; then
fail "API server manifest not found at $APISERVER_MANIFEST. This node may not be a static-pod control plane."
fi
# Normalize to absolute path
local ca_path="$CLIENT_CA_FILE"
log "Ensuring --client-ca-file is correctly configured in $APISERVER_MANIFEST"
# Backup before modifying
backup_file "$APISERVER_MANIFEST"
# Remove any existing --client-ca-file= arguments to avoid duplicates
sed -i 's/ *--client-ca-file=[^" ]*//g' "$APISERVER_MANIFEST"
# Ensure the manifest has a kube-apiserver command line with args.
# Append the flag to the command section or args list.
if grep -q -- '--client-ca-file=' "$APISERVER_MANIFEST"; then
log "--client-ca-file already present after cleanup; nothing to add."
else
# Try to append to an existing line with kube-apiserver command flags.
if grep -q 'kube-apiserver' "$APISERVER_MANIFEST"; then
# Add the flag to the first line containing 'kube-apiserver' that looks like a command line.
# This covers the common manifest style: - kube-apiserver ...flags...
awk -v flag=" --client-ca-file=${ca_path}" '
/kube-apiserver/ && /--advertise-address|--secure-port|--etcd-servers/ && !done {
sub(/kube-apiserver/, "kube-apiserver" flag, $0)
done=1
}
{ print }
' "$APISERVER_MANIFEST" >"${APISERVER_MANIFEST}.tmp" && mv "${APISERVER_MANIFEST}.tmp" "$APISERVER_MANIFEST"
log "Injected --client-ca-file into kube-apiserver command line."
else
fail "Could not find kube-apiserver command in $APISERVER_MANIFEST to inject --client-ca-file. Manual edit required."
fi
fi
}
verify_apiserver_flag() {
log "Waiting up to 120s for kube-apiserver static pod to restart and pick up changes..."
local end=$((SECONDS + 120))
local found=0
while (( SECONDS < end )); do
if /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -q -- "--client-ca-file=${CLIENT_CA_FILE}"; then
found=1
break
fi
sleep 5
done
if (( found == 1 )); then
log "VERIFICATION SUCCESS: kube-apiserver is running with --client-ca-file=${CLIENT_CA_FILE}"
/bin/ps -ef | grep kube-apiserver | grep -v grep
else
log "VERIFICATION FAILED: kube-apiserver process not showing --client-ca-file=${CLIENT_CA_FILE}"
log "Current kube-apiserver processes:"
/bin/ps -ef | grep kube-apiserver | grep -v grep || true
fail "Please check kubelet logs and /etc/kubernetes/manifests/kube-apiserver.yaml for issues."
fi
}
main() {
require_root
log "Starting remediation for CIS Kubernetes 4.2.3 on this control plane node."
ensure_client_ca_file_exists
update_apiserver_manifest
verify_apiserver_flag
log "Remediation for this node completed."
}
main "$@"