Skip to main content

Kubelet Client CA File Argument Set As Appropriate

More Info:

The kubelet --client-ca-file argument should be set to enable client certificate authentication. Without a client CA, the kubelet cannot verify the identity of API clients.

Risk Level

High

Address

Security

Compliance Standards

  • CIS OKE

Triage and Remediation

Remediation

Manual Steps
  1. On every worker node, confirm the current kubelet process arguments:

    /bin/ps -fC kubelet

    Check whether a --client-ca-file argument is present and whether it points to the intended CA (for example /etc/kubernetes/ca.crt).

  2. On every worker node, ensure the client CA file exists and is readable by kubelet (adjust the source path if your CA is elsewhere):

    ls -l /etc/kubernetes/ca.crt || sudo cp /etc/kubernetes/pki/ca.crt /etc/kubernetes/ca.crt
    sudo chown root:root /etc/kubernetes/ca.crt
    sudo chmod 644 /etc/kubernetes/ca.crt
  3. On every worker node, edit the kubelet systemd drop-in to add the --client-ca-file argument:

    sudo sed -i '/KUBELET_KUBEADM_ARGS=/d' /etc/systemd/system/kubelet.service.d/00-default.conf

    Then open the file and ensure the ExecStart or environment line includes the flag, for example:

    sudo vi /etc/systemd/system/kubelet.service.d/00-default.conf

    Add or adjust so it contains:

    [Service]
    Environment="KUBELET_KUBEADM_ARGS=--client-ca-file=/etc/kubernetes/ca.crt"

    or, if ExecStart uses inline flags, append:

    ExecStart=... --client-ca-file=/etc/kubernetes/ca.crt
  4. On every worker node, reload systemd and restart kubelet (this will briefly disrupt workloads on that node):

    sudo systemctl daemon-reload
    sudo systemctl restart kubelet.service
  5. On every worker node, confirm kubelet is healthy:

    sudo systemctl status kubelet -l
  6. On every worker node, verify that the --client-ca-file argument is now set correctly:

    /bin/ps -fC kubelet

    Confirm the output shows --client-ca-file=/etc/kubernetes/ca.crt (or your chosen CA path) in the kubelet command line.

Using kubectl

kubectl cannot configure the kubelet’s --client-ca-file flag or edit /etc/kubernetes/kubelet-config.json, because these are host-level settings managed on each worker node (systemd units and config files). To remediate this finding, make the changes directly on every worker node as described in the Manual Steps section.

Automation
#!/usr/bin/env bash
#
# Remediates CIS OKE 3.2.3:
# Ensure kubelet is started with --client-ca-file=/etc/kubernetes/ca.crt
#
# Run on: every worker node (as root)
# Safe to re-run (idempotent).

set -euo pipefail

KUBELET_DROPIN_DIR="/etc/systemd/system/kubelet.service.d"
KUBELET_DROPIN_FILE="${KUBELET_DROPIN_DIR}/00-default.conf"
CLIENT_CA_ARG="--client-ca-file=/etc/kubernetes/ca.crt"
CA_FILE="/etc/kubernetes/ca.crt"

echo "[INFO] Starting kubelet --client-ca-file remediation"

if [[ "$(id -u)" -ne 0 ]]; then
echo "[ERROR] This script must be run as root."
exit 1
fi

if [[ ! -f "${KUBELET_DROPIN_FILE}" ]]; then
echo "[ERROR] ${KUBELET_DROPIN_FILE} not found. Adjust path or create drop-in as per your distro."
exit 1
fi

if [[ ! -f "${CA_FILE}" ]]; then
echo "[ERROR] ${CA_FILE} not found. Create or place the correct client CA certificate before rerunning."
exit 1
fi

echo "[INFO] Ensuring kubelet drop-in directory exists: ${KUBELET_DROPIN_DIR}"
mkdir -p "${KUBELET_DROPIN_DIR}"

echo "[INFO] Ensuring ${KUBELET_DROPIN_FILE} contains ${CLIENT_CA_ARG}"

# Backup once
if [[ ! -f "${KUBELET_DROPIN_FILE}.cis-3.2.3.bak" ]]; then
cp "${KUBELET_DROPIN_FILE}" "${KUBELET_DROPIN_FILE}.cis-3.2.3.bak"
fi

# Normalize file and ensure Environment line with KUBELET_EXTRA_ARGS includes the arg
tmpfile="$(mktemp)"
trap 'rm -f "${tmpfile}"' EXIT

# Read current content
cat "${KUBELET_DROPIN_FILE}" > "${tmpfile}"

# Remove any duplicate --client-ca-file arguments
sed -i 's/--client-ca-file=[^ ]*//g' "${tmpfile}"

# Ensure there is an Environment line for KUBELET_EXTRA_ARGS
if ! grep -q 'Environment=.*KUBELET_EXTRA_ARGS' "${tmpfile}"; then
# Add a basic Environment line; adapt if your distro uses a different pattern
echo 'Environment="KUBELET_EXTRA_ARGS="' >> "${tmpfile}"
fi

# Append the CLIENT_CA_ARG to KUBELET_EXTRA_ARGS, preserving existing content
# Works whether Environment= or EnvironmentContains double quotes
perl -pi -e '
if (/^Environment=.*KUBELET_EXTRA_ARGS/) {
s/"$/ '"${CLIENT_CA_ARG}"'"/ if ! /'"${CLIENT_CA_ARG//\//\\/}"'/;
}
' "${tmpfile}"

# Install updated file if changed
if ! cmp -s "${tmpfile}" "${KUBELET_DROPIN_FILE}"; then
echo "[INFO] Updating ${KUBELET_DROPIN_FILE}"
cp "${tmpfile}" "${KUBELET_DROPIN_FILE}"
else
echo "[INFO] ${KUBELET_DROPIN_FILE} already contains ${CLIENT_CA_ARG}"
fi

echo "[INFO] Reloading systemd and restarting kubelet (this will restart the kubelet on this node)"
systemctl daemon-reload
systemctl restart kubelet.service

echo "[INFO] Checking kubelet status"
systemctl status kubelet -l --no-pager || true

echo "[INFO] Verifying kubelet is running with ${CLIENT_CA_ARG}"
if /bin/ps -fC kubelet | grep -q -- "${CLIENT_CA_ARG}"; then
echo "[SUCCESS] kubelet is running with ${CLIENT_CA_ARG}"
else
echo "[FAIL] kubelet is NOT running with ${CLIENT_CA_ARG}"
echo "[INFO] Full kubelet command line:"
/bin/ps -fC kubelet || true
exit 2
fi