> ## 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 Service Account Private Key File Argument Is Appropriate

### More Info:

Explicitly set a service account private key file for service accounts on the controller manager.

### Risk Level

Low

### 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, back up the controller manager static pod manifest:

           ```bash theme={null}
           sudo cp -a /etc/kubernetes/manifests/kube-controller-manager.yaml \
             /etc/kubernetes/manifests/kube-controller-manager.yaml.bak
           ```

        2. Identify (or create if needed) the service account private key file on the control plane node (example path below); ensure it is readable by the controller-manager:

           ```bash theme={null}
           sudo ls -l /etc/kubernetes/pki/sa.key || sudo openssl genrsa -out /etc/kubernetes/pki/sa.key 2048
           sudo chmod 600 /etc/kubernetes/pki/sa.key
           ```

        3. Edit the controller manager manifest to add or update the `--service-account-private-key-file` flag to point to that key file:

           ```bash theme={null}
           sudo sed -i \
             's#^\(\s*-\s*--service-account-private-key-file=\).*#\1/etc/kubernetes/pki/sa.key#' \
             /etc/kubernetes/manifests/kube-controller-manager.yaml || \
           sudo sed -i \
             '/^\s*- kube-controller-manager$/a\    - --service-account-private-key-file=/etc/kubernetes/pki/sa.key' \
             /etc/kubernetes/manifests/kube-controller-manager.yaml
           ```

        4. If the key file path (`/etc/kubernetes/pki/sa.key` in this example) is not already mounted into the container, edit the manifest to add a hostPath volume and mount (this restart is automatic when you save the file):

           ```bash theme={null}
           sudo sed -i '/volumes:/,/^ *[^- ]/s//volumes:\n  - name: sa-key\n    hostPath:\n      path: \/etc\/kubernetes\/pki\/sa.key\n      type: FileOrCreate\n&/' /etc/kubernetes/manifests/kube-controller-manager.yaml

           sudo sed -i '/volumeMounts:/,/^ *[^- ]/s//volumeMounts:\n  - name: sa-key\n    mountPath: \/etc\/kubernetes\/pki\/sa.key\n    readOnly: true\n&/' /etc/kubernetes/manifests/kube-controller-manager.yaml
           ```

           (Adjust if your manifest structure differs; saving the file will cause the kube-controller-manager static pod to restart.)

        5. Wait 30–60 seconds for the kubelet to restart the static pod, then verify on each control plane node that the controller manager process is using the correct flag and path:

           ```bash theme={null}
           /bin/ps -ef | grep kube-controller-manager | grep -v grep | \
             grep -- '--service-account-private-key-file=/etc/kubernetes/pki/sa.key'
           ```
      </Accordion>

      <Accordion title="Using kubectl">
        kubectl cannot modify the kube-controller-manager static pod manifest or its process flags. This setting must be changed directly on each control plane node by editing `/etc/kubernetes/manifests/kube-controller-manager.yaml`; see the Manual Steps section for detailed host-level instructions.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Automation: Configure --service-account-private-key-file for kube-controller-manager
        #
        # Run on: every control plane node (with root privileges)
        #
        # This script:
        #   - Ensures a service account private key exists at /etc/kubernetes/pki/sa.key
        #   - Adds/updates --service-account-private-key-file in
        #     /etc/kubernetes/manifests/kube-controller-manager.yaml
        #   - Relies on the kubelet to restart the static pod automatically
        #   - Verifies the flag is active in the running process
        #
        # Idempotent: safe to re-run.

        set -euo pipefail

        KCM_MANIFEST="/etc/kubernetes/manifests/kube-controller-manager.yaml"
        SA_KEY="/etc/kubernetes/pki/sa.key"
        SA_CERT="/etc/kubernetes/pki/sa.pub"
        BACKUP_SUFFIX="$(date +%Y%m%d%H%M%S)"

        if [[ $EUID -ne 0 ]]; then
          echo "ERROR: Run this script as root." >&2
          exit 1
        fi

        if [[ ! -f "$KCM_MANIFEST" ]]; then
          echo "ERROR: Manifest $KCM_MANIFEST not found on this node." >&2
          exit 1
        fi

        echo "==> Ensuring service account private key exists at $SA_KEY"

        if [[ ! -f "$SA_KEY" ]]; then
          mkdir -p "$(dirname "$SA_KEY")"
          chmod 700 "$(dirname "$SA_KEY")"

          echo "    Generating new RSA private key for service accounts..."
          openssl genrsa -out "$SA_KEY" 2048

          chmod 600 "$SA_KEY"
          chown root:root "$SA_KEY"

          echo "    Generating corresponding public key at $SA_CERT..."
          openssl rsa -in "$SA_KEY" -pubout -out "$SA_CERT"
        else
          echo "    Existing key found at $SA_KEY (leaving as-is)."
        fi

        echo "==> Updating $KCM_MANIFEST with --service-account-private-key-file flag"

        cp "$KCM_MANIFEST" "${KCM_MANIFEST}.bak.${BACKUP_SUFFIX}"

        if ! grep -q -- "--service-account-private-key-file=" "$KCM_MANIFEST"; then
          echo "    Flag not present; adding to manifest."

          # Insert the flag into the args list of the kube-controller-manager container
          # This sed adds the line right after the first occurrence of 'kube-controller-manager'
          # in the args section, which is typical for kubeadm-style manifests.
          sed -i '
            /- kube-controller-manager/ {
              :loop
              n
              /args:/!b loop
              n
              s/^/      - --service-account-private-key-file='"$SA_KEY"'\n/
            }
          ' "$KCM_MANIFEST"
        else
          echo "    Flag already present; normalizing its value to $SA_KEY."
          # Replace any existing value with the desired path
          sed -i "s#--service-account-private-key-file=\S*#--service-account-private-key-file=${SA_KEY}#g" "$KCM_MANIFEST"
        fi

        echo "==> Waiting for kube-controller-manager static pod to be restarted by kubelet..."
        sleep 20

        echo "==> Verification: checking running kube-controller-manager process"

        if /bin/ps -ef | grep kube-controller-manager | grep -v grep | grep -q -- "--service-account-private-key-file=${SA_KEY}"; then
          echo "SUCCESS: kube-controller-manager is running with --service-account-private-key-file=${SA_KEY}"
          exit 0
        else
          echo "WARNING: kube-controller-manager process does not yet show the expected flag."
          echo "Run the following manually to inspect the process:"
          echo "  /bin/ps -ef | grep kube-controller-manager | grep -v grep"
          exit 1
        fi
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>

### Additional Reading:

* [https://kubernetes.io/docs/admin/kube-controller-manager/](https://kubernetes.io/docs/admin/kube-controller-manager/)
