Skip to main content

Kubelet Rotate Server Certificates Argument Set To True

More Info:​

The kubelet --rotate-server-certificates argument should be set to true so the kubelet automatically requests and rotates its serving certificates. Disabling this increases exposure to expired or compromised server certificates.

Risk Level​

High

Address​

Security

Compliance Standards​

  • CIS OKE

Triage and Remediation​

Remediation​

Manual Steps
  1. On every worker node, open the kubelet systemd drop-in config for editing:

    sudo vi /etc/systemd/system/kubelet.service.d/00-default.conf
  2. In the ExecStart= line, ensure the kubelet is started with --rotate-server-certificates=true. Add it if missing, or change false to true, for example:

    ExecStart=/usr/bin/kubelet \
    ... \
    --rotate-server-certificates=true
  3. If the kubelet also uses a config file (e.g. /etc/kubernetes/kubelet-config.json), check it for a conflicting setting and remove or align it. For example, if present, update this key to true or delete it so the flag above is authoritative:

    sudo vi /etc/kubernetes/kubelet-config.json

    Ensure either this field is set true or absent:

    "rotateServerCertificate": true
  4. Reload systemd and restart kubelet on the same worker node:

    sudo systemctl daemon-reload
    sudo systemctl restart kubelet.service
  5. Confirm kubelet is healthy on the worker node:

    sudo systemctl status kubelet -l
  6. Verify the argument is now set to true on the worker node (repeat on all workers):

    /bin/ps -fC kubelet | grep -- --rotate-server-certificates

    The output must include --rotate-server-certificates=true.

Using kubectl

kubectl cannot modify kubelet process flags or host-level config files such as /etc/systemd/system/kubelet.service.d/00-default.conf or /etc/kubernetes/kubelet-config.json on worker nodes. To enable --rotate-server-certificates=true, make the change directly on each worker node as described in the Manual Steps section.

Automation
#!/usr/bin/env bash
#
# Enable kubelet --rotate-server-certificates=true on every worker node.
# Usage:
# 1) Populate NODES with worker node hostnames/IPs reachable via SSH.
# 2) Ensure passwordless sudo and SSH access.
# 3) Run this script from any admin machine: ./enable-kubelet-rotate-server-certs.sh
#
# Idempotent: safe to re-run.

set -euo pipefail

# EDIT THIS: list of worker nodes
NODES=(
worker-node-1
worker-node-2
)

SSH_OPTS="-o BatchMode=yes -o StrictHostKeyChecking=accept-new"

remote_run() {
local node="$1"; shift
ssh ${SSH_OPTS} "root@${node}" "$@"
}

for node in "${NODES[@]}"; do
echo "=== Processing node: ${node} ==="

remote_run "${node}" bash -s << 'EOF'
set -euo pipefail

UNIT_DIR="/etc/systemd/system/kubelet.service.d"
UNIT_FILE="${UNIT_DIR}/00-default.conf"

if [ ! -f "${UNIT_FILE}" ]; then
echo "ERROR: ${UNIT_FILE} not found; kubelet may be managed differently on this node."
exit 1
fi

echo "Current ${UNIT_FILE}:"
sed -n '1,160p' "${UNIT_FILE}" || true

# Ensure the drop-in has an [Service] section; if not, add one.
if ! grep -q '^\[Service\]' "${UNIT_FILE}"; then
printf '\n[Service]\n' >> "${UNIT_FILE}"
fi

# Make a backup once per run
BACKUP="${UNIT_FILE}.$(date +%Y%m%d%H%M%S).bak"
cp "${UNIT_FILE}" "${BACKUP}"
echo "Backup created at ${BACKUP}"

# Normalize into a single Environment line for editing
# (handles the common case where KUBELET_KUBECONFIG_ARGS etc. are defined)
if ! grep -q 'KUBELET_EXTRA_ARGS' "${UNIT_FILE}"; then
# If there's no extra args line, append one
cat << 'EOL' >> "${UNIT_FILE}"
Environment="KUBELET_EXTRA_ARGS="
EOL
fi

# Edit KUBELET_EXTRA_ARGS to ensure --rotate-server-certificates=true
tmpfile="$(mktemp)"
while IFS= read -r line; do
if [[ "${line}" =~ ^Environment= ]]; then
# Only touch lines with KUBELET_EXTRA_ARGS
if [[ "${line}" == *"KUBELET_EXTRA_ARGS"* ]]; then
# Remove any existing --rotate-server-certificates flags
cleaned="$(printf '%s\n' "${line}" | sed -E 's_--rotate-server-certificates(=[^" ]*)?__g')"
# Collapse multiple spaces
cleaned="$(printf '%s\n' "${cleaned}" | sed -E 's/ +/ /g')"
# Ensure it ends before final quote, then append desired flag
if [[ "${cleaned}" =~ \"$ ]]; then
cleaned="${cleaned%\"} --rotate-server-certificates=true\""
else
cleaned="${cleaned} --rotate-server-certificates=true"
fi
echo "${cleaned}" >> "${tmpfile}"
else
echo "${line}" >> "${tmpfile}"
fi
else
echo "${line}" >> "${tmpfile}"
fi
done < "${UNIT_FILE}"

mv "${tmpfile}" "${UNIT_FILE}"

echo "Updated ${UNIT_FILE}:"
sed -n '1,160p' "${UNIT_FILE}" || true

echo "Reloading systemd and restarting kubelet (this restarts the kubelet process)..."
systemctl daemon-reload
systemctl restart kubelet.service

echo "Verifying kubelet status..."
systemctl status kubelet -l --no-pager || {
echo "ERROR: kubelet service not healthy after restart."
exit 1
}

echo "Verifying kubelet process has --rotate-server-certificates=true..."
if /bin/ps -fC kubelet | grep -q -- '--rotate-server-certificates=true'; then
echo "OK: kubelet is running with --rotate-server-certificates=true"
else
echo "ERROR: kubelet is not running with --rotate-server-certificates=true"
/bin/ps -fC kubelet || true
exit 1
fi

EOF

echo "=== Node ${node} done ==="
done

echo "All nodes processed."