Skip to main content

Kubelet RotateKubeletServerCertificate Set To True

More Info:

The RotateKubeletServerCertificate feature gate should be true so the kubelet automatically rotates its serving certificates, preventing expiry-related failures.

Risk Level

High

Address

Security

Compliance Standards

  • CIS AKS

Triage and Remediation

Remediation

Manual Steps
  1. On every worker node, open the kubelet systemd drop-in file for editing (create it if it does not exist yet):
sudo mkdir -p /etc/systemd/system/kubelet.service.d
sudo vi /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
  1. In that file, ensure there is an Environment line that includes the RotateKubeletServerCertificate feature gate. For example, add or update:
[Service]
Environment="KUBELET_CERTIFICATE_ARGS=--feature-gates=RotateKubeletServerCertificate=true"

If other Environment="KUBELET_... lines already exist, keep them and only add or adjust the KUBELET_CERTIFICATE_ARGS line.

  1. If the kubelet is also configured via /etc/default/kubelet or /var/lib/kubelet/kubeadm-flags.env, check those files to ensure they do not override the feature gate. On every worker node:
sudo grep -n "feature-gates" /etc/default/kubelet /var/lib/kubelet/kubeadm-flags.env 2>/dev/null || true

If you see RotateKubeletServerCertificate=false anywhere, edit the file and remove that part or change it to true.

  1. Reload systemd configuration and restart kubelet on every worker node:
sudo systemctl daemon-reload
sudo systemctl restart kubelet.service
  1. Confirm kubelet is healthy on every worker node:
sudo systemctl status kubelet.service --no-pager
  1. Verify the kubelet process is running with RotateKubeletServerCertificate=true on every worker node:
/bin/ps -fC kubelet | grep -o 'RotateKubeletServerCertificate=[^,"]*' || echo "feature gate not found in args"
Using kubectl

kubectl cannot modify kubelet process flags or host-level configuration files, so this finding cannot be fixed via Kubernetes API changes. Configure RotateKubeletServerCertificate in /etc/systemd/system/kubelet.service.d/10-kubeadm.conf on every worker node as described, and follow the steps in the Manual Steps section.

Automation
#!/usr/bin/env bash
# Automation: enable RotateKubeletServerCertificate feature gate for kubelet
# Run on: every worker node (as root)
set -euo pipefail

KUBELET_DROPIN="/etc/systemd/system/kubelet.service.d/10-kubeadm.conf"
BACKUP_SUFFIX="$(date +%Y%m%d%H%M%S)"

if [[ ! -f "$KUBELET_DROPIN" ]]; then
echo "ERROR: $KUBELET_DROPIN not found on this node. Aborting."
exit 1
fi

echo "Backing up $KUBELET_DROPIN to ${KUBELET_DROPIN}.${BACKUP_SUFFIX}.bak"
cp -p "$KUBELET_DROPIN" "${KUBELET_DROPIN}.${BACKUP_SUFFIX}.bak"

# Ensure KUBELET_CERTIFICATE_ARGS line exists
if ! grep -qE '^\s*Environment=.*KUBELET_CERTIFICATE_ARGS=' "$KUBELET_DROPIN"; then
echo "Adding KUBELET_CERTIFICATE_ARGS environment line to $KUBELET_DROPIN"
cat <<'EOF' >>"$KUBELET_DROPIN"
Environment="KUBELET_CERTIFICATE_ARGS="
EOF
fi

# Idempotently ensure RotateKubeletServerCertificate=true is in feature-gates
tmpfile="$(mktemp)"
trap 'rm -f "$tmpfile"' EXIT

awk '
BEGIN {
target="RotateKubeletServerCertificate=true"
}
# Process lines containing KUBELET_CERTIFICATE_ARGS
/KUBELET_CERTIFICATE_ARGS=/ {
# Remove any existing RotateKubeletServerCertificate entry
gsub(/RotateKubeletServerCertificate=[^,"]*/, "", $0)
# Clean up any duplicate commas in feature-gates list
gsub(/,,+/, ",", $0)
gsub(/feature-gates=,/, "feature-gates=", $0)
gsub(/, *"/, "\"", $0)

if ($0 ~ /--feature-gates=/) {
# Append our gate to existing feature-gates
sub(/--feature-gates=([^" ]*)/, "&," target, $0)
# Fix potential leading/trailing commas
gsub(/--feature-gates=,/, "--feature-gates=", $0)
gsub(/,--feature-gates=/, "--feature-gates=", $0)
gsub(/,+"/, "\"", $0)
} else {
# No feature-gates yet; add one
# Insert before closing quote if present
if ($0 ~ /"$/) {
sub(/"$/, " --feature-gates=" target "\"", $0)
} else {
$0 = $0 " --feature-gates=" target
}
}
}
{ print }
' "$KUBELET_DROPIN" >"$tmpfile"

mv "$tmpfile" "$KUBELET_DROPIN"

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

echo "Verifying kubelet process has RotateKubeletServerCertificate=true enabled..."
/bin/ps -fC kubelet || {
echo "ERROR: kubelet process not found after restart."
exit 1
}

if /bin/ps -fC kubelet | grep -q -- '--feature-gates=.*RotateKubeletServerCertificate=true'; then
echo "SUCCESS: kubelet is running with RotateKubeletServerCertificate=true on this node."
exit 0
else
echo "ERROR: kubelet is not running with RotateKubeletServerCertificate=true."
echo "Current kubelet command line:"
/bin/ps -fC kubelet
exit 1
fi