Skip to main content

Kubelet Rotate Certificates Argument Not Set To False

More Info:

The kubelet --rotate-certificates argument should not be set to false so the kubelet automatically rotates its client certificates. Disabling rotation increases the risk of using expired or compromised credentials.

Risk Level

High

Address

Security

Compliance Standards

  • CIS OKE

Triage and Remediation

Remediation

Manual Steps
  1. On every worker node, open the kubelet systemd drop-in config for editing:

    sudo vi /etc/systemd/system/kubelet.service.d/00-default.conf
  2. In that file, locate the ExecStart= line. If it contains --rotate-certificates=false, remove =false so it reads --rotate-certificates (or, if the flag is missing entirely, add it), for example:

    ExecStart=/usr/bin/kubelet \
    --rotate-certificates \
    ...
  3. If your kubelet instead reads its options from /etc/kubernetes/kubelet-config.json, open that file and ensure the feature is not disabled there (do not set it to false):

    sudo vi /etc/kubernetes/kubelet-config.json

    Confirm there is no line like:

    "rotateCertificates": false

    If present, either remove that line or change it to:

    "rotateCertificates": true
  4. Reload systemd and restart the kubelet so the new flag takes effect (this will restart the kubelet on this worker node):

    sudo systemctl daemon-reload
    sudo systemctl restart kubelet.service
  5. Confirm the kubelet is healthy on this worker node:

    sudo systemctl status kubelet -l
  6. Verify on this worker node that the kubelet process is no longer running with --rotate-certificates=false and that --rotate-certificates is present:

    /bin/ps -fC kubelet

    Inspect the command line in the output and ensure --rotate-certificates=false does not appear and --rotate-certificates (without =false) is included.

Using kubectl

kubectl cannot modify kubelet process arguments or the host-level config file /etc/kubernetes/kubelet-config.json; this setting must be changed directly on every worker node in the systemd drop-in file /etc/systemd/system/kubelet.service.d/00-default.conf. Refer to the Manual Steps section for the exact on-node edits and restart commands needed to enable certificate rotation and then re-run /bin/ps -fC kubelet for verification.

Automation
#!/usr/bin/env bash
#
# Purpose: Ensure kubelet is configured with --rotate-certificates (not set to false)
# Scope: Run on every worker node (as root)
# Safe: Idempotent; can be re-run
#

set -euo pipefail

SYSTEMD_DROPIN_DIR="/etc/systemd/system/kubelet.service.d"
SYSTEMD_DROPIN_FILE="${SYSTEMD_DROPIN_DIR}/00-default.conf"

echo "[INFO] Ensuring kubelet --rotate-certificates is configured on this node"

if [[ ! -f "${SYSTEMD_DROPIN_FILE}" ]]; then
echo "[ERROR] Systemd drop-in not found: ${SYSTEMD_DROPIN_FILE}"
echo " This script expects kubelet to be managed by systemd with that drop-in."
echo " Adjust manually according to your environment."
exit 1
fi

# Ensure drop-in directory exists (usually already does)
mkdir -p "${SYSTEMD_DROPIN_DIR}"

# Backup the existing file once
if [[ ! -f "${SYSTEMD_DROPIN_FILE}.bak" ]]; then
cp "${SYSTEMD_DROPIN_FILE}" "${SYSTEMD_DROPIN_FILE}.bak"
echo "[INFO] Backup created at ${SYSTEMD_DROPIN_FILE}.bak"
fi

# Read current content
current_content="$(cat "${SYSTEMD_DROPIN_FILE}")"

# Remove any explicit --rotate-certificates=false occurrences
modified_content="$(printf '%s\n' "${current_content}" \
| sed -E 's/(^ExecStart=.*)--rotate-certificates=false[[:space:]]*/\1/g')"

# Ensure we have a --rotate-certificates flag somewhere in ExecStart
if echo "${modified_content}" | grep -qE '^ExecStart=.*--rotate-certificates(=|[[:space:]]|$)'; then
echo "[INFO] --rotate-certificates flag already present in ExecStart."
else
echo "[INFO] Adding --rotate-certificates to kubelet ExecStart."
modified_content="$(printf '%s\n' "${modified_content}" \
| sed -E 's|^(ExecStart=.*kubelet)|\1 --rotate-certificates|')"
fi

# Only write if changed
if ! diff -q <(printf '%s\n' "${current_content}") <(printf '%s\n' "${modified_content}") >/dev/null 2>&1; then
printf '%s\n' "${modified_content}" > "${SYSTEMD_DROPIN_FILE}"
echo "[INFO] Updated ${SYSTEMD_DROPIN_FILE}"
else
echo "[INFO] No changes needed in ${SYSTEMD_DROPIN_FILE}"
fi

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

echo "[INFO] Verifying kubelet is running with certificate rotation enabled..."
systemctl status kubelet -l --no-pager || {
echo "[ERROR] kubelet service is not healthy after restart."
exit 1
}

echo "[INFO] Current kubelet process flags:"
/bin/ps -fC kubelet || {
echo "[ERROR] kubelet process not found."
exit 1
}

if /bin/ps -fC kubelet | grep -q -- '--rotate-certificates=false'; then
echo "[ERROR] kubelet still has --rotate-certificates=false in its arguments."
exit 1
fi

if /bin/ps -fC kubelet | grep -q -- '--rotate-certificates'; then
echo "[INFO] kubelet is running with --rotate-certificates and not set to false."
echo "[INFO] Remediation successful on this node."
exit 0
else
echo "[WARN] kubelet process does not show --rotate-certificates flag explicitly."
echo " Review ${SYSTEMD_DROPIN_FILE} and kubelet configuration manually."
exit 1
fi