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

# API Server Should Set TLS Certificate And Private Key

### More Info:

Verifies that --tls-cert-file and --tls-private-key-file are set so the API server serves connections over TLS rather than plaintext HTTP.

### Risk Level

High

### 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, confirm where the API server static pod manifest is located and back it up:
           ```bash theme={null}
           sudo ls -l /etc/kubernetes/manifests/kube-apiserver.yaml
           sudo cp -a /etc/kubernetes/manifests/kube-apiserver.yaml /etc/kubernetes/manifests/kube-apiserver.yaml.bak.$(date +%F-%H%M%S)
           ```

        2. On the same control plane node, ensure you have or create a TLS certificate and key for the API server (adjust CN/SANs as appropriate for your cluster):
           ```bash theme={null}
           sudo mkdir -p /etc/kubernetes/pki
           cd /etc/kubernetes/pki

           sudo openssl req -newkey rsa:4096 -nodes -keyout apiserver.key \
             -x509 -days 365 -out apiserver.crt \
             -subj "/CN=kube-apiserver"
           sudo chmod 600 apiserver.key
           sudo chmod 644 apiserver.crt
           ```

        3. On every control plane node, edit the API server manifest to reference the TLS cert and key (this will cause the kube-apiserver static pod to restart when you save):
           ```bash theme={null}
           sudo sed -i '/- --tls-cert-file/d' /etc/kubernetes/manifests/kube-apiserver.yaml
           sudo sed -i '/- --tls-private-key-file/d' /etc/kubernetes/manifests/kube-apiserver.yaml

           sudo sed -i '/- kube-apiserver/a\  - --tls-cert-file=/etc/kubernetes/pki/apiserver.crt\n  - --tls-private-key-file=/etc/kubernetes/pki/apiserver.key' \
             /etc/kubernetes/manifests/kube-apiserver.yaml
           ```
           If the `- kube-apiserver` line does not exist exactly as matched above, instead open the file in an editor and add these two flags under `command:` or `args:`:
           ```yaml theme={null}
           - --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
           - --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
           ```

        4. On every control plane node, ensure the certificate and key are mounted into the kube-apiserver container if not already (edit with an editor if needed):\
           Add under `spec.containers[0].volumeMounts` in `/etc/kubernetes/manifests/kube-apiserver.yaml`:
           ```yaml theme={null}
           - mountPath: /etc/kubernetes/pki
             name: k8s-certs
             readOnly: true
           ```
           And ensure a matching volume exists under `spec.volumes`:
           ```yaml theme={null}
           - name: k8s-certs
             hostPath:
               path: /etc/kubernetes/pki
               type: DirectoryOrCreate
           ```
           Saving the file will restart the kube-apiserver static pod.

        5. Wait for the kube-apiserver pod to restart and become Running on each control plane node:
           ```bash theme={null}
           # From any machine with kubectl access
           kubectl -n kube-system get pods -l component=kube-apiserver -o wide
           ```

        6. Verify on every control plane node that the kube-apiserver process is now using the TLS certificate and key flags:
           ```bash theme={null}
           /bin/ps -ef | grep kube-apiserver | grep -v grep | \
             egrep -- '--tls-cert-file=|--tls-private-key-file='
           ```
      </Accordion>

      <Accordion title="Using kubectl">
        kubectl cannot modify the kube-apiserver static pod manifest or its process flags; this setting must be changed directly in `/etc/kubernetes/manifests/kube-apiserver.yaml` on every control plane node. Refer to the Manual Steps section for the exact edits and verification commands to remediate this finding.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Remediation for CIS Kubernetes 4.2.9:
        # Ensure kube-apiserver has --tls-cert-file and --tls-private-key-file set.
        #
        # Run on: every control plane node in the cluster (as root or with sudo).
        #
        # This script:
        #   - Backs up /etc/kubernetes/manifests/kube-apiserver.yaml
        #   - Ensures TLS cert/key files exist (placeholders if you don't have real ones yet)
        #   - Ensures the kube-apiserver manifest has the required flags
        #   - Relies on the kubelet to restart the static pod automatically
        #   - Verifies via the process flags
        #
        # NOTE: You must replace the placeholder certificate and key contents
        #       with valid TLS materials following your PKI/cluster design.
        #

        set -euo pipefail

        APISERVER_MANIFEST="/etc/kubernetes/manifests/kube-apiserver.yaml"
        TLS_CERT_FILE="/etc/kubernetes/pki/apiserver.crt"
        TLS_KEY_FILE="/etc/kubernetes/pki/apiserver.key"
        BACKUP_SUFFIX="$(date +%Y%m%d%H%M%S)"

        require_root() {
          if [ "$EUID" -ne 0 ]; then
            echo "ERROR: This script must be run as root or with sudo." >&2
            exit 1
          fi
        }

        check_manifest_exists() {
          if [ ! -f "$APISERVER_MANIFEST" ]; then
            echo "ERROR: $APISERVER_MANIFEST not found on this node. Is this a control plane node?" >&2
            exit 1
          fi
        }

        backup_manifest() {
          local backup="${APISERVER_MANIFEST}.${BACKUP_SUFFIX}.bak"
          cp -p "$APISERVER_MANIFEST" "$backup"
          echo "Backup created: $backup"
        }

        ensure_tls_files_exist() {
          # If you already have correct TLS files from kubeadm or your PKI,
          # this will not overwrite them.
          if [ ! -f "$TLS_CERT_FILE" ]; then
            echo "WARNING: $TLS_CERT_FILE not found. Creating placeholder file."
            mkdir -p "$(dirname "$TLS_CERT_FILE")"
            cat > "$TLS_CERT_FILE" <<'EOF'
        -----BEGIN CERTIFICATE-----
        PLACEHOLDER-APISERVER-CERTIFICATE
        Replace this placeholder with a valid apiserver TLS certificate
        following your cluster's PKI design.
        -----END CERTIFICATE-----
        EOF
            chmod 600 "$TLS_CERT_FILE"
          fi

          if [ ! -f "$TLS_KEY_FILE" ]; then
            echo "WARNING: $TLS_KEY_FILE not found. Creating placeholder file."
            mkdir -p "$(dirname "$TLS_KEY_FILE")"
            cat > "$TLS_KEY_FILE" <<'EOF'
        -----BEGIN PRIVATE KEY-----
        PLACEHOLDER-APISERVER-PRIVATE-KEY
        Replace this placeholder with a valid apiserver TLS private key
        matching the certificate above.
        -----END PRIVATE KEY-----
        EOF
            chmod 600 "$TLS_KEY_FILE"
          fi
        }

        ensure_arg_in_manifest() {
          local arg="$1"
          local value="$2"
          local file="$3"

          # If argument is already present (with any value), do nothing
          if grep -E "^\s*- ${arg}=" "$file" >/dev/null 2>&1; then
            # Optionally normalize the value if you want strict paths;
            # here we leave existing values untouched for safety.
            return 0
          fi

          # Insert argument into the 'command:' section for kube-apiserver container
          # We look for the first '- kube-apiserver' line and add the flag immediately after.
          if grep -E "^\s*- kube-apiserver" "$file" >/dev/null 2>&1; then
            # Use awk to insert line after '- kube-apiserver'
            awk -v a="$arg" -v v="$value" '
              {
                print $0
                if ($1 == "-" && $2 == "kube-apiserver") {
                  printf "    - %s=%s\n", a, v
                }
              }
            ' "$file" > "${file}.tmp"
            mv "${file}.tmp" "$file"
          else
            echo "ERROR: Could not locate '- kube-apiserver' command entry in $file; manual edit required." >&2
            exit 1
          fi
        }

        main() {
          require_root
          check_manifest_exists
          backup_manifest
          ensure_tls_files_exist

          echo "Ensuring --tls-cert-file and --tls-private-key-file are set in $APISERVER_MANIFEST"

          ensure_arg_in_manifest "--tls-cert-file" "$TLS_CERT_FILE" "$APISERVER_MANIFEST"
          ensure_arg_in_manifest "--tls-private-key-file" "$TLS_KEY_FILE" "$APISERVER_MANIFEST"

          echo "Manifest updated. The kubelet will automatically restart the kube-apiserver static pod."
          echo "Waiting 30 seconds for the kube-apiserver to restart..."
          sleep 30

          echo "Verification: checking kube-apiserver process flags"
          if /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -- "--tls-cert-file=${TLS_CERT_FILE}" >/dev/null 2>&1 \
             && /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -- "--tls-private-key-file=${TLS_KEY_FILE}" >/dev/null 2>&1; then
            echo "SUCCESS: kube-apiserver is running with --tls-cert-file and --tls-private-key-file set."
            /bin/ps -ef | grep kube-apiserver | grep -v grep
            exit 0
          else
            echo "WARNING: kube-apiserver process does not yet show the expected TLS flags." >&2
            echo "Current kube-apiserver processes:" >&2
            /bin/ps -ef | grep kube-apiserver | grep -v grep >&2
            exit 1
          fi
        }

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