> ## 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 Disable Profiling

### More Info:

Verifies that the API server --profiling argument is set to false. Profiling exposes detailed system and program data that could aid an attacker.

### 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, open the API server static pod manifest for editing:
           ```bash theme={null}
           sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml
           ```

        2. In the `command:` or `args:` list for `kube-apiserver`, locate any existing `--profiling` flag and change it to:
           ```yaml theme={null}
           - --profiling=false
           ```
           If no `--profiling` flag is present, add this line under the other arguments, for example:
           ```yaml theme={null}
           spec:
             containers:
             - name: kube-apiserver
               command:
               - kube-apiserver
               - --profiling=false
               ...
           ```

        3. Save and exit the editor. The kubelet will automatically detect the manifest change and restart the `kube-apiserver` static pod; expect a brief API server disruption during this restart.

        4. After 30–60 seconds, verify on the same control plane node that the `kube-apiserver` process is now running with `--profiling=false`:
           ```bash theme={null}
           ps -ef | grep kube-apiserver | grep -v grep
           ```

        5. In the command output, confirm that `--profiling=false` appears and that there is no `--profiling=true` flag. Repeat steps 1–4 on every control plane node.
      </Accordion>

      <Accordion title="Using kubectl">
        kubectl cannot modify the kube-apiserver static pod manifest or its process flags, so this finding cannot be fixed through the Kubernetes API. The change must be made directly on every control plane node in `/etc/kubernetes/manifests/kube-apiserver.yaml`; see the Manual Steps section for the exact procedure.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Remediate CISKubernetes 1.2.15:
        # Ensure that the kube-apiserver --profiling argument is set to false.
        #
        # Run this script on every control plane node as root.
        # It is safe to re-run; it will only adjust the --profiling flag as needed.
        #
        # Operational impact:
        # - Editing /etc/kubernetes/manifests/kube-apiserver.yaml will trigger
        #   the kube-apiserver static 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)"

        if [[ $EUID -ne 0 ]]; then
          echo "ERROR: This script must be run as root on each control plane node." >&2
          exit 1
        fi

        if [[ ! -f "$APISERVER_MANIFEST" ]]; then
          echo "ERROR: kube-apiserver manifest not found at ${APISERVER_MANIFEST}." >&2
          exit 1
        fi

        echo "Creating backup of ${APISERVER_MANIFEST} in ${BACKUP_DIR}..."
        mkdir -p "$BACKUP_DIR"
        cp -p "$APISERVER_MANIFEST" "${BACKUP_DIR}/kube-apiserver.yaml"

        echo "Ensuring --profiling=false is configured..."

        # Normalize existing --profiling flags:
        # 1) Convert any explicit --profiling=true to --profiling=false
        # 2) Remove any duplicate occurrences after the first corrected one

        TMP_FILE="$(mktemp)"
        trap 'rm -f "${TMP_FILE}"' EXIT

        # Step 1: Replace any explicit --profiling=true with --profiling=false
        # and keep existing --profiling=false as-is.
        # We do not add the flag yet; that happens in Step 2.
        sed -E \
          -e 's/(--profiling)=[Tt][Rr][Uu][Ee]/\1=false/g' \
          "$APISERVER_MANIFEST" > "${TMP_FILE}.step1"

        # Step 2: Ensure exactly one --profiling=false exists in the container args list.
        # Approach:
        # - Remove all existing --profiling=... entries
        # - Add a single "--profiling=false" as the last item in the args: list
        #   (or create args: section with it if missing)
        awk '
          BEGIN {
            in_container = 0
            in_args = 0
          }
          # Detect containers: section and container start
          /containers:/ { print; next }
          /- name: kube-apiserver/ {
            in_container = 1
            print
            next
          }
          in_container == 1 && /- name:/ && $0 !~ /kube-apiserver/ {
            # another container; end of kube-apiserver container
            if (in_args == 1) {
              # If we were in args, ensure we have added profiling flag
              if (profiling_added == 0) {
                print "        - \"--profiling=false\""
              }
              in_args = 0
            }
            in_container = 0
            profiling_added = 0
            print
            next
          }
          in_container == 1 && /args:/ {
            in_args = 1
            profiling_added = 0
            print
            next
          }
          in_container == 1 && in_args == 1 {
            # Within args of kube-apiserver
            if ($0 ~ /--profiling=/) {
              # Skip all existing profiling flags
              next
            }
            # Detect end of args list (next non-indented key or end of container)
            if ($1 !~ /^-/ && $1 !~ /^ *-/ && $1 !~ /^ *\"--/ && $1 !~ /^ *\'--/ && $1 !~ /^ *- /) {
              # We reached a new section; add profiling flag before this line
              if (profiling_added == 0) {
                print "        - \"--profiling=false\""
                profiling_added = 1
              }
              in_args = 0
              print
              next
            }
            # Normal args line; just print
            print
            next
          }
          {
            print
          }
          END {
            # No special END handling; if args: existed it was handled above
          }
        ' "${TMP_FILE}.step1" > "${TMP_FILE}.step2"

        # Step 3: If kube-apiserver container has no args: section at all,
        # add one with --profiling=false
        awk '
          BEGIN {
            in_container = 0
            has_args = 0
          }
          /- name: kube-apiserver/ {
            in_container = 1
            has_args = 0
            print
            next
          }
          in_container == 1 && /args:/ {
            has_args = 1
            print
            next
          }
          in_container == 1 && /- name:/ && $0 !~ /kube-apiserver/ {
            # another container; end of kube-apiserver container
            if (has_args == 0) {
              print "      args:"
              print "        - \"--profiling=false\""
            }
            in_container = 0
            has_args = 0
            print
            next
          }
          {
            print
          }
          END {
            # If file ended while still in kube-apiserver container with no args
            if (in_container == 1 && has_args == 0) {
              print "      args:"
              print "        - \"--profiling=false\""
            }
          }
        ' "${TMP_FILE}.step2" > "${TMP_FILE}"

        # Move final result into place
        cp "${TMP_FILE}" "$APISERVER_MANIFEST"

        echo "Updated ${APISERVER_MANIFEST} with --profiling=false."
        echo "kubelet will restart the kube-apiserver static pod automatically."

        # Wait for kube-apiserver process to restart and reflect new flags
        echo "Waiting for kube-apiserver to be running with --profiling=false..."
        RETRY=30
        SLEEP_SECONDS=5
        SUCCESS=0

        for i in $(seq 1 "$RETRY"); do
          if /bin/ps -ef | grep kube-apiserver | grep -v grep >/dev/null 2>&1; then
            if /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -- "--profiling=false" >/dev/null 2>&1; then
              # Ensure no process still has --profiling=true
              if ! /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -- "--profiling=true" >/dev/null 2>&1; then
                SUCCESS=1
                break
              fi
            fi
          fi
          sleep "$SLEEP_SECONDS"
        done

        echo
        echo "Verification output (ps -ef | grep kube-apiserver | grep -v grep):"
        # Final verification command as per audit guidance
        /bin/ps -ef | grep kube-apiserver | grep -v grep || true

        if [[ "$SUCCESS" -eq 1 ]]; then
          echo
          echo "Result: kube-apiserver is running with --profiling=false and no --profiling=true flags detected."
          exit 0
        else
          echo
          echo "WARNING: kube-apiserver process does not yet show --profiling=false as expected."
          echo "Inspect the manifest and kubelet status on this control plane node."
          exit 1
        fi
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
