The Rise of eBPF in Container Security
As containerization becomes the standard for deploying applications, securing the workloads running inside Docker or Kubernetes is a critical challenge. Traditional security tools rely on kernel modules or intercepting system calls in user space, both of which introduce significant performance overhead and instability.
eBPF (Extended Berkeley Packet Filter) is a revolutionary technology built directly into the modern Linux kernel. It allows administrators to securely run sandboxed programs inside the kernel without modifying kernel source code or loading unstable modules. eBPF provides unprecedented, low-overhead visibility into network traffic, file access, and process execution, making it the premier choice for implementing security policies for containers on Ubuntu 24.04.
Prerequisites
Ensure you are running Ubuntu 24.04 with a kernel version of 5.15 or newer (which is default). You will also need the bpfcc-tools and bpftrace packages installed to interact with eBPF subsystems.
sudo apt update
sudo apt install bpfcc-tools bpftrace linux-headers-$(uname -r) -y
Understanding eBPF Sensors
eBPF security policies are fundamentally built on “hooks.” An eBPF program attaches to a specific event in the kernel, such as a process attempting to open a file (sys_enter_openat) or attempting to send a network packet. When the container triggers the event, the kernel pauses execution, runs the eBPF program to evaluate the security policy, and then either allows or denies the action.
Step 1: Monitoring Container Syscalls with bpftrace
Before implementing a blocking policy, you must understand what your container is doing. We can use bpftrace, a high-level tracing language for Linux, to monitor every command executed by a specific Docker container.
First, find the Process ID (PID) of your container’s main process:
docker inspect --format '{{.State.Pid}}' my-container
Assuming the PID is 4512, create a simple bpftrace script to monitor any new processes spawned by this container (e.g., if an attacker gets a shell and runs curl or wget):
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_execve /pid == 4512/ { printf("Suspicious execution: %s\n", str(args->filename)); }'
This provides real-time, kernel-level visibility without any agent running inside the container itself.
Step 2: Implementing a Seccomp-eBPF Policy
To move from monitoring to enforcement, Docker utilizes a specific subset of eBPF called Seccomp (Secure Computing). Docker applies a default seccomp profile that blocks roughly 44 dangerous system calls. However, you can write custom JSON policies that leverage eBPF to restrict actions further.
Create a file named strict-profile.json. In this example, we will explicitly block the chmod and chown system calls, preventing the container from altering file permissions even if the application runs as root.
{
"defaultAction": "SCMP_ACT_ALLOW",
"syscalls": [
{
"names": ["chmod", "fchmod", "chown", "fchown", "lchown"],
"action": "SCMP_ACT_ERRNO"
}
]
}
Step 3: Applying the eBPF Policy to a Container
When launching your Docker container, pass the custom profile using the --security-opt flag. Docker parses the JSON and compiles it into an eBPF program that is injected into the kernel specifically for that container’s cgroup.
docker run --rm -it --security-opt seccomp=strict-profile.json ubuntu:24.04 bash
If you attempt to run chmod 777 /etc/passwd inside this container, the eBPF program will instantly block it, returning an “Operation not permitted” error, regardless of the user’s privileges.
Conclusion
By utilizing eBPF and Seccomp profiles on Ubuntu 24.04, Linux administrators can enforce granular, high-performance security boundaries around containerized applications. This kernel-level enforcement guarantees that compromised containers cannot exploit the host system or pivot to adjacent workloads.