Skip to main content

Ensure Audit Logs Are Collected And Managed

More Info:

Define an audit policy and forward audit logs to a centralized logging system such as CloudWatch or Elasticsearch. Without collection and management, audit records cannot be retained or reviewed.

Risk Level

High

Address

Security

Compliance Standards

  • CIS EKS

Triage and Remediation

Remediation

Manual Steps
  1. Verify EKS control plane audit logging is enabled and scoped correctly

    • On any admin machine with AWS CLI access, list EKS clusters and describe the target cluster:
      aws eks list-clusters
      aws eks describe-cluster --name <CLUSTER_NAME> --query "cluster.logging"
    • Confirm cluster.logging.clusterLogging has types including "api", "audit" (or "all" types, depending on region support) with "enabled": true and that logs are being sent to CloudWatch.
  2. Confirm audit policy configuration exists and matches organizational requirements

    • On any machine with kubectl access, check for an audit policy ConfigMap or file (common patterns):
      kubectl get configmap -n kube-system | grep -i audit
      kubectl get configmap cluster-audit-policy -n kube-system -o yaml
    • Compare the contents against the required policy (e.g., at minimum capturing Metadata for pods and other critical resources), and have security/operations sign off that scope, retention, and sensitivity are appropriate.
  3. Check that audit logs are being generated and delivered to CloudWatch

    • On any admin machine with AWS CLI access, identify the CloudWatch log groups associated with the cluster:
      aws logs describe-log-groups --log-group-name-prefix "/aws/eks/"
    • Inspect a sample of recent audit log events:
      aws logs describe-log-streams \
      --log-group-name "/aws/eks/<CLUSTER_NAME>/cluster" \
      --order-by LastEventTime --descending --limit 5

      aws logs get-log-events \
      --log-group-name "/aws/eks/<CLUSTER_NAME>/cluster" \
      --log-stream-name "<LOG_STREAM_NAME_FROM_ABOVE>" \
      --limit 20
    • Confirm that Kubernetes API calls (create/update/delete, authN/Z events, etc.) are present and timestamps are recent.
  4. Validate forwarding to any additional centralized logging/SIEM system

    • If you use a log forwarder (e.g., Fluent Bit/Fluentd/Vector/Custom):
      kubectl get pods -n kube-system | egrep -i 'fluent|vector|log|audit'
      kubectl logs <POD_NAME> -n kube-system --tail=100
    • Confirm configuration forwards CloudWatch (or node-level audit logs, if used) to the designated backend (Elasticsearch, OpenSearch, Splunk, etc.) and that events from this cluster are visible there (verify by querying on a known pod/namespace/user and recent timestamp).
  5. Review retention, access control, and integrity protections for audit logs

    • On any admin machine with AWS CLI access, verify CloudWatch retention and access:
      aws logs describe-log-groups \
      --log-group-name-prefix "/aws/eks/<CLUSTER_NAME>/cluster" \
      --query "logGroups[].{name:logGroupName,retentionInDays:retentionInDays}"
    • Confirm retention meets policy (e.g., 90/180/365 days), that IAM policies on the log group restrict write/delete/reader access appropriately, and that any downstream system (e.g., S3 archive, SIEM) also meets retention and integrity requirements.
  6. If gaps are found, update configuration and re‑verify

    • Enable/adjust EKS control plane logging (via console, aws eks update-cluster-config, or IaC) to include the required log types and CloudWatch destination.
    • Update the audit policy ConfigMap or backing IaC to meet your logging scope, then redeploy.
    • Re-run the commands from steps 1–3 to confirm that audit logs are enabled, correctly scoped, delivered to CloudWatch, and visible in your central logging solution.
Using kubectl

kubectl cannot configure EKS control plane audit logging or host-level audit settings on control plane nodes; these are managed via the cloud provider console/CLI/IaC and node-level configuration. Refer to the Manual Steps section for how to review and configure audit policies and centralized log forwarding.

Automation
#!/usr/bin/env bash
# Purpose: Report EKS control plane audit logging configuration and
# basic in-cluster audit log forwarding setup.
# Runs on: any machine with kubectl access and AWS CLI configured.

set -euo pipefail

echo "=== 1. EKS CONTROL PLANE AUDIT LOGGING (CLOUDTRAIL / CLOUDWATCH) ==="

# List all clusters and show which have audit logging enabled
aws eks list-clusters --output text | awk '{print $2}' | while read -r CLUSTER; do
if [ -z "$CLUSTER" ]; then
continue
fi
echo "Cluster: $CLUSTER"
aws eks describe-cluster --name "$CLUSTER" \
--query 'cluster.logging.clusterLogging[?types!=`[]`]' \
--output table || echo " ERROR: unable to describe cluster $CLUSTER"

echo
done

cat <<'EOF'

Interpretation (control plane logging):
- Problem indicators:
- No entry where "types" contains "audit".
- "enabled" is false for the logging entry that includes "audit".
- Healthy indicators:
- At least one entry with "types" containing "audit" and "enabled" = true.

NOTE: Enabling EKS control plane audit logging is done via AWS console/CLI/IaC,
not via kubectl or node-level changes.

EOF

echo "=== 2. IN-CLUSTER AUDIT POLICY CONFIGMAP (kube-system) ==="

# Check for a commonly used audit policy ConfigMap name
CM_NAMES=("cluster-audit-policy" "audit-policy" "kube-audit-policy")

for CM in "${CM_NAMES[@]}"; do
echo "Checking for ConfigMap: $CM in kube-system..."
if kubectl get configmap "$CM" -n kube-system >/dev/null 2>&1; then
echo " FOUND: $CM"
echo " --- audit-policy.yaml from $CM ---"
kubectl get configmap "$CM" -n kube-system -o jsonpath='{.data.audit-policy\.yaml}' 2>/dev/null \
|| echo " WARN: ConfigMap exists but does not contain key 'audit-policy.yaml'"
echo
else
echo " MISSING: $CM"
fi
echo
done

cat <<'EOF'

Interpretation (policy ConfigMap):
- Problem indicators:
- No ConfigMap found that contains an audit policy (e.g. cluster-audit-policy).
- ConfigMap exists but has no 'audit-policy.yaml' key or is effectively empty.
- Healthy indicators:
- A ConfigMap exists with an 'audit-policy.yaml' key containing a non-trivial
policy (appropriate levels and resources as per your org standard).

EOF

echo "=== 3. IN-CLUSTER AUDIT LOG FORWARDER PODS (kube-system) ==="

# Look for pods that appear to forward audit logs (by name or label)
echo "Pods in kube-system potentially related to audit log forwarding:"
kubectl get pods -n kube-system -o wide | egrep -i 'audit|log|forward|fluent|filebeat|logstash' || \
echo " No obvious audit/log forwarder pods detected by name pattern."

echo
echo "Checking for example 'audit-logging' pod from benchmark remediation:"
kubectl get pod audit-logging -n kube-system -o yaml 2>/dev/null || \
echo " Pod 'audit-logging' not found in kube-system."

cat <<'EOF'

Interpretation (forwarder pods):
- Problem indicators:
- No pods in kube-system with names suggesting log forwarding
(e.g., fluentd, fluent-bit, filebeat, log-forwarder, audit-logging).
- The 'audit-logging' pod (if used) is missing or not Running/Ready.
- Healthy indicators:
- A dedicated log forwarder DaemonSet/Deployment is present and Running,
and is known (by your ops standards) to ship audit logs to a central
system (CloudWatch, Elasticsearch, etc.).

EOF

echo "=== 4. NODE-LEVEL INSPECTION (KUBELET / APISERVER AUDIT FLAGS) ==="
cat <<'EOF'

This part cannot be automated cluster-wide with kubectl alone because:
- EKS control plane is managed; you cannot inspect API server flags via nodes.
- Worker nodes usually do not run the control plane and have no direct access
to control plane audit logs.

Manual checks to perform on each control plane node (for non-managed clusters):
- Verify that the API server is started with:
--audit-policy-file=</path/to/audit-policy.yaml>
--audit-log-path=</path/to/audit.log>
--audit-log-maxage / --audit-log-maxbackup / --audit-log-maxsize set properly.
- Confirm audit log files exist and are being written.
- Confirm your node or sidecar agents (e.g., Fluent Bit, Filebeat) are
configured to ship these audit logs to your centralized logging system.

EOF