Runtime Security and Threat Detection for Containers
Every control up to this point is preventive: minimal images, signed provenance, admission gates, tight RBAC and network policy. They shrink the ways an attack can start. None of them tell you that a container which passed every check is, right now, spawning a shell and connecting to an unfamiliar IP. Runtime security is the detective layer — watching live container behaviour for the signs that prevention failed, because eventually some of it will.
Containers are, on paper, ideal for behavioural detection precisely because they are meant to be predictable. A given microservice runs the same handful of processes, opens the same ports, reads the same files, and talks to the same services on every replica. Deviation from that tight baseline is a far stronger signal than it would be on a general-purpose host — a container is supposed to be boring, so an interactive shell inside one is inherently suspicious.
Why eBPF changed the game
Modern container runtime security is built on eBPF — a facility for running sandboxed programs inside the Linux kernel, safely and without kernel modules. eBPF lets a sensor observe syscalls, process execution, file access, and network connections across every container on a node from a single vantage point in the kernel, with low overhead and no changes to the workloads. It is the technology under most of the current tooling: Falco (a CNCF project) can use an eBPF probe, and Tetragon and Tracee are eBPF-native. The payoff is deep, host-wide visibility that a sidecar-per-pod model cannot match.
What to actually alert on
- A shell in a container that should have none.
execof/bin/shor/bin/bashin a production app pod is the canonical post-exploitation move — and impossible in a distroless image, which is part of why you built one. - Unexpected outbound connections. A pod reaching an IP or domain outside its known dependency set — possible exfiltration or C2.
- Writes to unexpected paths. Modifying binaries, dropping files into
/tmpand executing them, or touching the container runtime socket. - Privilege-escalation and escape attempts. Unexpected
setuidcalls, mounts, or capability changes at runtime. - Container drift. A process running that was never in the image — a strong indicator that something was fetched and executed after start.
- Sensitive file access. Reads of
/etc/shadow, service-account tokens, or cloud credential paths that the app has no reason to touch.
condition: spawned_process and container and proc.name in (bash, sh, zsh)
output: "Shell spawned in container (pod=%k8s.pod.name cmd=%proc.cmdline)"
priority: WARNING
From detection to response
An alert nobody acts on is telemetry, not security. The value of runtime detection is realised only when signals route into your SOC workflow — enriched with Kubernetes context (which pod, namespace, node, image, and owning team) so a responder can act without a scavenger hunt. More advanced setups add response: eBPF frameworks like Tetragon can enforce as well as observe, killing a process or blocking a syscall inline, and orchestration can automatically cordon a node or delete a pod exhibiting escape behaviour. Enforcement demands confidence in your rules — an over-eager kill action is its own outage — so most teams start in detect-only and graduate specific, high-fidelity rules to enforcement.
Tuning is the whole job
Out-of-the-box rulesets are noisy, and an ignored alert stream is worse than none because it manufactures false confidence. The work is baselining each workload's normal behaviour, suppressing benign deviations, and reserving alerts for genuinely anomalous activity. Done well, runtime security is the layer that turns 'we assume we'll be breached' from a slogan into a capability.
Its blind spot is the same one as everything else: a runtime sensor only watches the nodes and clusters it is deployed on. A workload running somewhere your eBPF probes are not is an intrusion you will never see coming — you can't detect a breach in an environment you haven't discovered.
- Ask whether a runtime sensor (Falco, Tetragon, Tracee or equivalent) is actually running on every node, or only some — the uncovered node is the blind spot.
- Pick a rule you assume exists, like "shell in a prod container", and confirm it would genuinely fire rather than trusting the default ruleset to cover it.
Confirming coverage on paper is one thing; validating detection end to end and finding the nodes no probe watches is what our assessment runs for you.