Skip to main content

Kubelet RotateKubeletServerCertificate Argument Set To True

More Info:​

The RotateKubeletServerCertificate feature gate enables automatic rotation of the kubelet serving certificate. Enabling it ensures the kubelets server certificate is renewed before it expires.

Risk Level​

High

Address​

Security

Compliance Standards​

  • CIS Kubernetes

Triage and Remediation​

Remediation​

Manual Steps
  1. On every control plane node, back up the current kube-controller-manager manifest:

    sudo cp -a /etc/kubernetes/manifests/kube-controller-manager.yaml /etc/kubernetes/manifests/kube-controller-manager.yaml.backup
  2. Edit the kube-controller-manager static pod manifest to configure the feature gate:

    sudo sed -i '/- kube-controller-manager/a\ - --feature-gates=RotateKubeletServerCertificate=true' /etc/kubernetes/manifests/kube-controller-manager.yaml

    If a --feature-gates= argument already exists, edit that line instead (with a text editor such as sudo vi /etc/kubernetes/manifests/kube-controller-manager.yaml) to ensure it includes RotateKubeletServerCertificate=true in the comma-separated list.

  3. Wait for the kube-controller-manager pod to be recreated (editing any file under /etc/kubernetes/manifests causes an automatic restart via the kubelet). You can watch for the new pod on any machine with kubectl access:

    kubectl -n kube-system get pods -l component=kube-controller-manager -w
  4. Verify on each control plane node that the kube-controller-manager process now has the correct feature gate set:

    /bin/ps -ef | grep kube-controller-manager | grep -v grep

    Confirm the output includes --feature-gates=RotateKubeletServerCertificate=true (or a --feature-gates= value that contains RotateKubeletServerCertificate=true).

Using kubectl

kubectl cannot be used to enable RotateKubeletServerCertificate because this setting is controlled via the kube-controller-manager static pod manifest on each control plane node. To remediate, edit /etc/kubernetes/manifests/kube-controller-manager.yaml on every control plane node as described in the Manual Steps section.

Automation
#!/usr/bin/env bash
#
# Enable RotateKubeletServerCertificate via kube-controller-manager feature-gate
# Scope: run on every control plane node (as root)
# Safe to re-run (idempotent). Requires: bash, sed, grep, systemctl (for static pod restart behavior note only).
#

set -euo pipefail

MANIFEST="/etc/kubernetes/manifests/kube-controller-manager.yaml"

echo "[INFO] Ensuring RotateKubeletServerCertificate=true on feature-gates in ${MANIFEST}"

if [ ! -f "${MANIFEST}" ]; then
echo "[ERROR] Controller manager manifest not found at ${MANIFEST}. Are you on a control plane node?"
exit 1
fi

# Backup once
if [ ! -f "${MANIFEST}.pre-rotatekubeletservercertificate.bak" ]; then
cp "${MANIFEST}" "${MANIFEST}.pre-rotatekubeletservercertificate.bak"
echo "[INFO] Backup created: ${MANIFEST}.pre-rotatekubeletservercertificate.bak"
fi

# Normalize file to avoid sed issues with CRLF
dos2unix "${MANIFEST}" >/dev/null 2>&1 || true

# Function to check if RotateKubeletServerCertificate=true is already present on a given line
has_rotate_gate() {
# $1 = line
grep -q -- "--feature-gates=" <<<"$1" && \
grep -q "RotateKubeletServerCertificate=true" <<<"$1"
}

# Detect if any --feature-gates arg exists
if grep -q -- "--feature-gates=" "${MANIFEST}"; then
echo "[INFO] Existing --feature-gates flag found; ensuring RotateKubeletServerCertificate=true is set"

# Update any existing --feature-gates container args that contain RotateKubeletServerCertificate but not =true
# and add RotateKubeletServerCertificate=true where missing.
tmpfile="$(mktemp)"
awk '
/--feature-gates=/ {
line=$0
# if RotateKubeletServerCertificate is already =true, leave unmodified
if (line ~ /RotateKubeletServerCertificate=true/) {
print line
} else if (line ~ /RotateKubeletServerCertificate=/) {
# Normalize any existing RotateKubeletServerCertificate entry to true
gsub(/RotateKubeletServerCertificate=[^,"]*/, "RotateKubeletServerCertificate=true", line)
print line
} else {
# Append RotateKubeletServerCertificate=true to the feature-gates list
# Handle common forms: --feature-gates=A=B,C=D or with surrounding quotes
if (line ~ /--feature-gates=["'\''"][^"'\''"]*["'\''"]/ ) {
gsub(/(--feature-gates=["'\''"])([^"'\''"]*)(["'\''"])/, "\\1\\2,RotateKubeletServerCertificate=true\\3", line)
} else if (line ~ /--feature-gates=[^ ,]+/) {
gsub(/--feature-gates=([^ ,]+)/, "--feature-gates=\\1,RotateKubeletServerCertificate=true", line)
} else {
# Fallback: just append to the argument
gsub(/--feature-gates=/, "--feature-gates=RotateKubeletServerCertificate=true,", line)
}
print line
}
next
}
{ print }
' "${MANIFEST}" > "${tmpfile}"

mv "${tmpfile}" "${MANIFEST}"
else
echo "[INFO] No --feature-gates flag found; adding one with RotateKubeletServerCertificate=true"

# Add a new --feature-gates arg under the kube-controller-manager container args
# This handles common kubeadm-style static pod manifests.
tmpfile="$(mktemp)"
awk '
/name: kube-controller-manager/ { in_kcm=1 }
in_kcm && /args:/ && !seen_args {
seen_args=1
print
print " - --feature-gates=RotateKubeletServerCertificate=true"
next
}
{ print }
' "${MANIFEST}" > "${tmpfile}"

# If we failed to inject (no changes), fall back to appending to any args: block under containers:
if ! grep -q "RotateKubeletServerCertificate=true" "${tmpfile}"; then
awk '
/containers:/ { in_containers=1 }
in_containers && /args:/ && !seen_args {
seen_args=1
print
print " - --feature-gates=RotateKubeletServerCertificate=true"
next
}
{ print }
' "${MANIFEST}" > "${tmpfile}"
fi

if ! grep -q "RotateKubeletServerCertificate=true" "${tmpfile}"; then
echo "[ERROR] Unable to inject --feature-gates into ${MANIFEST}. Please edit manually."
rm -f "${tmpfile}"
exit 1
fi

mv "${tmpfile}" "${MANIFEST}"
fi

echo "[INFO] Updated ${MANIFEST}. kube-controller-manager static pod will be restarted automatically by kubelet."

# Verification: ensure running kube-controller-manager has the correct feature-gate
# Wait briefly for static pod restart if needed
sleep 10

echo "[INFO] Verifying running kube-controller-manager process on this control plane node"
if /bin/ps -ef | grep kube-controller-manager | grep -v grep | grep -q "RotateKubeletServerCertificate=true"; then
echo "[SUCCESS] kube-controller-manager is running with RotateKubeletServerCertificate=true in --feature-gates"
exit 0
else
echo "[WARN] kube-controller-manager process does not yet show RotateKubeletServerCertificate=true."
echo "[WARN] It may still be restarting; re-run this verification:"
echo " /bin/ps -ef | grep kube-controller-manager | grep -v grep"
exit 1
fi