eBPF Runtime Security: Catching Container Attacks Your Cloud Logs Can't See

CloudTrail and identity logs won't catch a reverse shell inside a container. Here's how open-source eBPF tooling gives you real-time runtime visibility, and how to feed it into your detection pipeline.

Your control-plane logs tell you who called an API. They tell you nothing about what happened inside the process that API call started.

The blind spot in cloud-native security logging

Most SIEM programs are built almost entirely on control-plane telemetry: cloud audit logs, identity provider events, load balancer access logs. That data answers “who did what to which resource.” It does not answer “what is running inside my containers right now.”

An attacker who gets remote code execution in a workload — through a vulnerable dependency, a misconfigured job, or a compromised CI pipeline — doesn’t need to touch the cloud API at all to do damage. They can read environment variables, scrape a mounted credential file, spawn a shell, or reach out to a command-and-control server, and none of it shows up in CloudTrail-style audit logs. By the time that activity produces an API call worth alerting on (assuming a stolen credential is even used), the attacker has already had the run of the container.

This is the gap runtime security closes: instrumenting the kernel itself so you see process execution, file access, and network activity as they happen, independent of what any application chooses to log.

Why eBPF changed what’s practical here

Kernel-level visibility used to mean a kernel module: custom C code running in kernel space, one crash away from taking down the host, and rebuilt for every kernel version you supported. That tradeoff kept most teams out of runtime monitoring entirely.

eBPF (extended Berkeley Packet Filter) changes the economics. It lets you run small, verified programs inside the kernel — attached to syscalls, network events, or scheduler hooks — without writing a kernel module. The in-kernel verifier rejects anything that could crash or hang the kernel before it loads, and the programs are portable across kernel versions far more easily than a compiled module ever was. That’s why eBPF has become the foundation for a wave of open-source runtime security tools over the last few years, and why it’s now practical for teams well outside the hyperscalers to run.

The open-source landscape

ToolWhat it’s good atMaturity
FalcoReal-time rule-based detection on syscalls (CNCF graduated project)Production-ready, large rule community
TetragoneBPF-based enforcement + observability, can block not just alertProduction-ready, tighter Kubernetes integration
TraceeSyscall tracing with a built-in signature engine, lighter footprintActively developed, smaller community

All three ship a default rule set covering common attacker behavior — shell spawned in a container, write to a sensitive path like /etc/shadow, outbound connection from an unexpected binary. Start with the defaults. Tune from there.

How to instrument a cluster: a walkthrough

The example below uses Falco’s rule syntax because it’s the most widely deployed, but the concepts (a rule against a stream of kernel events, tagged with process, container, and network context) apply to any of the three tools.

Step 1 — Deploy the agent. All three run as a DaemonSet, one instance per node, reading events directly from the kernel via eBPF probes. No sidecar per pod, no application changes required.

# conceptual daemonset shape — adapt to your tool of choice
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: runtime-sensor
spec:
  template:
    spec:
      hostPID: true
      containers:
        - name: sensor
          image: <runtime-security-tool>:latest
          securityContext:
            privileged: true   # required for eBPF probe attachment
          volumeMounts:
            - name: kernel-headers
              mountPath: /usr/src

Step 2 — Write a rule for a behavior you actually care about. Here’s a Falco-style rule that fires when a shell is spawned inside a container that has no business running one:

- rule: Unexpected shell in container
  desc: A shell was spawned inside a container outside of the allowed exec list
  condition: >
    spawned_process
    and container
    and proc.name in (bash, sh, zsh)
    and not container.image.repository in (allowed_shell_images)
  output: >
    Shell spawned in container
    (user=%user.name container=%container.name image=%container.image.repository
    command=%proc.cmdline parent=%proc.pname)
  priority: WARNING
  tags: [container, shell, mitre_execution]

Step 3 — Add process lineage, not just the event. A single syscall event is weak signal. The same event with full process ancestry — parent process, container image, pod name, namespace — is enough to triage without a follow-up query. Every mature runtime tool attaches this context automatically; make sure it’s actually being captured and not stripped before it leaves the node.

Step 4 — Get sensitive file access covered. Credential theft is one of the highest-value detections runtime tooling gives you that control-plane logs can’t touch at all:

- rule: Read of cloud credential file
  desc: Process read a well-known cloud credential path
  condition: >
    open_read
    and fd.name in (/root/.aws/credentials, /var/run/secrets/kubernetes.io/serviceaccount/token)
    and not proc.name in (allowed_credential_readers)
  output: >
    Sensitive credential file read
    (file=%fd.name process=%proc.name container=%container.name)
  priority: CRITICAL

Getting runtime events into your detection pipeline

Runtime tools are noisy in isolation and most valuable correlated with everything else you already collect. The pattern that works well, described generically:

kernel event (eBPF probe)
  -> runtime agent enriches with process/container/pod context
  -> event shipped to your log pipeline in a normalized shape
  -> stored alongside cloud audit and identity events
  -> correlation layer: same principal, same time window, same workload
  -> alert only on the correlated finding, not the raw kernel event

The correlation step is what turns “a shell was spawned in a pod” (happens constantly in normal ops, especially in dev) into “a shell was spawned in a pod immediately after that pod’s service account made an unusual API call” — which is a very different alert priority. Concretely:

if runtime_event.type == "shell_spawned"
   and cloud_event.principal == runtime_event.service_account
   and abs(cloud_event.timestamp - runtime_event.timestamp) < 5 minutes
   and cloud_event.action in sensitive_api_actions:
     raise_alert(severity=critical, correlated=true)

None of this requires a specific storage engine or query language — any pipeline that can normalize both event types into a common schema and join on principal + time window will do it. If you’re already normalizing multi-vendor logs into a common schema, add runtime events as just another source.

Detection ideas worth building first

BehaviorMITRE ATT&CKWhy it’s high value
Shell spawned in a container with no interactive-use caseT1059 - Command and Scripting InterpreterNear-zero false positives in most production workloads
Read of a cloud credential file by an unexpected processT1552.001 - Credentials In FilesCatches credential theft before it becomes an API-based attack
Outbound connection from a binary that never makes network callsT1071 - Application Layer ProtocolFlags C2 beaconing regardless of destination reputation
Write to a container’s read-only root filesystem pathT1611 - Escape to HostSignals an active escape attempt, not just a misconfiguration
New binary executed from /tmp or another writable, non-image pathT1105 - Ingress Tool TransferCatches malware dropped after initial access

Start with these five. They map to common attacker behavior, generate low noise against a normal workload baseline, and don’t require you to already know what you’re looking for the way anomaly-based rules do.

Where it falls short

Runtime tooling isn’t a replacement for control-plane logging — it’s the layer underneath it. It won’t tell you an IAM policy was changed or a storage bucket was made public; that’s still audit-log territory. It also generates real operational load: expect to spend real tuning time getting a rule set from “technically correct” to “doesn’t page someone at 2 a.m. for a routine deploy.” Budget for a baselining period of two to four weeks per environment before you route these alerts anywhere that pages a human.

Final thought

Cloud-native attacks increasingly live entirely inside the workload, and workload-only visibility is exactly what most security programs are missing. eBPF-based runtime tooling is mature enough now, and cheap enough operationally, that there’s little excuse to leave that layer dark. Start with the shell-execution and credential-read rules above — they’re the highest signal-to-noise detections you can add this week.

If you want help wiring runtime detections into a pipeline that already correlates identity, cloud, and application logs, contact us.