Skip to main content

Ensure Kubelet Only Makes Use Strong Cryptographic Ciphers

More Info:

Ensure that the Kubelet is configured to only use strong cryptographic ciphers.

Risk Level

Medium

Address

Security

Compliance Standards

  • CIS Kubernetes

Triage and Remediation

Remediation

Manual Steps
  1. On every worker node, back up the existing kubelet config and systemd drop-in (if present):

    sudo cp -a /var/lib/kubelet/config.yaml /var/lib/kubelet/config.yaml.bak.$(date +%F_%H%M%S) 2>/dev/null || true
    sudo cp -a /etc/systemd/system/kubelet.service.d/10-kubeadm.conf /etc/systemd/system/kubelet.service.d/10-kubeadm.conf.bak.$(date +%F_%H%M%S) 2>/dev/null || true
  2. On every worker node, configure strong ciphers in the kubelet config file /var/lib/kubelet/config.yaml (if the file exists and is used) by adding or updating the tlsCipherSuites field under the top-level config (create the list if missing):

    sudo sed -i '/^tlsCipherSuites:/d' /var/lib/kubelet/config.yaml 2>/dev/null || true
    sudo tee -a /var/lib/kubelet/config.yaml >/dev/null <<'EOF'

tlsCipherSuites:

  • TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
  • TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
  • TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
  • TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
  • TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
  • TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 EOF
Adjust placement/indentation if your file has a different structure; ensure it is valid YAML.

3. On every worker node, configure strong ciphers via kubelet arguments (if the kubelet is started with flags via systemd) by editing `/etc/systemd/system/kubelet.service.d/10-kubeadm.conf` and setting `--tls-cipher-suites` to the approved list (either add or replace an existing value). Open the file in an editor:
```bash
sudo vi /etc/systemd/system/kubelet.service.d/10-kubeadm.conf

Ensure the KUBELET_CONFIG_ARGS / KUBELET_EXTRA_ARGS / ExecStart= line contains:

--tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384

Save and exit. If both the config file and flags specify ciphers, ensure they are consistent; prefer the config file as the single source where possible.

  1. On every worker node, reload systemd and restart kubelet (note: restarting kubelet temporarily disrupts node-level operations and may evict or reschedule pods depending on your cluster configuration):

    sudo systemctl daemon-reload
    sudo systemctl restart kubelet.service
  2. On every worker node, verify that the kubelet process is running and (if started via flags) that the --tls-cipher-suites argument reflects only the strong cipher list:

    /bin/ps -fC kubelet

    Confirm the output shows kubelet running and, where applicable, includes:
    --tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384.

Using kubectl

kubectl cannot configure kubelet’s TLS cipher suites because this setting lives in host-level files and flags on each worker node (for example /var/lib/kubelet/config.yaml or the kubelet systemd unit). To remediate this finding, follow the guidance in the Manual Steps section directly on every worker node.

Automation
#!/usr/bin/env bash
#
# Harden kubelet TLS cipher suites on every worker node.
# Usage: run on each worker node as root (e.g. via SSH or Ansible shell).
# Safe to re-run; it will update config only when needed.

set -euo pipefail

CIPHERS="TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"

KUBELET_CONFIG="/var/lib/kubelet/config.yaml"
KUBELET_SYSTEMD_DROPIN="/etc/systemd/system/kubelet.service.d/10-kubeadm.conf"

changed_config=0
changed_systemd=0

echo "==> Hardening kubelet TLS cipher suites on host: $(hostname)"

#------------------------------
# 1) Ensure tlsCipherSuites in kubelet config file (if present)
#------------------------------
if [ -f "$KUBELET_CONFIG" ]; then
echo "-> Detected kubelet config file: $KUBELET_CONFIG"

# Backup once per day (simple rotation)
ts="$(date +%Y%m%d-%H%M%S)"
backup="$KUBELET_CONFIG.bak-$ts"
cp "$KUBELET_CONFIG" "$backup"
echo " Backup created: $backup"

# If tlsCipherSuites is already correct, do nothing
if grep -qE '^[[:space:]]*tlsCipherSuites:' "$KUBELET_CONFIG"; then
if grep -qE "^[[:space:]]*tlsCipherSuites:[[:space:]]*\[$CIPHERS\][[:space:]]*$" "$KUBELET_CONFIG"; then
echo " tlsCipherSuites already set correctly in $KUBELET_CONFIG"
else
echo " Updating existing tlsCipherSuites in $KUBELET_CONFIG"
# Normalize to a single-line array
# This is a simple matcher that replaces any existing tlsCipherSuites line.
# If your file uses multi-line YAML arrays, you may need to adjust manually.
sed -i -E "s|^[[:space:]]*tlsCipherSuites:.*|tlsCipherSuites: [$CIPHERS]|" "$KUBELET_CONFIG"
changed_config=1
fi
else
echo " Adding tlsCipherSuites to $KUBELET_CONFIG"
{
echo ""
echo "tlsCipherSuites: [$CIPHERS]"
} >> "$KUBELET_CONFIG"
changed_config=1
fi
else
echo "-> No kubelet config file found at $KUBELET_CONFIG, skipping file-based config."
fi

#------------------------------
# 2) Ensure --tls-cipher-suites in systemd kubelet drop-in (if present)
#------------------------------
if [ -f "$KUBELET_SYSTEMD_DROPIN" ]; then
echo "-> Detected kubelet systemd drop-in: $KUBELET_SYSTEMD_DROPIN"

ts="$(date +%Y%m%d-%H%M%S)"
backup="$KUBELET_SYSTEMD_DROPIN.bak-$ts"
cp "$KUBELET_SYSTEMD_DROPIN" "$backup"
echo " Backup created: $backup"

if grep -q -- "--tls-cipher-suites=" "$KUBELET_SYSTEMD_DROPIN"; then
if grep -q -- "--tls-cipher-suites=$CIPHERS" "$KUBELET_SYSTEMD_DROPIN"; then
echo " --tls-cipher-suites already set correctly in $KUBELET_SYSTEMD_DROPIN"
else
echo " Updating existing --tls-cipher-suites in $KUBELET_SYSTEMD_DROPIN"
sed -i -E "s|--tls-cipher-suites=[^[:space:]]*|--tls-cipher-suites=$CIPHERS|g" "$KUBELET_SYSTEMD_DROPIN"
changed_systemd=1
fi
else
echo " Adding --tls-cipher-suites to kubelet ExecStart in $KUBELET_SYSTEMD_DROPIN"
# Append parameter inside ExecStart line
sed -i -E "s|^(ExecStart=.*kubelet)(.*)$|\1 --tls-cipher-suites=$CIPHERS\2|" "$KUBELET_SYSTEMD_DROPIN"
changed_systemd=1
fi
else
echo "-> No kubelet systemd drop-in at $KUBELET_SYSTEMD_DROPIN, skipping flag-based config."
fi

#------------------------------
# 3) Restart kubelet if anything changed
#------------------------------
if [ "$changed_config" -eq 1 ] || [ "$changed_systemd" -eq 1 ]; then
echo "-> Changes detected; reloading systemd and restarting kubelet"
systemctl daemon-reload
systemctl restart kubelet.service
echo " kubelet restarted (this may temporarily disrupt workloads on this node)"
else
echo "-> No changes made; kubelet restart not required."
fi

#------------------------------
# 4) Verification (adapted from audit)
#------------------------------
echo "==> Verification: kubelet process and effective TLS cipher suites"

echo "-- kubelet process:"
/bin/ps -fC kubelet || echo "kubelet process not found"

echo "-- Checking for tlsCipherSuites in $KUBELET_CONFIG (if file exists):"
if [ -f "$KUBELET_CONFIG" ]; then
grep -E '^[[:space:]]*tlsCipherSuites:' "$KUBELET_CONFIG" || echo "tlsCipherSuites not set in $KUBELET_CONFIG"
else
echo "$KUBELET_CONFIG not present"
fi

echo "-- Checking for --tls-cipher-suites flag in kubelet process:"
/bin/ps -C kubelet -o args= | grep -- "--tls-cipher-suites=" || echo "--tls-cipher-suites flag not present on kubelet process"

echo "==> Completed on host: $(hostname)"