Rotate Kubelet Server Certificate Argument Is Set True
More Info:
Enable kubelet server certificate rotation.
Risk Level
Low
Address
Security
Compliance Standards
- APRA CPS 234 (Australia)
- BSI C5 (Germany)
- Brazil LGPD
- CCPA / CPRA (California)
- CIS Critical Security Controls v8
- CIS GKE
- CMMC 2.0
- CSA Cloud Controls Matrix v4
- DPDPA
- Digital Operational Resilience Act (EU)
- Essential 8
- ISO/IEC 27017
- ISO/IEC 27018
- ISO/IEC 27701
- KSA PDPL
- MAS Technology Risk Management (Singapore)
- MITRE ATT&CK (Cloud)
- NIST SP 800-171
- NYDFS 23 NYCRR 500
- SWIFT Customer Security Controls Framework
- Sarbanes-Oxley IT General Controls
- UK NCSC Cyber Assessment Framework
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
On every worker node, check how kubelet is configured:
ps -fC kubeletls -l /var/lib/kubelet/config.yaml /etc/kubernetes/kubelet-config.yaml /etc/systemd/system/kubelet.service.dReview the kubelet command line from
psfor any--rotate-kubelet-server-certificateflag. -
If using the kubelet config file at
/var/lib/kubelet/config.yaml, edit it to enable the feature gate (createfeatureGatesif missing):sudo sed -i '/^featureGates:/,/^[^ ]/d' /var/lib/kubelet/config.yamlsudo bash -c 'cat <<EOF >> /var/lib/kubelet/config.yaml
featureGates: RotateKubeletServerCertificate: true EOF'
Adjust indentation if your file is using different YAML structure.
3. Ensure no systemd drop-in overrides this by forcing it to false. On every worker node, edit `/etc/systemd/system/kubelet.service.d/10-kubelet-args.conf` and remove any `--rotate-kubelet-server-certificate=false` from `KUBELET_ARGS`, or change it to true:
```bash
sudo sed -i 's/--rotate-kubelet-server-certificate=false/--rotate-kubelet-server-certificate=true/g' \
/etc/systemd/system/kubelet.service.d/10-kubelet-args.conf
-
If the kubelet is configured only via executable arguments and not via the config file, on every worker node append the flag to
KUBELET_ARGSin/etc/systemd/system/kubelet.service.d/10-kubelet-args.conf:sudo sed -i 's/^KUBELET_ARGS="/KUBELET_ARGS="--rotate-kubelet-server-certificate=true /' \/etc/systemd/system/kubelet.service.d/10-kubelet-args.confOr, if
KUBELET_ARGSdoes not exist, add a new line:echo 'KUBELET_ARGS="--rotate-kubelet-server-certificate=true"' | \sudo tee -a /etc/systemd/system/kubelet.service.d/10-kubelet-args.conf -
Restart kubelet on every worker node so changes take effect (this restarts the kubelet process):
sudo systemctl daemon-reloadsudo systemctl restart kubelet.servicesudo systemctl status kubelet -l -
Verify on every worker node that kubelet is running with server certificate rotation enabled:
/bin/ps -fC kubeletConfirm either the flag
--rotate-kubelet-server-certificate=trueis present and not set to false, and/or that the kubelet config file in use containsRotateKubeletServerCertificate: trueinfeatureGates.
Using kubectl
kubectl cannot modify kubelet’s host-level configuration or systemd unit files, so this finding cannot be fixed via the Kubernetes API. To remediate, you must change the kubelet config and/or systemd unit on every worker node (as described in the Manual Steps section) and then restart the kubelet service.
Automation
#!/usr/bin/env bash
#
# Enable kubelet server certificate rotation on all worker nodes.
# Run this script on each worker node as root.
#
# Idempotent:
# - Safely updates /var/lib/kubelet/config.yaml featureGates
# - Ensures no conflicting --rotate-kubelet-server-certificate=false flag
# - Restarts kubelet only when needed
#
# Requirements: bash, systemd, kubelet using /var/lib/kubelet/config.yaml
set -euo pipefail
KUBELET_CONFIG="/var/lib/kubelet/config.yaml"
KUBELET_DROPIN_DIR="/etc/systemd/system/kubelet.service.d"
KUBELET_DROPIN_FILE="${KUBELET_DROPIN_DIR}/10-kubelet-args.conf"
NEED_RESTART=0
echo "[INFO] Running on host: $(hostname)"
#-----------------------------
# Helper: ensure featureGates map exists and set RotateKubeletServerCertificate: true
#-----------------------------
ensure_feature_gate() {
local cfg="${1}"
if [[ ! -f "${cfg}" ]]; then
echo "[ERROR] Kubelet config file not found at ${cfg}. Aborting."
exit 1
fi
# Create a backup once per run
if [[ ! -f "${cfg}.bak.cis-rotate-kubelet-server-cert" ]]; then
cp -p "${cfg}" "${cfg}.bak.cis-rotate-kubelet-server-cert"
echo "[INFO] Backup created at ${cfg}.bak.cis-rotate-kubelet-server-cert"
fi
# If the exact line exists and is already true, assume it's correctly set
if grep -Eq '^[[:space:]]*RotateKubeletServerCertificate:[[:space:]]*true[[:space:]]*$' "${cfg}"; then
echo "[INFO] RotateKubeletServerCertificate already set to true in ${cfg}"
return
fi
# If featureGates block exists, update or add key
if grep -q '^[[:space:]]*featureGates:' "${cfg}"; then
# If key exists with false, flip to true
if grep -Eq '^[[:space:]]*RotateKubeletServerCertificate:' "${cfg}"; then
echo "[INFO] Updating existing RotateKubeletServerCertificate in featureGates to true"
# Replace only in the featureGates section
perl -0pi -e '
s/(featureGates:[^\n]*\n(?:[ \t].*\n)*)/do {
my $blk = $1;
$blk =~ s/^([ \t]*RotateKubeletServerCertificate:).*/$1 true/m;
$blk;
}/e
' "${cfg}"
else
# Insert key into existing featureGates map (2 spaces indent)
echo "[INFO] Adding RotateKubeletServerCertificate: true to existing featureGates"
perl -0pi -e '
s/(^[ \t]*featureGates:[^\n]*\n)/$1 RotateKubeletServerCertificate: true\n/m
' "${cfg}"
fi
else
# No featureGates: append a minimal block
echo "[INFO] Adding featureGates section with RotateKubeletServerCertificate: true"
cat <<'EOF' >> "${cfg}"
featureGates:
RotateKubeletServerCertificate: true
EOF
fi
NEED_RESTART=1
}
#-----------------------------
# Helper: adjust systemd kubelet args drop-in
# - Ensure no explicit false flag
# - Optionally ensure true flag if using arg-based config
#-----------------------------
ensure_systemd_args() {
local dropin="${KUBELET_DROPIN_FILE}"
if [[ ! -d "${KUBELET_DROPIN_DIR}" ]]; then
echo "[INFO] Kubelet systemd drop-in dir not found at ${KUBELET_DROPIN_DIR}, skipping arg checks."
return
fi
if [[ -f "${dropin}" ]]; then
if [[ ! -f "${dropin}.bak.cis-rotate-kubelet-server-cert" ]]; then
cp -p "${dropin}" "${dropin}.bak.cis-rotate-kubelet-server-cert"
echo "[INFO] Backup created at ${dropin}.bak.cis-rotate-kubelet-server-cert"
fi
# Remove any explicit --rotate-kubelet-server-certificate=false
if grep -q -- '--rotate-kubelet-server-certificate=false' "${dropin}"; then
echo "[INFO] Removing --rotate-kubelet-server-certificate=false from ${dropin}"
sed -i 's/--rotate-kubelet-server-certificate=false//g' "${dropin}"
NEED_RESTART=1
fi
# If args-based config is used, ensure true flag exists.
# We add it only if no flag is present at all.
if ! grep -q -- '--rotate-kubelet-server-certificate=' "${dropin}"; then
if grep -q 'KUBELET_ARGS' "${dropin}"; then
echo "[INFO] Adding --rotate-kubelet-server-certificate=true to KUBELET_ARGS in ${dropin}"
# Append to the end of KUBELET_ARGS line
sed -i 's/^\(.*KUBELET_ARGS=.*\)"$/\1 --rotate-kubelet-server-certificate=true"/' "${dropin}" || true
NEED_RESTART=1
else
echo "[INFO] No KUBELET_ARGS found in ${dropin}; not adding flag."
fi
else
echo "[INFO] A --rotate-kubelet-server-certificate flag already exists in ${dropin}; not modifying it (except removing false)."
fi
else
echo "[INFO] ${dropin} not found; kubelet may be managed differently. Skipping arg-based remediation."
fi
}
#-----------------------------
# Apply config file remediation (Method 1)
#-----------------------------
ensure_feature_gate "${KUBELET_CONFIG}"
#-----------------------------
# Ensure no conflicting systemd arg, and add true if using args (Method 2)
#-----------------------------
ensure_systemd_args
#-----------------------------
# Restart kubelet if needed
#-----------------------------
if [[ "${NEED_RESTART}" -eq 1 ]]; then
echo "[INFO] Reloading systemd and restarting kubelet"
systemctl daemon-reload
systemctl restart kubelet.service
else
echo "[INFO] No changes made; kubelet restart not required"
fi
echo "[INFO] Checking kubelet status"
systemctl status kubelet -l --no-pager || {
echo "[ERROR] kubelet is not healthy after configuration changes"
exit 1
}
#-----------------------------
# Verification: confirm RotateKubeletServerCertificate is enabled
# Prefer local config file; optionally cross-check with process flags.
#-----------------------------
echo "[INFO] Verifying kubelet configuration"
if grep -Eq '^[[:space:]]*RotateKubeletServerCertificate:[[:space:]]*true[[:space:]]*$' "${KUBELET_CONFIG}"; then
echo "[OK] ${KUBELET_CONFIG} has RotateKubeletServerCertificate: true"
else
echo "[WARN] ${KUBELET_CONFIG} does not clearly show RotateKubeletServerCertificate: true"
fi
echo "[INFO] Current kubelet process flags:"
/bin/ps -fC kubelet || true
echo "[INFO] Verification complete on host: $(hostname)"