> ## Documentation Index
> Fetch the complete documentation index at: https://cloudanix.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Ensure Rotate Kubelet Server Certificate Argument Is Enabled

### 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 EKS
* 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

<Tabs>
  <Tab title="Remediation">
    ### Remediation

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. On every worker node, open the kubelet config file and enable the feature gate:
           ```bash theme={null}
           sudo sed -i '/^featureGates:/,/^[^ ]/d' /var/lib/kubelet/config.yaml
           sudo tee -a /var/lib/kubelet/config.yaml >/dev/null <<'EOF'
           featureGates:
             RotateKubeletServerCertificate: true
           EOF
           ```

        2. On every worker node, ensure no conflicting flag is set in the systemd drop-in; remove any existing `--rotate-kubelet-server-certificate` setting:
           ```bash theme={null}
           sudo sed -i 's/--rotate-kubelet-server-certificate=[^ ]*//g' /etc/systemd/system/kubelet.service.d/10-kubelet-args.conf
           ```

        3. (Optional alternative to step 1 if you prefer flags instead of config file; still on every worker node) Append the flag to the kubelet args line:
           ```bash theme={null}
           sudo sed -i 's/^KUBELET_ARGS="/KUBELET_ARGS="--rotate-kubelet-server-certificate=true /' /etc/systemd/system/kubelet.service.d/10-kubelet-args.conf
           ```

        4. On every worker node, reload systemd and restart kubelet (this restarts the kubelet process, affecting node registration/Pods briefly):
           ```bash theme={null}
           sudo systemctl daemon-reload
           sudo systemctl restart kubelet.service
           sudo systemctl status kubelet -l --no-pager
           ```

        5. On any machine with kubectl access, verify kubelet config via the configz endpoint for each worker node (replace NODE\_NAME with each node’s name from `kubectl get nodes`):
           ```bash theme={null}
           kubectl proxy --port=8001 >/tmp/kubectl-proxy.log 2>&1 &
           export HOSTNAME_PORT=localhost:8001
           export NODE_NAME=<worker-node-name>
           curl -sSL "http://${HOSTNAME_PORT}/api/v1/nodes/${NODE_NAME}/proxy/configz" | grep -A3 RotateKubeletServerCertificate
           ```

        6. On every worker node, confirm the running kubelet process includes the correct setting and no `false` override:
           ```bash theme={null}
           /bin/ps -fC kubelet
           ```
           Inspect the output to ensure either:
           * no `--rotate-kubelet-server-certificate` flag is present (so the config file controls it and configz shows `RotateKubeletServerCertificate:true`), or
           * if present, it is `--rotate-kubelet-server-certificate=true` and not `false`.
      </Accordion>

      <Accordion title="Using kubectl">
        kubectl cannot be used to enable `RotateKubeletServerCertificate` because this setting is applied via kubelet host-level configuration on each worker node (for example `/etc/kubernetes/kubelet/kubelet-config.json`, `/var/lib/kubelet/config.yaml`, and the systemd unit drop-in). Make the changes directly on every worker node as described in the Manual Steps section and then restart the kubelet service.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Enable RotateKubeletServerCertificate on all worker nodes (run via SSH, Ansible, or similar).
        # This script is idempotent and safe to re-run.
        #
        # Usage (example with a single node):
        #   ssh root@worker-node 'bash -s' < enable-kubelet-server-cert-rotation.sh
        #
        # Apply this to every worker node.

        set -euo pipefail

        KUBELET_CONFIG_FILE="/var/lib/kubelet/config.yaml"
        KUBELET_ARGS_DROPIN="/etc/systemd/system/kubelet.service.d/10-kubelet-args.conf"

        changed=0

        echo "=== [$(hostname)] Configuring kubelet server certificate rotation ==="

        #############################################
        # 1) Ensure featureGates in kubelet config  #
        #############################################

        if [[ -f "${KUBELET_CONFIG_FILE}" ]]; then
          echo "-> Updating ${KUBELET_CONFIG_FILE}"

          # Backup once per run
          cp -a "${KUBELET_CONFIG_FILE}" "${KUBELET_CONFIG_FILE}.$(date +%Y%m%d%H%M%S).bak"

          # Ensure featureGates block exists; use yq if available, otherwise do minimal YAML edit
          if command -v yq >/dev/null 2>&1; then
            # Use yq to set featureGates.RotateKubeletServerCertificate=true
            yq -i '.featureGates.RotateKubeletServerCertificate = true' "${KUBELET_CONFIG_FILE}"
          else
            # Minimal YAML manipulation without external tools
            # If featureGates block exists, replace/ensure key; else append block at end
            if grep -qE '^featureGates:' "${KUBELET_CONFIG_FILE}"; then
              # Remove any existing RotateKubeletServerCertificate entry
              sed -i '/featureGates:/,/^[^[:space:]]/ s/^[[:space:]]*RotateKubeletServerCertificate:.*$/  RotateKubeletServerCertificate: true/' "${KUBELET_CONFIG_FILE}"
              # If key was not present, append it under existing featureGates:
              if ! sed -n '/featureGates:/,/^[^[:space:]]/p' "${KUBELET_CONFIG_FILE}" | grep -q 'RotateKubeletServerCertificate:'; then
                # Insert after the 'featureGates:' line
                awk '
                  /^featureGates:/ && !added { print; print "  RotateKubeletServerCertificate: true"; added=1; next }
                  { print }
                ' "${KUBELET_CONFIG_FILE}" > "${KUBELET_CONFIG_FILE}.tmp" && mv "${KUBELET_CONFIG_FILE}.tmp" "${KUBELET_CONFIG_FILE}"
              fi
            else
              cat <<'EOF' >> "${KUBELET_CONFIG_FILE}"

        featureGates:
          RotateKubeletServerCertificate: true
        EOF
            fi
          fi

          changed=1
        else
          echo "-> WARNING: ${KUBELET_CONFIG_FILE} not found; skipping featureGates update"
        fi

        ##############################################################
        # 2) Ensure no flag overrides to false; set flag to true     #
        #    in 10-kubelet-args.conf when using executable args      #
        ##############################################################

        if [[ -f "${KUBELET_ARGS_DROPIN}" ]]; then
          echo "-> Updating ${KUBELET_ARGS_DROPIN}"

          cp -a "${KUBELET_ARGS_DROPIN}" "${KUBELET_ARGS_DROPIN}.$(date +%Y%m%d%H%M%S).bak"

          # Remove any explicit false setting
          sed -i 's/--rotate-kubelet-server-certificate=false//g' "${KUBELET_ARGS_DROPIN}"

          # Ensure true flag is present at the end of KUBELET_ARGS or ExecStart line

          if grep -q 'KUBELET_ARGS' "${KUBELET_ARGS_DROPIN}"; then
            if ! grep -q -- '--rotate-kubelet-server-certificate=true' "${KUBELET_ARGS_DROPIN}"; then
              # Append to existing KUBELET_ARGS
              awk '
                /KUBELET_ARGS/ && !done {
                  sub(/"$/, " --rotate-kubelet-server-certificate=true\"")
                  done=1
                }
                { print }
              ' "${KUBELET_ARGS_DROPIN}" > "${KUBELET_ARGS_DROPIN}.tmp" && mv "${KUBELET_ARGS_DROPIN}.tmp" "${KUBELET_ARGS_DROPIN}"
              changed=1
            fi
          elif grep -q '^ExecStart=' "${KUBELET_ARGS_DROPIN}"; then
            if ! grep -q -- '--rotate-kubelet-server-certificate=true' "${KUBELET_ARGS_DROPIN}"; then
              sed -i 's#^ExecStart=\(.*kubelet.*\)$#ExecStart=\1 --rotate-kubelet-server-certificate=true#' "${KUBELET_ARGS_DROPIN}"
              changed=1
            fi
          else
            # If the drop-in is present but does not define args, leave it unchanged.
            echo "-> INFO: ${KUBELET_ARGS_DROPIN} does not define kubelet args; no changes"
          fi
        else
          echo "-> INFO: ${KUBELET_ARGS_DROPIN} not found; assuming kubelet fully configured via config file"
        fi

        ########################################
        # 3) Reload systemd and restart kubelet
        ########################################

        if (( changed == 1 )); then
          echo "-> Reloading systemd and restarting kubelet (this will restart the kubelet on this node)"
          systemctl daemon-reload
          systemctl restart kubelet.service
        else
          echo "-> No configuration changes detected; kubelet restart not required"
        fi

        echo "-> Checking kubelet status"
        systemctl status kubelet.service -l --no-pager || true

        ########################################
        # 4) Verification                      #
        ########################################

        echo "=== Verification: kubelet process flags ==="
        /bin/ps -fC kubelet || true

        echo
        echo "=== Verification: RotateKubeletServerCertificate setting ==="

        if command -v yq >/dev/null 2>&1 && [[ -f "${KUBELET_CONFIG_FILE}" ]]; then
          echo "- From ${KUBELET_CONFIG_FILE} (via yq):"
          yq '.featureGates.RotateKubeletServerCertificate' "${KUBELET_CONFIG_FILE}" 2>/dev/null || echo "  (key not found)"
        else
          if [[ -f "${KUBELET_CONFIG_FILE}" ]]; then
            echo "- From ${KUBELET_CONFIG_FILE} (grep):"
            grep -A3 '^featureGates:' "${KUBELET_CONFIG_FILE}" || echo "  (featureGates block not found)"
          else
            echo "- ${KUBELET_CONFIG_FILE} not present; skipping file-based verification"
          fi
        fi

        echo
        echo "=== Completed on $(hostname) ==="
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>

### Additional Reading:

* [https://kubernetes.io/docs/admin/kubelet-tls-bootstrapping/#kubelet-configuration](https://kubernetes.io/docs/admin/kubelet-tls-bootstrapping/#kubelet-configuration)
