Back

K05: Inadequate Logging and Monitoring - Prevention

Prevention Strategy Overview

Preventing K05 means building a cluster that records what matters, ships it somewhere durable, and turns high-risk events into alerts a human receives. Think of it as four layers stacked on top of each other—each is necessary and none is sufficient alone:

  1. Capture the signal: API-server audit, runtime, workload, node, and cloud telemetry.
  2. Centralise it off-cluster in tamper-resistant storage with retention.
  3. Detect: alert on the specific events that indicate compromise.
  4. Respond: wire alerts into an incident-response process.

Core Principles

1. Enable API-Server Audit Logging with a Sound Policy

The API audit log is the single richest security signal in Kubernetes. Enable it with a tiered policy: cheap Metadata for routine traffic, full RequestResponse for sensitive verbs, and None for high-volume noise.

# audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
omitStages: ["RequestReceived"]
rules:
  # Full request+response for the crown-jewel resources
  - level: RequestResponse
    resources:
      - group: ""
        resources: ["secrets", "configmaps", "serviceaccounts"]
      - group: "rbac.authorization.k8s.io"
        resources: ["roles", "rolebindings", "clusterroles", "clusterrolebindings"]
  # Record exec / attach / port-forward into pods in full
  - level: RequestResponse
    resources:
      - group: ""
        resources: ["pods/exec", "pods/attach", "pods/portforward"]
  # Drop noisy, low-value reads to control cost
  - level: None
    users: ["system:kube-scheduler", "system:kube-proxy"]
    verbs: ["watch", "get"]
  - level: None
    resources:
      - group: ""
        resources: ["events"]
  # Everything else: metadata is cheap and still valuable
  - level: Metadata
# Wire the policy into kube-apiserver (self-managed clusters)
kube-apiserver \
  --audit-policy-file=/etc/kubernetes/audit-policy.yaml \
  --audit-log-path=/var/log/kubernetes/audit.log \
  --audit-log-maxage=30 \
  --audit-log-maxbackup=10 \
  --audit-log-maxsize=100
# Managed clusters: enable the provider's audit/control-plane logging
# and forward it to your log sink (this is off or minimal by default).

On managed control planes you cannot pass apiserver flags directly—enable the provider's audit-logging feature and export it to your logging service or SIEM. It is frequently disabled by default.

2. Deploy Runtime Threat Detection (Falco / Tetragon)

API audit tells you what was asked of the control plane; a runtime sensor tells you what actually executed inside containers and on nodes. Deploy one as a DaemonSet on every node.

# Install Falco cluster-wide (Helm)
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm install falco falcosecurity/falco \
  --namespace falco --create-namespace \
  --set falcosidekick.enabled=true \
  --set falcosidekick.config.slack.webhookurl=$SLACK_WEBHOOK

Runtime rules should cover, at minimum: a shell spawned in a container, writes to sensitive paths, reads of the service-account token by unexpected processes, sensitive host mounts, and outbound connections to unexpected destinations. (See the Examples page for concrete rules.)

3. Centralise Logs Off-Cluster (Tamper-Resistant)

Ship every source—audit log, runtime events, pod stdout/stderr, node logs—off the cluster in real time to storage the cluster's own identities cannot modify.

# Fluent Bit DaemonSet: tail node-local logs and forward to a sink
[INPUT]
    Name              tail
    Path              /var/log/containers/*.log
    Tag               kube.*
    Refresh_Interval  5

[INPUT]
    Name              tail
    Path              /var/log/kubernetes/audit.log
    Tag               audit.*

[FILTER]
    Name                kubernetes
    Match               kube.*
    Merge_Log           On

[OUTPUT]
    Name   es                 # or loki, splunk, http -> your SIEM
    Match  *
    Host   logs.internal.example
    Port   9200
    tls    On
    Retry_Limit  5

Hardening rules for the pipeline:

4. Alert on High-Risk Events

Collection is inert without alerting. Define rules that page a human on the events that indicate compromise.

EventSourceWhy alert
exec/attach into a prod podAPI auditInteractive access is rare and high-risk
Create pod with privileged/hostPID/hostPathAPI audit / admissionEscape primitive
New binding granting cluster-adminAPI audit (RBAC)Privilege escalation
Bulk get/list secrets by one identityAPI auditCredential harvesting
Image pulled from non-allow-listed registryRuntime / eventsMalware / miner delivery
Shell or package manager run in a containerRuntime (Falco)Post-exploitation
Requests from system:anonymousAPI auditUnauthenticated probing
# Prometheus Alertmanager rule (fed by a metrics exporter over audit/runtime)
groups:
- name: k8s-security
  rules:
  - alert: PrivilegedPodCreated
    expr: increase(k8s_audit_privileged_pod_created_total[5m]) > 0
    labels: { severity: critical }
    annotations:
      summary: "Privileged pod created in {{ $labels.namespace }}"
  - alert: ClusterAdminBindingCreated
    expr: increase(k8s_audit_clusteradmin_binding_total[5m]) > 0
    labels: { severity: critical }
  - alert: ExecIntoProdPod
    expr: increase(k8s_audit_pod_exec_total{namespace="prod"}[5m]) > 0
    labels: { severity: high }

5. Monitor for Cryptomining and Anomalies

6. Collect the Cloud Control-Plane and Node Trail

The cluster is only half the picture. Forward the cloud provider's audit trail (managed control-plane logs, IAM activity, node metadata access) into the same SIEM so cross-plane pivots can be correlated.

7. Ensure Retention, Integrity, and Time Synchronisation

# Every node runs NTP/chrony so events order correctly across sources
timedatectl set-ntp true
chronyc tracking      # verify offset is small and stable

8. Integrate With Incident Response

Telemetry exists to drive action. Close the loop:

Defence Coverage Matrix

Attacker activityPrimary controlBackstop control
Exec into podAudit alert on pods/execFalco shell-in-container rule
Privileged podAudit/admission alertRuntime sensitive-mount rule
Secret harvestingAudit RequestResponse on secretsPer-identity anomaly alert
Container escapeFalco/Tetragon syscall ruleNode log + cloud audit
CryptominerRegistry allow-list alertEgress + CPU baseline
Evidence deletionOff-cluster append-only sinkAudit of delete calls

Key Takeaways

  1. Enable API audit with a tiered policy — metadata everywhere, full request/response for exec, secrets, and RBAC.
  2. Add a runtime sensor — Falco/Tetragon on every node is the only view into in-container and on-node activity.
  3. Centralise off-cluster, tamper-resistant, with retention — evidence must outlive the pod and survive a node compromise.
  4. Alert, don't just collect — wire high-risk events to paging and a runbook.
  5. Correlate and rehearse — sync clocks, pull in the cloud trail, and prove the pipeline before you need it.

Next Steps