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

# Kubelet TLS Cert File And Private Key File Arguments Set As Appropriate

### More Info:

Setting tlsCertFile and tlsPrivateKeyFile provides the kubelet with a proper serving certificate and key for its API. This ensures kubelet connections are secured with trusted TLS material.

### Risk Level

Medium

### Address

Security

### Compliance Standards

* CIS Kubernetes

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. On every control plane node, identify the current API server manifest and TLS files:
           ```bash theme={null}
           sudo ls -l /etc/kubernetes/manifests/kube-apiserver.yaml
           sudo grep -n "tls-cert-file" /etc/kubernetes/manifests/kube-apiserver.yaml || echo "no tls-cert-file set"
           sudo grep -n "tls-private-key-file" /etc/kubernetes/manifests/kube-apiserver.yaml || echo "no tls-private-key-file set"
           sudo ls -l /etc/kubernetes/pki
           ```
           Decide which existing certificate/key pair you will use (for example, `/etc/kubernetes/pki/apiserver.crt` and `/etc/kubernetes/pki/apiserver.key`), or provision new ones according to your PKI policy.

        2. If you need to generate a new serving certificate and key for the API server on this control plane node, create them (example using openssl; adjust CN/SANs to match your cluster and certificate policy):
           ```bash theme={null}
           cd /etc/kubernetes/pki
           sudo openssl req -newkey rsa:4096 -nodes -keyout apiserver.key \
             -out apiserver.csr \
             -subj "/CN=kube-apiserver" \
             -addext "subjectAltName=DNS:kubernetes,DNS:kubernetes.default,DNS:kubernetes.default.svc,DNS:kubernetes.default.svc.cluster.local,IP:10.96.0.1"

           # Sign with your cluster CA (example: /etc/kubernetes/pki/ca.crt and ca.key)
           sudo openssl x509 -req -in apiserver.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
             -out apiserver.crt -days 365 -sha256
           sudo chmod 600 apiserver.key
           sudo chmod 644 apiserver.crt
           ```

        3. On every control plane node, edit the API server static pod manifest to set the TLS certificate and key flags (this edit will automatically restart the kube-apiserver pod when you save the file):
           ```bash theme={null}
           sudo cp /etc/kubernetes/manifests/kube-apiserver.yaml /etc/kubernetes/manifests/kube-apiserver.yaml.bak.$(date +%s)
           sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml
           ```
           In the `command:` section of the kube-apiserver container, ensure the following lines exist and point to the chosen files (adjust paths if different):
           ```yaml theme={null}
               - --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
               - --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
           ```
           Save and exit; kubelet will detect the manifest change and restart the API server pod with the new flags.

        4. If the certificate and key are not yet mounted into the API server container path, ensure the manifest has appropriate volume and volumeMount entries (still on every control plane node editing `/etc/kubernetes/manifests/kube-apiserver.yaml`):
           ```yaml theme={null}
             volumeMounts:
               - mountPath: /etc/kubernetes/pki
                 name: k8s-certs
                 readOnly: true
           ...
             volumes:
               - name: k8s-certs
                 hostPath:
                   path: /etc/kubernetes/pki
                   type: DirectoryOrCreate
           ```
           Save the file; kubelet will restart the API server pod again if you changed volumes.

        5. After waiting 30–60 seconds for the static pod to restart, verify on each control plane node that the kube-apiserver process is running with the required flags:
           ```bash theme={null}
           /bin/ps -ef | grep kube-apiserver | grep -v grep
           ```
           Confirm the output includes both `--tls-cert-file=/etc/kubernetes/pki/apiserver.crt` and `--tls-private-key-file=/etc/kubernetes/pki/apiserver.key` (or your chosen paths) for the running kube-apiserver process.
      </Accordion>

      <Accordion title="Using kubectl">
        kubectl cannot modify kube-apiserver process flags or the static pod manifest on the node. This finding must be fixed by editing `/etc/kubernetes/manifests/kube-apiserver.yaml` and related TLS files directly on every control plane node; see the Manual Steps section for exact host-level instructions.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Automation: Configure kube-apiserver --tls-cert-file and --tls-private-key-file
        # Scope: run on every control plane node (with sudo)
        #
        # This script:
        #   - Backs up /etc/kubernetes/manifests/kube-apiserver.yaml
        #   - Ensures --tls-cert-file and --tls-private-key-file arguments are present
        #   - Uses placeholder paths you must replace with correct certificate/key paths
        #   - Verifies via the audit command
        #
        # NOTE: Editing a static pod manifest under /etc/kubernetes/manifests will cause
        #       the kube-apiserver pod to restart on this node.

        set -euo pipefail

        APISERVER_MANIFEST="/etc/kubernetes/manifests/kube-apiserver.yaml"
        BACKUP_DIR="/etc/kubernetes/manifests/backup-$(date +%Y%m%d-%H%M%S)"
        # TODO: set these to the correct, existing cert and key paths for your environment
        TLS_CERT_PATH="/etc/kubernetes/pki/apiserver.crt"
        TLS_KEY_PATH="/etc/kubernetes/pki/apiserver.key"

        run_on_control_plane_only() {
          if [ ! -f "$APISERVER_MANIFEST" ]; then
            echo "This node does not appear to be a control plane node (no $APISERVER_MANIFEST). Skipping."
            exit 0
          fi
        }

        require_root() {
          if [ "$(id -u)" -ne 0 ]; then
            echo "Run this script as root (sudo)."
            exit 1
          fi
        }

        validate_paths() {
          if [ ! -f "$TLS_CERT_PATH" ]; then
            echo "TLS certificate not found at $TLS_CERT_PATH"
            echo "Update TLS_CERT_PATH in this script to a valid certificate file before re-running."
            exit 1
          fi
          if [ ! -f "$TLS_KEY_PATH" ]; then
            echo "TLS private key not found at $TLS_KEY_PATH"
            echo "Update TLS_KEY_PATH in this script to a valid key file before re-running."
            exit 1
          fi
        }

        backup_manifest() {
          mkdir -p "$BACKUP_DIR"
          cp -a "$APISERVER_MANIFEST" "$BACKUP_DIR/kube-apiserver.yaml"
          echo "Backed up $APISERVER_MANIFEST to $BACKUP_DIR/kube-apiserver.yaml"
        }

        ensure_arg() {
          local arg_name="$1"
          local arg_value="$2"
          local file="$3"

          # If argument already present, replace its value; if absent, append to command args.
          if grep -q -- "$arg_name=" "$file"; then
            # Replace existing value (handles both '--arg=val' forms)
            sed -i "s#${arg_name}=[^\"'[:space:]]*#${arg_name}=${arg_value}#g" "$file"
          else
            # Append argument in the container command args. This assumes standard kubeadm-style manifest.
            # Insert before the first occurrence of '--advertise-address' if present,
            # otherwise just append as an extra - --arg line.
            if grep -q -- "--advertise-address" "$file"; then
              # Insert line before '--advertise-address'
              # Works on typical YAML:
              #   - --some-arg
              #   - --advertise-address=...
              sed -i "/--advertise-address/ i\    - ${arg_name}=${arg_value}" "$file"
            else
              # Append near the end of the args list: insert before the closing 'volumeMounts' or 'volumes'
              if grep -q "volumeMounts:" "$file"; then
                sed -i "/volumeMounts:/ i\    - ${arg_name}=${arg_value}" "$file"
              else
                # Fallback: append at end of file (still valid for static pod)
                printf "    - %s=%s\n" "$arg_name" "$arg_value" >> "$file"
              fi
            fi
          fi
        }

        apply_fix() {
          echo "Ensuring --tls-cert-file and --tls-private-key-file are configured in $APISERVER_MANIFEST"

          ensure_arg "--tls-cert-file" "$TLS_CERT_PATH" "$APISERVER_MANIFEST"
          ensure_arg "--tls-private-key-file" "$TLS_KEY_PATH" "$APISERVER_MANIFEST"

          echo "Changes applied. kubelet will restart the kube-apiserver static pod automatically."
        }

        verify() {
          echo "Waiting for kube-apiserver process to reflect new arguments..."

          # Give kubelet some time to restart the static pod if it just changed
          sleep 10

          if /bin/ps -ef | grep kube-apiserver | grep -v grep >/dev/null 2>&1; then
            echo "kube-apiserver process detected. Verifying TLS arguments..."
          else
            echo "kube-apiserver process not found yet. Current processes:"
            /bin/ps -ef | grep kube-apiserver || true
            exit 1
          fi

          # Show the relevant arguments for manual confirmation
          /bin/ps -ef | grep kube-apiserver | grep -v grep | tr -s ' ' | sed 's/ /\n/g' | \
            grep -E -- '--tls-cert-file|--tls-private-key-file' || true

          # Automated check for both flags and correct values
          if /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -q -- "--tls-cert-file=${TLS_CERT_PATH}" \
             && /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -q -- "--tls-private-key-file=${TLS_KEY_PATH}"; then
            echo "Verification successful: kube-apiserver is running with the desired --tls-cert-file and --tls-private-key-file."
          else
            echo "Verification FAILED: kube-apiserver does not show the expected TLS arguments."
            echo "Inspect the kube-apiserver manifest and process output above to troubleshoot."
            exit 1
          fi
        }

        main() {
          require_root
          run_on_control_plane_only
          validate_paths
          backup_manifest
          apply_fix
          verify
        }

        main "$@"
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
