> ## 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 The Audit Policy Covers Key Security Concerns

### More Info:

Ensure that the audit policy created for the cluster covers key security concerns.

### Risk Level

High

### Address

Security

### Compliance Standards

* CIS GKE

### Triage and Remediation

<Tabs>
  <Tab title="Remediation">
    ### Remediation

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. **Identify cluster type and constraints**
           * On any machine with `gcloud` access, confirm this is a GKE cluster and note its mode (standard vs autopilot), as GKE manages the API server:
             ```bash theme={null}
             gcloud container clusters list
             gcloud container clusters describe CLUSTER_NAME --zone=CLUSTER_ZONE \
               --format="value(name,location,releaseChannel.channel,loggingConfig)"
             ```

        2. **Review current GKE audit/logging configuration**
           * On any machine with `gcloud` access, check which control-plane logs are enabled (these are GKE’s effective “audit surfaces”):
             ```bash theme={null}
             gcloud container clusters describe CLUSTER_NAME --zone=CLUSTER_ZONE \
               --format="yaml(loggingConfig,monitoringConfig)"
             ```
           * Confirm that at least **API server audit logs** / **control plane logs** are enabled (names and options vary by GKE version; look for entries under `loggingConfig.componentConfig.enableComponents` such as `APISERVER`, `AUDIT`, or `CONTROLPLANE`).

        3. **Review log sink and retention settings**
           * On any machine with `gcloud` access, determine where logs go and for how long, as this impacts audit usefulness:
             ```bash theme={null}
             # List sinks that may capture GKE control plane logs
             gcloud logging sinks list

             # Show retention for the main logging bucket
             gcloud logging buckets list --location=global
             gcloud logging buckets describe _Default --location=global
             ```
           * Verify logs are retained for a period that meets your policy (e.g., 90–365 days) and that sinks route them to an appropriate SIEM or storage location if required.

        4. **Sample current audit-related events for key security concerns**
           * On any machine with `gcloud` access, query Cloud Logging for recent events that reflect key security concerns, such as:
             * Authentication/authorization failures
             * Changes to `ClusterRole`, `Role`, `RoleBinding`, `ClusterRoleBinding`
             * Changes to `Namespace`, `NetworkPolicy`, `PodSecurityPolicy`/equivalent, `Pod`, `ServiceAccount`, `Secret`
           * Example queries:
             ```bash theme={null}
             # Any failed API calls
             gcloud logging read \
               'resource.type="k8s_cluster" severity>=WARNING 
                protoPayload.status.code!=""' \
               --limit=20 --format="table(timestamp,protoPayload.methodName,protoPayload.status.code)"

             # Changes to RBAC objects
             gcloud logging read \
               'resource.type="k8s_cluster" 
                protoPayload.methodName=~"io.k8s.authorization.rbac.v1.(Role|ClusterRole|RoleBinding|ClusterRoleBinding).*"' \
               --limit=20 --format="table(timestamp,protoPayload.authenticationInfo.principalEmail,protoPayload.methodName)"
             ```
           * Adjust filters in the Cloud Console Logs Explorer to visually verify that such actions are being logged.

        5. **Compare observed logging coverage with your security requirements**
           * Using your organization’s policies, confirm that the available GKE audit/control-plane logs:
             * Capture administrative actions on critical resources (RBAC, namespaces, network/security policies, workloads, service accounts, secrets).
             * Include enough context (actor, source IP, target object, verb, timestamp) to support incident response and forensics.
             * Are reliably exported and retained per policy.
           * If gaps exist that cannot be closed due to GKE’s managed nature (for example, you cannot customize the underlying `/etc/kubernetes/manifests/kube-apiserver.yaml` or audit policy file), document the residual risk and any compensating controls (e.g., higher-level IAM logging, workload-level audit, admission webhooks, or service mesh logs).

        6. **Decide and document compliance status**
           * If GKE’s built-in control-plane logging and your sinks/retention meet your documented requirements for “key security concerns,” record this control as **“Covered by managed GKE audit/control plane logging; configuration not directly modifiable”** and keep evidence from steps 2–4.
           * If requirements are not met and cannot be met within GKE’s constraints, mark the control as **accepted risk/partially compliant**, attach the evidence and rationale, and define any additional monitoring or architectural changes (e.g., moving to a more configurable environment) needed to close the gap.
      </Accordion>

      <Accordion title="Using kubectl">
        kubectl cannot be used to configure or modify the API server audit policy for this control, because it is defined via the control plane’s host-level configuration in `/etc/kubernetes/manifests/kube-apiserver.yaml` (and, in GKE, is not user-modifiable). Please refer to the Manual Steps section for guidance on how to review this setting and what decisions are required.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Purpose:
        #   Summarize GKE audit logging coverage across all clusters/contexts
        #   to help review whether key security concerns are being audited.
        #
        # Requirements:
        #   - gcloud installed and authenticated (for cluster discovery)
        #   - kubectl installed
        #   - Sufficient IAM to list clusters and use their kubeconfigs
        #
        # Notes:
        #   - In GKE, the audit policy itself is not editable.
        #   - This script does NOT fix anything; it collects evidence to review.
        #

        set -euo pipefail

        ############################################################
        # Helper: print a section header
        ############################################################
        section() {
          echo
          echo "==================== $* ===================="
        }

        ############################################################
        # 1. List GKE clusters and their logging/audit configuration
        ############################################################
        section "GKE CLUSTERS AND LOGGING / AUDIT SETTINGS"

        # Change this if you want to scope to specific project(s)/regions.
        PROJECTS=$(gcloud projects list --format='value(projectId)')

        for PROJECT in $PROJECTS; do
          echo "Project: $PROJECT"

          CLUSTERS=$(gcloud container clusters list \
            --project "$PROJECT" \
            --format='value(name,location)')

          if [ -z "$CLUSTERS" ]; then
            echo "  No clusters found."
            continue
          fi

          # Header
          printf "  %-30s %-15s %-10s %-15s %-20s\n" \
            "CLUSTER" "LOCATION" "VERSION" "MASTER_LOGS" "WORKLOAD_LOGGING"
          printf "  %-30s %-15s %-10s %-15s %-20s\n" \
            "-------" "--------" "-------" "-----------" "----------------"

          while read -r NAME LOCATION; do
            # Fetch cluster details in JSON
            INFO=$(gcloud container clusters describe "$NAME" \
              --project "$PROJECT" \
              --region "$LOCATION" 2>/dev/null || \
              gcloud container clusters describe "$NAME" \
                --project "$PROJECT" \
                --zone "$LOCATION" 2>/dev/null || true)

            if [ -z "$INFO" ]; then
              printf "  %-30s %-15s %-10s %-15s %-20s\n" "$NAME" "$LOCATION" "N/A" "N/A" "N/A"
              continue
            fi

            VERSION=$(echo "$INFO" | yq '.currentMasterVersion // .currentMasterVersion' 2>/dev/null || echo "N/A")

            # Master (control plane) logging – relevant for API server audit visibility
            MASTER_LOGGING=$(echo "$INFO" | yq '.loggingService // .loggingConfig.componentConfig.enableComponents[]? // ""' 2>/dev/null || echo "")
            if echo "$MASTER_LOGGING" | grep -qi "none"; then
              MASTER_STATUS="DISABLED"
            else
              MASTER_STATUS="ENABLED"
            fi

            # Workload logging mode
            WORKLOAD_LOGGING=$(echo "$INFO" | yq '.loggingConfig.componentConfig.enableComponents[]? // .loggingConfig // ""' 2>/dev/null || echo "")

            printf "  %-30s %-15s %-10s %-15s %-20s\n" \
              "$NAME" "$LOCATION" "$VERSION" "$MASTER_STATUS" "${WORKLOAD_LOGGING:0:18}"
          done <<< "$CLUSTERS"
        done

        ############################################################
        # 2. Per-cluster: verify Audit / API logs presence in Cloud Logging
        ############################################################
        section "CLOUD LOGGING: API / AUDIT LOG SINK PRESENCE (SAMPLE CHECK)"

        # Adjust time range as needed for your environment
        TIME_RANGE='timestamp >= "'$(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ)'"'

        for PROJECT in $PROJECTS; do
          echo "Project: $PROJECT"

          # Check for ADMIN_READ / DATA_WRITE / DATA_READ audit logs for Kubernetes API
          # This is a heuristic: presence shows that GKE audit/API logs are reaching Cloud Logging.
          for LOG_TYPE in "ADMIN_READ" "DATA_WRITE" "DATA_READ"; do
            echo "  Checking presence of Kubernetes audit-like entries: logType=$LOG_TYPE (last 1h)"

            COUNT=$(gcloud logging read \
              "logName:\"cloudaudit.googleapis.com\" \
               protoPayload.serviceName=\"kubernetes.io\" \
               protoPayload.methodName:\"\" \
               protoPayload.authenticationInfo.principalEmail!=\"\" \
               protoPayload.@type=\"type.googleapis.com/google.cloud.audit.AuditLog\" \
               protoPayload.methodName!=\"io.k8s.core.v1.Event\" \
               protoPayload.metadata.\"@type\"!=\"type.googleapis.com/google.cloud.audit.AuditLog\" \
               protoPayload.metadata=\"\" \
               protoPayload.requestMetadata.callerIp!=\"\" \
               protoPayload.metadata.severity!=\"DEBUG\" \
               protoPayload.metadata.log_type=\"$LOG_TYPE\" \
               $TIME_RANGE" \
              --project="$PROJECT" \
              --format='value(insertId)' \
              --limit=1 2>/dev/null | wc -l | tr -d ' ')

            if [ "$COUNT" -gt 0 ]; then
              echo "    FOUND sample entries for logType=$LOG_TYPE"
            else
              echo "    NOT FOUND sample entries for logType=$LOG_TYPE  <-- REVIEW"
            fi
          done
        done

        ############################################################
        # 3. Per-cluster API server flags snapshot (where visible via /configz)
        #    Run from the active kubectl context only.
        ############################################################
        section "KUBE-APISERVER AUDIT-RELATED FLAGS (CURRENT KUBECTL CONTEXT)"

        # This requires that the current context points at a GKE cluster,
        # and that the /configz endpoint is reachable/authorized.
        set +e
        API_CONFIGZ=$(kubectl get --raw /configz 2>/dev/null)
        if [ $? -ne 0 ] || [ -z "$API_CONFIGZ" ]; then
          echo "Unable to query /configz via kubectl. This is expected on many GKE clusters."
          echo "Use Cloud Logging views and IAM audit logs for evaluation."
          exit 0
        fi
        set -e

        echo "Extracting kube-apiserver audit-related flags from /configz:"
        echo "$API_CONFIGZ" | jq -r '
          .kubeAPIServerConfig | [
            .auditLogPath,
            .auditPolicyFile,
            .auditWebhookConfigFile,
            .auditLogMaxAge,
            .auditLogMaxBackup,
            .auditLogMaxSize,
            .auditWebhookMode,
            .auditBatchMaxSize,
            .auditBatchMaxWait,
            .auditBatchThrottleBurst,
            .auditBatchThrottleEnable,
            .auditBatchThrottleQPS
          ] | {
            auditLogPath: .[0],
            auditPolicyFile: .[1],
            auditWebhookConfigFile: .[2],
            auditLogMaxAge: .[3],
            auditLogMaxBackup: .[4],
            auditLogMaxSize: .[5],
            auditWebhookMode: .[6],
            auditBatchMaxSize: .[7],
            auditBatchMaxWait: .[8],
            auditBatchThrottleBurst: .[9],
            auditBatchThrottleEnable: .[10],
            auditBatchThrottleQPS: .[11]
          }' 2>/dev/null || echo "Could not parse kubeAPIServerConfig from /configz"

        echo
        echo "Review Guidance:"
        echo "  - In GKE, audit policy is managed by the platform and not user-editable."
        echo "  - Use the sections above to verify that:"
        echo "      * Control plane (master) logging is ENABLED."
        echo "      * Kubernetes API / audit logs (ADMIN_READ / DATA_WRITE / DATA_READ)"
        echo "        are present in Cloud Logging for your project(s)."
        echo "  - If master logging is DISABLED or relevant audit logs are NOT FOUND,"
        echo "    this indicates a potential gap in audit coverage that must be evaluated"
        echo "    against your organization’s logging and compliance requirements."
        ```

        **How to interpret the output**

        * Problems that need review:
          * Any cluster where `MASTER_LOGS` shows `DISABLED`.
          * Any project where `NOT FOUND` appears for `ADMIN_READ`, `DATA_WRITE`, or `DATA_READ` in the last hour (may indicate missing or misrouted audit/API logs, or simply no activity).
        * Because this control is MANUAL and GKE’s audit policy is not user-modifiable, these outputs are evidence for a human review, not an automatic pass/fail decision.
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>

### Additional Reading:

* [https://github.com/k8scop/k8s-security-dashboard/blob/master/configs/kubernetes/adv-audit.yaml](https://github.com/k8scop/k8s-security-dashboard/blob/master/configs/kubernetes/adv-audit.yaml)
