> ## 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 Audit Log Maxage Should Be 30 Or More

### More Info:

Verifies that --audit-log-maxage is set to 30 days or an appropriate value so audit records are retained long enough for investigations.

### 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`, add or modify the audit log max age flag so it is present exactly once and set to at least 30. For example, ensure there is a line like:
           ```yaml theme={null}
           - --audit-log-maxage=30
           ```

        3. Save and exit the file. The kubelet will automatically detect the change and restart the `kube-apiserver` static pod. Be aware this briefly restarts the API server on that node.

        4. Wait for the `kube-apiserver` pod to restart and become Running on that node:
           ```bash theme={null}
           sudo crictl ps | grep kube-apiserver
           ```
           (Use `docker ps` instead of `crictl` if the node uses Docker.)

        5. Verify the `kube-apiserver` process now includes the correct `--audit-log-maxage` parameter on each control plane node:
           ```bash theme={null}
           /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -- '--audit-log-maxage=30'
           ```
      </Accordion>

      <Accordion title="Using kubectl">
        kubectl cannot modify the kube-apiserver static pod manifest or its process flags, so it cannot be used to set `--audit-log-maxage`. This must be fixed directly on each control plane node by editing `/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
        #
        # Remediation: Ensure kube-apiserver --audit-log-maxage is set to 30 (or higher)
        # Scope: every control plane node
        #
        # Usage: run as root on each control plane node:
        #   chmod +x fix-audit-log-maxage.sh
        #   ./fix-audit-log-maxage.sh
        #
        # This script is idempotent and safe to re-run.

        set -euo pipefail

        APISERVER_MANIFEST="/etc/kubernetes/manifests/kube-apiserver.yaml"
        DESIRED_MAXAGE="30"

        echo "=== Ensuring --audit-log-maxage is set to ${DESIRED_MAXAGE} (or higher) in ${APISERVER_MANIFEST}"

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

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

        # Backup once (idempotent: do not overwrite an existing backup)
        BACKUP="${APISERVER_MANIFEST}.pre-audit-log-maxage.bak"
        if [[ ! -f "${BACKUP}" ]]; then
          cp -p "${APISERVER_MANIFEST}" "${BACKUP}"
          echo "Backup created at ${BACKUP}"
        else
          echo "Backup already exists at ${BACKUP}"
        fi

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

        # Determine if the flag is already present
        if grep -qE -- '--audit-log-maxage(=|\s)' "${APISERVER_MANIFEST}"; then
          echo "Existing --audit-log-maxage flag found; updating value if needed."

          # Replace any existing value with the desired value
          # Handles forms:
          #   - --audit-log-maxage=10
          #   - --audit-log-maxage 10
          sed -E \
            -e "s/(--audit-log-maxage=)[0-9]+/\1${DESIRED_MAXAGE}/" \
            -e "s/(--audit-log-maxage[[:space:]]+)[0-9]+/\1${DESIRED_MAXAGE}/" \
            "${APISERVER_MANIFEST}" > "${TMP_FILE}"

        else
          echo "No --audit-log-maxage flag found; adding it."

          # Insert a new line with the flag under the 'command:' or after '--audit-log-path'
          # Preference: place it immediately after an existing --audit-log-path line if present.
          if grep -q -- '--audit-log-path' "${APISERVER_MANIFEST}"; then
            # Insert after first occurrence of --audit-log-path
            awk -v flag="        - --audit-log-maxage=${DESIRED_MAXAGE}" '
              {
                print $0
                if (!inserted && $0 ~ /--audit-log-path/) {
                  print flag
                  inserted=1
                }
              }
              END {
                if (!inserted) {
                  # Fallback: append at end of file (should not normally happen here)
                  print flag
                }
              }
            ' "${APISERVER_MANIFEST}" > "${TMP_FILE}"
          else
            # Fallback: append to the command list after detecting "command:" block
            awk -v flag="        - --audit-log-maxage=${DESIRED_MAXAGE}" '
              /command:[[:space:]]*$/ {
                print $0
                getline
                # Print the first list element then insert our flag
                print $0
                print flag
                printed=1
                next
              }
              { print $0 }
              END {
                if (!printed) {
                  # Absolute fallback: append at end of file
                  print flag
                }
              }
            ' "${APISERVER_MANIFEST}" > "${TMP_FILE}"
          fi
        fi

        # Only replace the original if there is an actual change
        if cmp -s "${APISERVER_MANIFEST}" "${TMP_FILE}"; then
          echo "No changes required; manifest already configured with --audit-log-maxage=${DESIRED_MAXAGE}."
        else
          mv "${TMP_FILE}" "${APISERVER_MANIFEST}"
          chmod 600 "${APISERVER_MANIFEST}" || true
          echo "Updated ${APISERVER_MANIFEST} with --audit-log-maxage=${DESIRED_MAXAGE}."

          echo
          echo "NOTE: Because this is a static pod manifest under /etc/kubernetes/manifests,"
          echo "the kube-apiserver pod on this node will be restarted automatically by kubelet."
        fi

        # Verification: check running kube-apiserver process on this node
        # (there may be a short delay while the pod restarts)
        echo
        echo "=== Verifying running kube-apiserver process has --audit-log-maxage=${DESIRED_MAXAGE}"

        # Wait up to 60 seconds for kube-apiserver to be running with the new flag
        TRIES=12
        SLEEP_SEC=5
        SUCCESS=0

        for i in $(seq 1 "${TRIES}"); do
          if /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -q -- "--audit-log-maxage=${DESIRED_MAXAGE}"; then
            SUCCESS=1
            break
          fi
          echo "  Attempt ${i}/${TRIES}: kube-apiserver with --audit-log-maxage=${DESIRED_MAXAGE} not detected yet; waiting ${SLEEP_SEC}s..."
          sleep "${SLEEP_SEC}"
        done

        if [[ "${SUCCESS}" -eq 1 ]]; then
          echo "Verification succeeded: kube-apiserver is running with --audit-log-maxage=${DESIRED_MAXAGE}."
          echo
          echo "Command used for verification (for manual re-check):"
          echo "/bin/ps -ef | grep kube-apiserver | grep -v grep"
          exit 0
        else
          echo "WARNING: After waiting, kube-apiserver with --audit-log-maxage=${DESIRED_MAXAGE} was not detected." >&2
          echo "Please check the kube-apiserver pod status and logs." >&2
          echo
          echo "Manual verification command:"
          echo "/bin/ps -ef | grep kube-apiserver | grep -v grep"
          exit 1
        fi
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
