Container and Kubernetes detection

The detection surface for containers and Kubernetes splits between runtime signals inside the pod and control plane signals in the API server audit log. Both are necessary. An attacker who exploits a pod but makes no API calls appears only in runtime telemetry. An attacker moving through the API server using a stolen service account token may produce no runtime anomalies at all.

Kubernetes audit log

The API server generates an audit log entry for every API request, recording the verb, resource, requesting principal, namespace, source IP, and optionally the request and response objects. The audit policy controls which events are logged and at what detail level; a minimal policy logs metadata for most verbs and full request objects for sensitive operations.

Events worth alerting on:

Privileged pod creation: a create request on the pods resource where the request object contains securityContext.privileged: true, hostPID: true, hostNetwork: true, or hostIPC: true. These are rare in production workloads and common in container escape attempts.

Pod exec: a create request on the pods/exec subresource. Legitimate uses include debugging and one-off administrative commands. High-frequency exec events, exec into production pods from non-CI service accounts, or exec from unexpected source IPs are anomalous.

RBAC escalation: create or patch requests on clusterrolebindings or rolebindings, particularly binding a subject to a high-privilege role. Modification of clusterroles to add wildcard permissions is a related signal.

Secret enumeration: list or get requests on secrets from a service account that normally has no reason to access secrets, particularly from an application namespace.

Service account token creation: create requests on serviceaccounts/token outside expected CI or operator contexts.

A useful audit policy excerpt for sensitive operations:

rules:
  - level: RequestResponse
    verbs: ["create", "update", "patch", "delete"]
    resources:
      - group: "rbac.authorization.k8s.io"
        resources: ["clusterrolebindings", "rolebindings", "clusterroles", "roles"]
  - level: Request
    verbs: ["create"]
    resources:
      - group: ""
        resources: ["pods"]
        subresources: ["exec", "portforward"]
      - group: ""
        resources: ["serviceaccounts"]
        subresources: ["token"]
  - level: Metadata
    verbs: ["list", "get", "watch"]
    resources:
      - group: ""
        resources: ["secrets"]

Runtime signals

eBPF-based instrumentation (Falco, Tracee, Tetragon) captures syscall events from all processes on the host, including containerised ones, with container context attached. This layer is container-runtime-agnostic: it works regardless of whether an agent is installed inside the container.

Shell spawns inside containers that have no legitimate use for a shell are a reliable high-signal indicator. The baseline for each image determines what is expected. A Python web application that never runs bash or sh produces a shell spawn event only when something unexpected is happening. The Falco rule structure for shell spawn detection is covered in evasion/notes/containers.md; the detection value is in establishing per-image baselines rather than a single cluster-wide rule.

The memfd_create syscall creates an anonymous in-memory file not backed by the filesystem. Combined with execveat, it allows payload execution without writing to disk. Application containers have few legitimate uses for memfd_create. An explicit Falco rule for this syscall in container context catches fileless execution attempts that process-based rules miss.

ptrace from an unexpected process inside a container indicates memory inspection or injection. Legitimate uses are confined to debuggers; application containers running in production have no reason to call ptrace.

Writes to sensitive paths (/etc/passwd, /etc/shadow, /etc/sudoers, /root/.ssh/*, /proc/sys/*) inside a container have few legitimate uses in a production image. When combined with readOnlyRootFilesystem: true, such writes fail at the kernel level and produce a denial event; on containers without that setting, they succeed silently unless a runtime rule fires.

Package manager execution (apt, yum, apk, pip, npm) inside a running container suggests tool installation. Immutable container images do not run package managers after build. Falco rules for this pattern are covered in evasion/notes/containers.md.

Unexpected outbound connections

Network policy violation logs from Calico or Cilium record dropped outbound connections from pods that are subject to egress restrictions. Even in the absence of egress restrictions, outbound connections to external IPs on uncommon ports from database or internal-service pods are anomalous and worth correlating with runtime events from the same container.

An outbound connection to port 443 from a pod that has never made external connections, occurring within minutes of a shell spawn or sensitive file access in the same container, is a strong combined indicator.

Image pull monitoring

Admission webhook logs record every attempted pod creation including image references. Pulls from registries outside the approved list appear at admission time. At the runtime level, container runtime logs record image pull operations; a pull from an unexpected registry outside of a deployment event may indicate direct API server access by an attacker creating a pod without going through normal deployment tooling.

Image pull events from an unexpected registry alongside ClusterRoleBinding creation from the same service account within a short time window is the signal for automated control plane lateral movement.

Correlating layers

The highest-confidence container compromise indicators combine runtime and control plane signals. A shell spawn inside an application pod followed by Kubernetes API calls from that pod’s service account, followed by a new ClusterRoleBinding created by that same service account, is a clear escalation chain. Neither the shell spawn alone nor the API calls alone are definitive; the sequence across both layers is.

Correlating Kubernetes audit log events with Falco events requires a shared identifier. The pod name and namespace appear in both; a SIEM or log aggregator that joins on these fields across the two log sources makes the correlation practical.