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

# Controller Manager Should Use Individual Service Account Credentials

### More Info:

Verifies that --use-service-account-credentials is set to true so each controller uses its own service account, enabling least-privilege RBAC for control loops.

### 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, back up the existing manifest:
           ```bash theme={null}
           sudo cp -a /etc/kubernetes/manifests/kube-controller-manager.yaml /etc/kubernetes/manifests/kube-controller-manager.yaml.backup.$(date +%s)
           ```

        2. Open the controller manager manifest for editing:
           ```bash theme={null}
           sudo vi /etc/kubernetes/manifests/kube-controller-manager.yaml
           ```

        3. In the `spec.containers[0].command` section, ensure the following flag is present and set to true (add it if missing):
           ```yaml theme={null}
           - --use-service-account-credentials=true
           ```
           Example snippet:
           ```yaml theme={null}
           spec:
             containers:
               - name: kube-controller-manager
                 command:
                   - kube-controller-manager
                   - --use-service-account-credentials=true
                   # ...other existing flags...
           ```

        4. Save and exit the editor. The kube-controller-manager static pod will be automatically restarted by the kubelet because the manifest under `/etc/kubernetes/manifests` was modified.

        5. Wait 30–60 seconds, then confirm the controller manager process is running with the correct flag:
           ```bash theme={null}
           ps -ef | grep kube-controller-manager | grep -v grep
           ```

        6. Verify that the output includes `--use-service-account-credentials=true` in the kube-controller-manager command line.
      </Accordion>

      <Accordion title="Using kubectl">
        kubectl cannot modify the kube-controller-manager static pod manifest or its process flags, so this setting cannot be fixed via the Kubernetes API. To remediate, edit `/etc/kubernetes/manifests/kube-controller-manager.yaml` directly on every control plane node as described in the Manual Steps section.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Remediation: Ensure kube-controller-manager uses --use-service-account-credentials=true
        # Scope: Run on every control plane node
        # Idempotent: Yes – safe to re-run

        set -euo pipefail

        MANIFEST="/etc/kubernetes/manifests/kube-controller-manager.yaml"
        BACKUP_DIR="/etc/kubernetes/manifests/backup-controller-manager-sa-creds"
        TIMESTAMP="$(date +%Y%m%d-%H%M%S)"

        echo "=== Ensuring kube-controller-manager uses individual service account credentials ==="

        # 1) Preconditions
        if [ "$(id -u)" -ne 0 ]; then
          echo "ERROR: This script must be run as root (to edit ${MANIFEST})." >&2
          exit 1
        fi

        if [ ! -f "${MANIFEST}" ]; then
          echo "ERROR: Manifest not found: ${MANIFEST}" >&2
          exit 1
        fi

        # 2) Backup current manifest once per run (kept with timestamp)
        mkdir -p "${BACKUP_DIR}"
        cp "${MANIFEST}" "${BACKUP_DIR}/kube-controller-manager.yaml.${TIMESTAMP}"
        echo "Backup created at ${BACKUP_DIR}/kube-controller-manager.yaml.${TIMESTAMP}"

        # 3) Normalize line endings to avoid sed issues
        dos2unix "${MANIFEST}" >/dev/null 2>&1 || true

        # 4) Ensure the flag exists and is set to true
        #
        # Logic:
        # - If --use-service-account-credentials is already present, force to =true.
        # - Else, add it as a new - --use-service-account-credentials=true line
        #   under the args: section (preferred) or after the kube-controller-manager
        #   command line if args: is absent.

        echo "Patching ${MANIFEST} to set --use-service-account-credentials=true"

        # If flag exists anywhere, set it to true in-place
        if grep -q -- "--use-service-account-credentials" "${MANIFEST}"; then
          # Handle cases like:
          #   - --use-service-account-credentials=false
          #   - --use-service-account-credentials
          sed -i -E \
            's|(--use-service-account-credentials)(=[^"[:space:]]*)?|\1=true|g' \
            "${MANIFEST}"
        else
          # Flag not present; add it.
          # Prefer to inject under args: if present.
          if grep -qE '^[[:space:]]*args:' "${MANIFEST}"; then
            # Insert after the "args:" line, indented with two spaces and dash.
            # This keeps yaml structure valid in common kubeadm layouts.
            awk '
              /^[[:space:]]*args:[[:space:]]*$/ && inserted == 0 {
                print $0
                print "    - --use-service-account-credentials=true"
                inserted=1
                next
              }
              { print $0 }
              END {
                if (inserted == 0) {
                  # fallback if args: pattern somehow not matched
                  print "  args:"
                  print "    - --use-service-account-credentials=true"
                }
              }
            ' "${MANIFEST}" > "${MANIFEST}.tmp"
            mv "${MANIFEST}.tmp" "${MANIFEST}"
          else
            # No args: section; append an args block near the end of the container spec.
            # This is a best-effort generic insertion that keeps yaml valid in most
            # standard kubeadm-generated manifests.
            awk '
              BEGIN { inserted=0 }
              /image:.*kube-controller-manager/ && inserted == 0 {
                print $0
                next
              }
              /command:|args:/ && inserted == 0 { seen_block=1 }
              /- kube-controller-manager/ && inserted == 0 { seen_cmd=1 }
              /^[[:space:]]*resources:/ && inserted == 0 && seen_cmd == 1 {
                print "    args:"
                print "      - --use-service-account-credentials=true"
                inserted=1
              }
              { print $0 }
              END {
                if (inserted == 0) {
                  print "    args:"
                  print "      - --use-service-account-credentials=true"
                }
              }
            ' "${MANIFEST}" > "${MANIFEST}.tmp"
            mv "${MANIFEST}.tmp" "${MANIFEST}"
          fi
        fi

        echo "Manifest updated. kube-controller-manager static pod will be restarted automatically by kubelet."

        # 5) Wait for kube-controller-manager to restart and apply new args
        echo "Waiting for kube-controller-manager process to reflect new flag..."
        # Wait up to 120 seconds for the flag to appear
        END_TIME=$((SECONDS + 120))
        while [ ${SECONDS} -lt ${END_TIME} ]; do
          if /bin/ps -ef | grep kube-controller-manager | grep -v grep | grep -q -- "--use-service-account-credentials=true"; then
            break
          fi
          sleep 5
        done

        # 6) Verification (adapted from audit command)
        echo "=== Verification ==="
        /bin/ps -ef | grep kube-controller-manager | grep -v grep || {
          echo "ERROR: kube-controller-manager process not found." >&2
          exit 1
        }

        if /bin/ps -ef | grep kube-controller-manager | grep -v grep | grep -q -- "--use-service-account-credentials=true"; then
          echo "PASS: kube-controller-manager is running with --use-service-account-credentials=true"
          exit 0
        else
          echo "FAIL: kube-controller-manager is NOT running with --use-service-account-credentials=true" >&2
          echo "Inspect ${MANIFEST} and kubelet logs for errors." >&2
          exit 1
        fi
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
