> ## 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 That A Minimal Audit Policy Is Created

### More Info:

An audit policy file must be configured so the API server records audit events. Without it, security-relevant activity is not logged.

### 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. **Review current API server flags for audit configuration**\
           Run on: **every control plane node**
           ```bash theme={null}
           /bin/ps -ef | grep kube-apiserver | grep -v grep
           ```
           Check whether `--audit-policy-file=` is present. If it is already configured and points to an existing file, refine that policy instead of creating a new one.

        2. **Create a minimal audit policy file**\
           Run on: **every control plane node**
           ```bash theme={null}
           sudo mkdir -p /etc/kubernetes/audit
           sudo tee /etc/kubernetes/audit/audit-policy.yaml >/dev/null <<'EOF'
           apiVersion: audit.k8s.io/v1
           kind: Policy
           rules:
             # Log all requests at the Metadata level.
             - level: Metadata
           EOF
           ```
           Adjust the rules later as appropriate for your organization’s logging and privacy requirements.

        3. **Ensure filesystem permissions are appropriate**\
           Run on: **every control plane node**
           ```bash theme={null}
           sudo chown root:root /etc/kubernetes/audit/audit-policy.yaml
           sudo chmod 600 /etc/kubernetes/audit/audit-policy.yaml
           ```

        4. **Configure the API server static pod to use the audit policy**\
           Run on: **every control plane node**\
           Edit the manifest:
           ```bash theme={null}
           sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml
           ```
           In the `command:` or `args:` list for `kube-apiserver`, ensure these flags are present (add them if missing, adjusting paths as needed):
           ```yaml theme={null}
           - --audit-policy-file=/etc/kubernetes/audit/audit-policy.yaml
           - --audit-log-path=/var/log/kubernetes/audit.log
           - --audit-log-maxage=30
           - --audit-log-maxbackup=10
           - --audit-log-maxsize=100
           ```
           In the `volumeMounts:` section for the container, add:
           ```yaml theme={null}
           - mountPath: /etc/kubernetes/audit
             name: audit-policy
             readOnly: true
           - mountPath: /var/log/kubernetes
             name: audit-logs
           ```
           In the `volumes:` section of the pod spec, add:
           ```yaml theme={null}
           - name: audit-policy
             hostPath:
               path: /etc/kubernetes/audit
               type: DirectoryOrCreate
           - name: audit-logs
             hostPath:
               path: /var/log/kubernetes
               type: DirectoryOrCreate
           ```
           **Operational impact:** saving this file will cause the kubelet to restart the `kube-apiserver` static pod.

        5. **Confirm that the API server restarted cleanly and is writing audit logs**\
           Run on: **every control plane node**
           ```bash theme={null}
           sudo ls -l /var/log/kubernetes/audit.log
           sudo tail -n 5 /var/log/kubernetes/audit.log
           ```
           Ensure new entries appear when you make API calls (for example, run `kubectl get pods` from a machine with kubectl access).

        6. **Verify the API server process now includes the audit policy flag**\
           Run on: **every control plane node**
           ```bash theme={null}
           /bin/ps -ef | grep kube-apiserver | grep -v grep
           ```
           Confirm that the output includes `--audit-policy-file=/etc/kubernetes/audit/audit-policy.yaml` (and associated audit log flags), demonstrating that the minimal audit policy is in use.
      </Accordion>

      <Accordion title="Using kubectl">
        kubectl cannot configure the API server’s audit policy or edit `/etc/kubernetes/manifests/kube-apiserver.yaml`, because these are host-level settings on each control plane node. To address this finding, make the changes directly on the control plane nodes as described in the Manual Steps section.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Automation: Ensure a minimal audit policy is created and enabled for kube-apiserver
        # Scope: run on every control plane node (with root privileges)
        #
        # This script will:
        #   - Create a minimal audit policy file if missing
        #   - Ensure kube-apiserver static pod manifest references that policy
        #   - Ensure audit log output file path is configured
        #   - Verify kube-apiserver is running with the expected audit flags
        #
        # Safe to re-run (idempotent).

        set -euo pipefail

        APISERVER_MANIFEST="/etc/kubernetes/manifests/kube-apiserver.yaml"
        AUDIT_POLICY_FILE="/etc/kubernetes/audit-policy.yaml"
        AUDIT_LOG_FILE="/var/log/kubernetes/apiserver-audit.log"
        BACKUP_SUFFIX=".pre_audit_$(date +%Y%m%d%H%M%S)"

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

        check_files_exist() {
          if [[ ! -f "$APISERVER_MANIFEST" ]]; then
            echo "ERROR: kube-apiserver static pod manifest not found at $APISERVER_MANIFEST" >&2
            echo "This script expects a static pod-based control plane." >&2
            exit 1
          fi
        }

        ensure_audit_policy_file() {
          if [[ -f "$AUDIT_POLICY_FILE" ]]; then
            echo "Audit policy file already exists at $AUDIT_POLICY_FILE"
            return
          fi

          echo "Creating minimal audit policy at $AUDIT_POLICY_FILE"

          install -o root -g root -m 0640 /dev/null "$AUDIT_POLICY_FILE"

          cat >"$AUDIT_POLICY_FILE" <<'EOF'
        apiVersion: audit.k8s.io/v1
        kind: Policy
        # Minimal audit policy: log at least metadata for all requests.
        rules:
          - level: Metadata
        EOF
        }

        ensure_audit_log_path() {
          # Ensure directory for log exists
          local log_dir
          log_dir="$(dirname "$AUDIT_LOG_FILE")"
          if [[ ! -d "$log_dir" ]]; then
            echo "Creating audit log directory $log_dir"
            mkdir -p "$log_dir"
            chmod 0750 "$log_dir"
          fi
        }

        backup_manifest_once() {
          # Only back up once per script run
          if [[ -z "${_BACKED_UP:-}" ]]; then
            cp "$APISERVER_MANIFEST" "${APISERVER_MANIFEST}${BACKUP_SUFFIX}"
            echo "Backed up $APISERVER_MANIFEST to ${APISERVER_MANIFEST}${BACKUP_SUFFIX}"
            _BACKED_UP=1
          fi
        }

        ensure_flag_in_manifest() {
          local flag="$1"        # e.g. --audit-policy-file
          local value="$2"       # e.g. /etc/kubernetes/audit-policy.yaml
          local file="$APISERVER_MANIFEST"

          if grep -qE "[[:space:]]${flag}=" "$file"; then
            # Replace existing value
            backup_manifest_once
            # Use perl-compatible regex for safe in-place replacement
            sed -i "s#${flag}=[^\"'[:space:]]*#${flag}=${value}#g" "$file"
            echo "Updated existing ${flag} in $file to ${value}"
          elif grep -qE "[[:space:]]${flag}[[:space:]]" "$file"; then
            # Flag present without =value form; ensure correct form
            backup_manifest_once
            sed -i "s#${flag}[[:space:]]#${flag}=${value} #g" "$file"
            echo "Updated existing ${flag} in $file to ${value}"
          else
            # Add new flag under the kube-apiserver command args
            backup_manifest_once
            # Try to append into the 'command:' array if present; otherwise append to 'args:'
            if grep -qE '^\s*- kube-apiserver' "$file"; then
              # Typical static pod: first list item under container command
              sed -i "s#^\(\s*-\s*kube-apiserver.*\)#\1\n\1 \"${flag}=${value}\"#g" "$file" || true
            fi
            # Fallback: try to add under args:
            if ! grep -q "${flag}=${value}" "$file"; then
              if grep -qE '^\s*args:\s*$' "$file"; then
                # Append new arg line
                awk -v f="${flag}=${value}" '
                  /^[[:space:]]*args:[[:space:]]*$/ && !added {
                    print $0
                    print "    - " f
                    added=1
                    next
                  }
                  { print $0 }
                ' "$file" >"${file}.tmp" && mv "${file}.tmp" "$file"
              else
                # As a last resort, append an args section with this flag
                cat >>"$file" <<EOF_APPEND

          args:
            - "${flag}=${value}"
        EOF_APPEND
              fi
            fi
            echo "Ensured ${flag}=${value} configured in $file"
          fi
        }

        ensure_audit_flags() {
          echo "Ensuring kube-apiserver manifest has audit flags configured"

          ensure_flag_in_manifest "--audit-policy-file" "$AUDIT_POLICY_FILE"
          ensure_flag_in_manifest "--audit-log-path" "$AUDIT_LOG_FILE"

          # Optional but sensible defaults; harmless if already present
          ensure_flag_in_manifest "--audit-log-maxage" "30"
          ensure_flag_in_manifest "--audit-log-maxbackup" "10"
          ensure_flag_in_manifest "--audit-log-maxsize" "100"
        }

        restart_notice() {
          echo
          echo "NOTE: Editing $APISERVER_MANIFEST causes the kubelet to restart the kube-apiserver static pod."
          echo "This restart should occur automatically within a short time."
          echo
        }

        verify() {
          echo "Verifying that kube-apiserver is running with audit flags..."
          sleep 10

          /bin/ps -ef | grep kube-apiserver | grep -v grep || {
            echo "ERROR: kube-apiserver process not found. Check the static pod status with:" >&2
            echo "  kubectl -n kube-system get pods -l component=kube-apiserver" >&2
            exit 1
          }

          local ps_out
          ps_out="$(/bin/ps -ef | grep kube-apiserver | grep -v grep)"

          echo "$ps_out" | grep -q -- "--audit-policy-file=${AUDIT_POLICY_FILE}" || {
            echo "ERROR: --audit-policy-file flag not active on kube-apiserver process." >&2
            echo "Current kube-apiserver command line:" >&2
            echo "$ps_out" >&2
            exit 1
          }

          echo "$ps_out" | grep -q -- "--audit-log-path=${AUDIT_LOG_FILE}" || {
            echo "ERROR: --audit-log-path flag not active on kube-apiserver process." >&2
            echo "Current kube-apiserver command line:" >&2
            echo "$ps_out" >&2
            exit 1
          }

          echo "Verification successful: kube-apiserver is running with audit policy and log path configured."
        }

        main() {
          require_root
          check_files_exist
          ensure_audit_policy_file
          ensure_audit_log_path
          ensure_audit_flags
          restart_notice
          verify
        }

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