Marcio Cunha

Container Hardening with Seccomp to Block Syscalls in the Linux Kernel

Learn how Seccomp restricts system calls in the Linux kernel to shield Docker and Kubernetes containers against complex attacker exploits.

Marcio Cunha12 min
Also available in:EspañolPortuguês
Summary
  • Seccomp acts as a direct kernel filter to block sensitive system calls that application containers rarely need to execute
  • Custom profiles prevent software flaws inside the application from compromising the entire host operating system
  • Rule creation requires prior monitoring to avoid accidentally breaking legitimate services in production environments
  • Modern tools simplify software behavior auditing and translation into efficient, restrictive security policies
  • Adopting standard security profiles drastically reduces the attack surface without requiring code rewrites

The Silent Security Challenge in Containerized Environments

When we run an application inside a container, we get the false impression that it lives in a bubble completely isolated from the rest of the computer. In practice, containers are nothing more than regular operating system processes sharing the same kernel, which is the core of Linux. This means that if an attacker discovers a severe security flaw in your code, they gain a direct bridge to converse with the host machine through commands called system calls, or syscalls. This is precisely where Seccomp comes in, acting as a strict security guard that blocks dangerous requests before they ever reach the core of the system.

To understand the practical impact of this, think of the Linux kernel as the central administration office of a large commercial building. Containers are individual offices rented to different companies. Without rules, any employee in one room could call the central desk and ask for the master key to the entire building. Seccomp functions as a restrictive phone list at the reception desk, determining exactly which telephone extensions each room is allowed to dial. If a program tries to call a forbidden extension, the call is cut off instantly and the attacker is left helpless, even after gaining total control of the web application.

In modern software engineering, relying solely on basic namespace and path isolation is no longer enough to guarantee secure corporate environments. Containers frequently run outdated code packages, third-party libraries full of known vulnerabilities, and command-line utilities that carry dozens of unnecessary privileges. Hardening, which is the process of reinforcing and shielding an infrastructure against intrusions, requires closing every possible gap. Blocking unregulated access to the deep gears of the operating system is the difference between an incident contained in seconds and a catastrophic data leak.

How Seccomp Operates in the Deep Layers of Linux

The acronym Seccomp stands for Secure Computing Mode, a feature that has existed inside the Linux kernel for many years and has evolved dramatically. In its early versions, it was uncompromising: a program would activate strict mode and could only perform two basic operations, reading and writing files to already open descriptors. Any other command attempt resulted in the immediate termination of the process. While very secure, this model broke practically any modern application that needed to create network connections or allocate memory in complex ways.

The turning point arrived with the introduction of BPF-based filters, technically known as Berkeley Packet Filter. This technology allows the creation of highly customized mathematical rules that evaluate the arguments passed in every system call before deciding whether it should be permitted, rejected, or monitored. In simple terms, Seccomp with BPF evaluates the program's request in fractions of a microsecond and checks if the syscall number matches something authorized in the whitelist configured by the administrator.

When Docker or Kubernetes start a container, they already apply a default Seccomp profile that blocks around three hundred system calls considered obsolete or overly dangerous for daily operations. Syscalls linked to direct hardware manipulation, kernel module changes, or deep process debugging are cut off immediately. However, this default profile must remain generic enough not to break databases, web servers, and various languages, which means it still leaves a considerable margin of open commands that your specific application might never use.

Writing and Applying a Custom Profile in Practice

Creating a tailored restrictive policy requires understanding exactly which system calls your software needs to operate. If you block the wrong syscall, the application will simply stop responding or return cryptic system errors. To avoid guesswork, the first step involves auditing the application's behavior in a staging environment, recording every command it sends to the Linux kernel during normal execution and load testing.

The format of a Seccomp profile is a structured JSON file that defines the default action to take, usually rejecting everything, followed by a list of permitted exceptions. Below is a real and functional example of a profile that severely restricts operations permitted to a basic microservice:

{
'defaultAction': 'SCMP_ACT_ERRNO',
'architectures': [
'SCMP_ARCH_X86_64'
],
'syscalls': [
{
'names': [
'read',
'write',
'exit',
'sigreturn'
],
'action': 'SCMP_ACT_ALLOW'
}
]
}

In the example above, the defaultAction property specifies that any call not explicitly listed should return an immediate error to the program. The syscalls section opens strict exceptions only for core read, write, and process termination operations. In practice, applying this to a real Docker container is done via a simple command-line flag, instructing the container engine to load the custom JSON rules file created specifically for that workload.

To use the configuration file created earlier in a production Docker container, the startup command takes a specific parameter pointing directly to the rule document on the local disk. The complete command is structured as follows in the server terminal:

docker run --rm \
--security-opt seccomp=/path/to/profile.json \
nginx:alpine

This approach ensures that even if the Nginx web server suffers an intrusion via an unknown vulnerability in request processing, the attacker cannot execute arbitrary commands on the system. Since the vast majority of modern exploitation tools rely on dozens of varied system calls to escalate privileges and download malicious payloads, cutting off access to these backdoors neutralizes the attack before it gains traction.

Writing Seccomp profiles manually line by line for dozens of microservices in a dynamic production environment is an unfeasible task prone to human error. This is why the infrastructure ecosystem has developed intelligent tools capable of observing container behavior and generating these security policies automatically. Tools like Seccomp profile generators or built-in features in platforms like Falco can inspect syscall traffic at runtime and export ready-to-use JSON files.

In the Kubernetes world, applying custom profiles requires coordinating the rule file with the lifecycle of the pods. Although it is possible to inject annotations directly into pod configuration files, modern approaches utilize dedicated operators that manage profiles at the cluster level. This allows the security team to define a corporate baseline that is automatically applied to all namespaces in the organization, ensuring compliance without burdening application developers with operational bureaucracy.

Another critical aspect involves handling software updates. When an application changes version, its internal dependencies might start requiring new system calls that were previously unused. If the Seccomp profile is overly rigid, the update will fail mysteriously in the continuous delivery pipeline. Therefore, the best operational practice involves running continuous audits in test environments, ensuring the profile evolves in sync with the source code before reaching servers serving real clients.

Final Thoughts on Shielding Workloads

Container hardening is no longer a corporate luxury; it has become a fundamental survival requirement in modern software engineering. As cybercriminals automate the search for flaws in cloud-based applications, relying solely on perimeter firewalls and strong passwords is like locking the front door while leaving all the windows open. Seccomp gives you the power to control what happens deep within the operating system, blocking invasion routes that would go unnoticed by any traditional tool.

Implementing this defense layer requires patience, rigorous testing, and close collaboration between development and operations teams. However, the return on effort is incomparable: transforming ordinary containers into armored boxes capable of resisting sophisticated intrusions. By adopting the principle of least privilege also at the Linux kernel level, your architecture gains real resilience, ensuring that even the worst-case scenario of code compromise remains contained and harmless.