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."