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
Remediation
Manual Steps
-
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 -
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.yamlIf a
--feature-gates=argument already exists, edit that line instead (with a text editor such assudo vi /etc/kubernetes/manifests/kube-controller-manager.yaml) to ensure it includesRotateKubeletServerCertificate=truein the comma-separated list. -
Wait for the kube-controller-manager pod to be recreated (editing any file under
/etc/kubernetes/manifestscauses an automatic restart via the kubelet). You can watch for the new pod on any machine withkubectlaccess:kubectl -n kube-system get pods -l component=kube-controller-manager -w -
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 grepConfirm the output includes
--feature-gates=RotateKubeletServerCertificate=true(or a--feature-gates=value that containsRotateKubeletServerCertificate=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