Skip to main content

Ensure Rotate Certificates Argument Is Not Disabled

More Info:

Enable kubelet client certificate rotation.

Risk Level

Low

Address

Security

Compliance Standards

  • APRA CPS 234 (Australia)
  • BSI C5 (Germany)
  • Brazil LGPD
  • CCPA / CPRA (California)
  • CIS AKS
  • CIS Critical Security Controls v8
  • 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)
  • NIS2 Directive
  • 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

Manual Steps
  1. On every worker node, back up and edit the kubelet configuration to enable certificate rotation:

    sudo cp -a /var/lib/kubelet/config.yaml /var/lib/kubelet/config.yaml.bak.$(date +%s)
    sudo sed -i '/^rotateCertificates:/d' /var/lib/kubelet/config.yaml
    echo 'rotateCertificates: true' | sudo tee -a /var/lib/kubelet/config.yaml
  2. On every worker node, ensure no kubelet systemd drop-in overrides this with a false flag:

    if [ -f /etc/systemd/system/kubelet.service.d/10-kubelet-args.conf ]; then
    sudo sed -i 's/--rotate-certificates=false//g' /etc/systemd/system/kubelet.service.d/10-kubelet-args.conf
    fi
  3. On every worker node where kubelet flags are managed via an environment file, ensure the argument is not set to false and is explicitly true if present:

    if [ -f /etc/sysconfig/kubelet ]; then
    sudo sed -i 's/--rotate-certificates=false//g' /etc/sysconfig/kubelet
    grep -q -- '--rotate-certificates=' /etc/sysconfig/kubelet || \
    echo 'KUBELET_CERTIFICATE_ARGS="--rotate-certificates=true"' | sudo tee -a /etc/sysconfig/kubelet
    fi
    if [ -f /etc/default/kubelet ]; then
    sudo sed -i 's/--rotate-certificates=false//g' /etc/default/kubelet
    grep -q -- '--rotate-certificates=' /etc/default/kubelet || \
    echo 'KUBELET_CERTIFICATE_ARGS="--rotate-certificates=true"' | sudo tee -a /etc/default/kubelet
    fi
  4. On every worker node, reload systemd units and restart kubelet (this will briefly disrupt pods on the node):

    sudo systemctl daemon-reload
    sudo systemctl restart kubelet.service
  5. On every worker node, verify kubelet is running:

    sudo systemctl status kubelet -l
  6. On every worker node, verify from the running process that --rotate-certificates is not set to false:

    /bin/ps -fC kubelet
    # Ensure there is no '--rotate-certificates=false' in the args; if present, repeat the steps above.
Using kubectl

kubectl cannot configure kubelet process flags or host files, so it cannot fix this finding. This must be remediated directly on every worker node by editing the kubelet configuration and systemd units; follow the steps in the Manual Steps section.

Automation
#!/usr/bin/env bash
#
# Enable kubelet client certificate rotation on every worker node.
# Run as root on each worker node (safe to re-run).

set -euo pipefail

# Detect if this node runs kubelet; exit quietly if not
if ! pgrep -x kubelet >/dev/null 2>&1; then
echo "No kubelet process found on this node; nothing to do."
exit 0
fi

# 1) Ensure kubelet config enables rotateCertificates
KUBELET_JSON="/etc/kubernetes/kubelet/kubelet-config.json"
KUBELET_YAML="/var/lib/kubelet/config.yaml"

ensure_rotate_in_json() {
local f="$1"
if [ ! -f "$f" ]; then
echo "File $f not found, skipping JSON config adjustment."
return 0
fi

# If rotateCertificates is already true, nothing to do
if jq -e '.rotateCertificates == true' "$f" >/dev/null 2>&1; then
echo "rotateCertificates already true in $f"
return 0
fi

# Set/overwrite rotateCertificates to true
echo "Setting rotateCertificates=true in $f"
tmp="$(mktemp)"
if jq '.rotateCertificates = true' "$f" >"$tmp"; then
cp "$tmp" "$f"
chmod --reference="$f" "$f" 2>/dev/null || true
chown --reference="$f" "$f" 2>/dev/null || true
else
echo "ERROR: Failed to update $f with jq" >&2
rm -f "$tmp"
exit 1
fi
rm -f "$tmp"
}

ensure_rotate_in_yaml() {
local f="$1"
if [ ! -f "$f" ]; then
echo "File $f not found, skipping YAML config adjustment."
return 0
fi

# If rotateCertificates: true already present, nothing to do
if grep -Eq '^[[:space:]]*rotateCertificates:[[:space:]]*true[[:space:]]*$' "$f"; then
echo "rotateCertificates already true in $f"
return 0
fi

echo "Ensuring rotateCertificates: true in $f"
# Remove existing rotateCertificates lines, append correct setting
tmp="$(mktemp)"
grep -Ev '^[[:space:]]*rotateCertificates:[[:space:]]*' "$f" >"$tmp" || true
printf "\nrotateCertificates: true\n" >>"$tmp"
cp "$tmp" "$f"
chmod --reference="$f" "$f" 2>/dev/null || true
chown --reference="$f" "$f" 2>/dev/null || true
rm -f "$tmp"
}

# Prefer the path specified in the finding, but also honor the benchmark path if present
if [ -f "$KUBELET_JSON" ]; then
ensure_rotate_in_json "$KUBELET_JSON"
fi

if [ -f "$KUBELET_YAML" ]; then
ensure_rotate_in_yaml "$KUBELET_YAML"
fi

# 2) Ensure systemd drop-in does NOT disable rotate-certificates
DROPIN="/etc/systemd/system/kubelet.service.d/10-kubelet-args.conf"
if [ -f "$DROPIN" ]; then
echo "Checking $DROPIN for --rotate-certificates=false overrides"
tmp="$(mktemp)"
# Remove any explicit --rotate-certificates=false occurrences
# from Environment lines
sed -E 's/--rotate-certificates=false[[:space:]]*//g' "$DROPIN" >"$tmp"
# Also clean up duplicate spaces
sed -E -i 's/[[:space:]]+/ /g' "$tmp"
if ! diff -q "$DROPIN" "$tmp" >/dev/null 2>&1; then
echo "Removing --rotate-certificates=false from $DROPIN"
cp "$tmp" "$DROPIN"
chmod --reference="$DROPIN" "$DROPIN" 2>/dev/null || true
chown --reference="$DROPIN" "$DROPIN" 2>/dev/null || true
fi
rm -f "$tmp"
else
echo "$DROPIN not found; no systemd override to clean."
fi

# 3) If using explicit executable arguments variable, ensure --rotate-certificates=true is present
# This is implementation-specific; edit if your environment uses a different env file.
CERT_ENV_FILE="/etc/sysconfig/kubelet"
if [ -f "$CERT_ENV_FILE" ]; then
echo "Ensuring --rotate-certificates=true in $CERT_ENV_FILE (if KUBELET_CERTIFICATE_ARGS is used)"
if grep -q '^KUBELET_CERTIFICATE_ARGS=' "$CERT_ENV_FILE"; then
if ! grep -q '--rotate-certificates=true' "$CERT_ENV_FILE"; then
tmp="$(mktemp)"
sed -E 's/^(KUBELET_CERTIFICATE_ARGS="*)(.*)("\s*$)/\1\2 --rotate-certificates=true\3/' \
"$CERT_ENV_FILE" >"$tmp" || true
if ! grep -q '--rotate-certificates=true' "$tmp"; then
echo 'KUBELET_CERTIFICATE_ARGS="--rotate-certificates=true"' >>"$tmp"
fi
cp "$tmp" "$CERT_ENV_FILE"
rm -f "$tmp"
else
echo "--rotate-certificates=true already present in $CERT_ENV_FILE"
fi
else
echo 'KUBELET_CERTIFICATE_ARGS="--rotate-certificates=true"' >>"$CERT_ENV_FILE"
fi
else
echo "$CERT_ENV_FILE not found; skipping explicit KUBELET_CERTIFICATE_ARGS configuration."
fi

# 4) Restart kubelet to apply changes
echo "Restarting kubelet..."
systemctl daemon-reload
systemctl restart kubelet.service

echo "Checking kubelet status..."
systemctl status kubelet -l --no-pager || {
echo "ERROR: kubelet did not start correctly after restart" >&2
exit 1
}

# 5) Verification matching the audit intent
echo "Verifying that kubelet has NOT disabled certificate rotation..."
/bin/ps -fC kubelet || {
echo "ERROR: kubelet process not found after restart" >&2
exit 1
}

if /bin/ps -fC kubelet | grep -q -- '--rotate-certificates=false'; then
echo "ERROR: kubelet is still running with --rotate-certificates=false" >&2
exit 1
fi

echo "Verification passed: kubelet is running and --rotate-certificates is not set to false."

Additional Reading: