Skip to main content

Ensure Client Ca File Argument Is Set As Appropriate

More Info:

Enable Kubelet authentication using certificates.

Risk Level

Low

Address

Security

Compliance Standards

  • APRA CPS 234 (Australia)
  • BSI C5 (Germany)
  • Brazil LGPD
  • CCPA / CPRA (California)
  • CIS Critical Security Controls v8
  • CIS GKE
  • CMMC 2.0
  • CSA Cloud Controls Matrix v4
  • DPDPA
  • Digital Operational Resilience Act (EU)
  • Essential 8
  • ISO/IEC 27017
  • ISO/IEC 27018
  • ISO/IEC 27701
  • KSA PDPL
  • MAS Technology Risk Management (Singapore)
  • MITRE ATT&CK (Cloud)
  • NIS2 Directive
  • NIST SP 800-171
  • NYDFS 23 NYCRR 500
  • SWIFT Customer Security Controls Framework
  • Sarbanes-Oxley IT General Controls
  • UK NCSC Cyber Assessment Framework

Triage and Remediation

Remediation

Manual Steps
  1. On every worker node, open the kubelet config file and configure the client CA file:

    sudo vi /var/lib/kubelet/config.yaml

    Ensure the following section exists and is set to the correct CA certificate path (create the nested keys if missing):

    authentication:
    x509:
    clientCAFile: "/etc/kubernetes/pki/ca.crt"

    Replace /etc/kubernetes/pki/ca.crt with the actual path to your client CA file if different.

  2. Confirm the CA file exists and is readable by the kubelet user (usually root):

    sudo ls -l /etc/kubernetes/pki/ca.crt
    sudo file /etc/kubernetes/pki/ca.crt
  3. Reload systemd and restart the kubelet so the new configuration takes effect:

    sudo systemctl daemon-reload
    sudo systemctl restart kubelet.service
  4. Verify the kubelet process is running and pick its PID:

    /bin/ps -fC kubelet

    Confirm that the kubelet is running without crash-looping (the command should show a stable kubelet process).

  5. (Optional, if you also use command-line arguments instead of or in addition to the config file) On every worker node, edit the kubelet systemd drop-in to ensure --client-ca-file is present in the KUBELET_AUTHZ_ARGS:

    sudo vi /etc/systemd/system/kubelet.service.d/10-kubeadm.conf

    In the Environment= line that defines KUBELET_AUTHZ_ARGS, ensure it contains:

    Environment="KUBELET_AUTHZ_ARGS=--client-ca-file=/etc/kubernetes/pki/ca.crt"

    Then reload and restart again:

    sudo systemctl daemon-reload
    sudo systemctl restart kubelet.service
  6. Final verification on every worker node:

    /bin/ps -fC kubelet

    If you are using only the config file, the presence of authentication.x509.clientCAFile in /var/lib/kubelet/config.yaml together with a healthy kubelet process satisfies the control; if you are also using flags, confirm --client-ca-file=/etc/kubernetes/pki/ca.crt appears in the kubelet command line output.

Using kubectl

kubectl cannot configure the kubelet’s --client-ca-file or edit /var/lib/kubelet/config.yaml, because these are host-level settings managed on each worker node. To remediate this finding, make the changes directly on the nodes as described in the Manual Steps section.

Automation
#!/usr/bin/env bash
#
# Purpose: Ensure kubelet is configured with a client CA file for x509 auth
# Scope: Run on every worker node (as root)
#
# Behavior:
# - Ensures authentication.x509.clientCAFile is set in /var/lib/kubelet/config.yaml
# - Leaves an existing non-empty clientCAFile unchanged
# - Restarts kubelet only if a change is made
# - Verifies kubelet is running with a client CA configured

set -euo pipefail

KUBELET_CONFIG="/var/lib/kubelet/config.yaml"
# Adjust this path if your cluster uses a different CA location
DEFAULT_CLIENT_CA_FILE="/etc/kubernetes/pki/ca.crt"
BACKUP_SUFFIX=".pre_clientcafile.bak_$(date +%Y%m%d%H%M%S)"

require_root() {
if [[ "$(id -u)" -ne 0 ]]; then
echo "ERROR: This script must be run as root on each worker node." >&2
exit 1
fi
}

check_file_exists() {
local f="$1"
if [[ ! -f "$f" ]]; then
echo "ERROR: Required file not found: $f" >&2
exit 1
fi
}

ensure_yq() {
if ! command -v yq >/dev/null 2>&1; then
echo "ERROR: This script requires 'yq' (YAML processor) to modify $KUBELET_CONFIG safely." >&2
echo "Install v4+ of 'yq' (https://github.com/mikefarah/yq) and re-run." >&2
exit 1
fi
}

backup_file_if_needed() {
local f="$1"
if [[ -f "$f" ]]; then
cp -p "$f" "${f}${BACKUP_SUFFIX}"
echo "Backup created: ${f}${BACKUP_SUFFIX}"
fi
}

configure_kubelet_client_ca() {
local cfg="$1"
local ca_file="$2"
local changed=0

# If authentication.x509.clientCAFile is already set and non-empty, do nothing
local current
current="$(yq '.authentication.x509.clientCAFile // ""' "$cfg")"
if [[ -n "$current" && "$current" != "null" ]]; then
echo "Existing clientCAFile detected in $cfg: $current"
return 0
fi

echo "Setting authentication.x509.clientCAFile to $ca_file in $cfg"
backup_file_if_needed "$cfg"
yq -i ".authentication.x509.clientCAFile = \"$ca_file\"" "$cfg"
changed=1

return $changed
}

restart_kubelet_if_needed() {
local changed="$1"
if [[ "$changed" -eq 1 ]]; then
echo "Reloading systemd and restarting kubelet..."
systemctl daemon-reload
systemctl restart kubelet.service
else
echo "No kubelet config change detected; not restarting kubelet."
fi
}

verify() {
echo "Verification: checking kubelet process and effective client CA setting..."

echo "kubelet process:"
/bin/ps -fC kubelet || {
echo "ERROR: kubelet process not found after changes." >&2
exit 1
}

# Show relevant flags for manual confirmation
echo
echo "kubelet command-line (for reference):"
/bin/ps -o args= -C kubelet || true

# Show effective YAML setting
if [[ -f "$KUBELET_CONFIG" ]]; then
echo
echo "Configured authentication.x509.clientCAFile in $KUBELET_CONFIG:"
yq '.authentication.x509.clientCAFile' "$KUBELET_CONFIG"
else
echo
echo "WARNING: $KUBELET_CONFIG not found during verification."
fi
}

main() {
require_root
check_file_exists "$KUBELET_CONFIG"
check_file_exists "$DEFAULT_CLIENT_CA_FILE"
ensure_yq

local changed=0
if configure_kubelet_client_ca "$KUBELET_CONFIG" "$DEFAULT_CLIENT_CA_FILE"; then
# Return code 0 either way; detect change by comparing config before/after
# Simple heuristic: if backup exists and differs, assume change
if [[ -f "${KUBELET_CONFIG}${BACKUP_SUFFIX}" ]] && \
! diff -q "${KUBELET_CONFIG}${BACKUP_SUFFIX}" "$KUBELET_CONFIG" >/dev/null 2>&1; then
changed=1
fi
fi

restart_kubelet_if_needed "$changed"
verify
}

main "$@"

Additional Reading: