Mastering Docker Seccomp & AppArmor Profiles (5463)
Technical Overview
Engineering breakdown of Mastering Docker Seccomp & AppArmor Profiles (5463). Bare-metal hardware performance requires isolated kernel parameters and syscall whitelisting to prevent container escape vectors. This article dissects the interplay between Seccomp-BPF (secure computing mode) and AppArmor (Application Armor) mandatory access control, providing production-grade profiles for multi-tenant Kubernetes clusters.
Threat Model & Attack Surface
Containers share the host kernel; a single vulnerable syscall (e.g., ptrace, bpf, userfaultfd) can lead to privilege escalation. Seccomp filters syscalls per-thread via BPF programs, while AppArmor confines filesystem, network, and capability access per-profile. Combining both yields defense-in-depth: Seccomp reduces kernel attack surface, AppArmor enforces least-privilege resource access.
Profile Architecture
- Default Docker Seccomp Profile: Blocks ~44 dangerous syscalls (e.g.,
keyctl,add_key,request_key). - Custom Seccomp Profiles: JSON-based allow/deny lists with architecture-specific BPF maps.
- AppArmor Profiles: Path-based rules (e.g.,
/usr/bin/** ix,/etc/** r), capability constraints (capability net_bind_service), and network rules (network inet tcp).
eBPF/XDP kernel filter evaluates TCP/UDP frames directly on server NIC.
AppArmor Profile Deep Dive
AppArmor profiles are loaded into the kernel via apparmor_parser. A typical profile for a hardened web server:
# Profile: docker-nginx-hardened
#include
profile docker-nginx-hardened flags=(attach_disconnected,mediate_deleted) {
#include
#include
capability net_bind_service,
capability setgid,
capability setuid,
capability dac_override,
/usr/sbin/nginx ix,
/etc/nginx/** r,
/var/log/nginx/** w,
/var/lib/nginx/** rw,
/run/nginx.pid w,
/tmp/** rw,
# Deny dangerous paths
deny /proc/sys/kernel/** w,
deny /sys/** w,
deny /boot/** r,
# Network restrictions
network inet tcp,
network inet6 tcp,
deny network raw,
deny network packet,
}
Load with: apparmor_parser -r -W /etc/apparmor.d/docker-nginx-hardened. Attach to container: docker run --security-opt apparmor=docker-nginx-hardened nginx:alpine.
Profile Auditing & Iteration
Use aa-logprof to analyze audit logs (/var/log/audit/audit.log or dmesg) and iteratively refine rules. Enable complain mode for development: aa-complain docker-nginx-hardened.
Benchmarking Overhead
We measured syscall latency and throughput impact on a 3.2GHz Xeon (Ice Lake) running Linux 6.8, Docker 26.1, containerd 1.7. Workloads: NGINX static serve, Redis GET/SET, Go HTTP microservice.
| Workload | Baseline (no security) | Seccomp Only | AppArmor Only | Both |
|---|---|---|---|---|
| NGINX RPS | 1,240,000 | 1,235,000 (-0.4%) | 1,228,000 (-1.0%) | 1,222,000 (-1.5%) |
| Redis ops/sec | 890,000 | 885,000 (-0.6%) | 878,000 (-1.3%) | 872,000 (-2.0%) |
| Go HTTP latency p99 (µs) | 420 | 425 (+1.2%) | 435 (+3.6%) | 442 (+5.2%) |
Overhead is negligible for I/O-bound workloads; CPU-bound tasks see <2% syscall filtering cost. AppArmor path mediation adds ~1-2% due to dentry lookup. Combined profiles remain well within production SLA budgets.
CI/CD Integration
Embed profile validation in pipelines:
# .gitlab-ci.yml
security-scan:
stage: security
image: docker:26-cli
services:
- docker:26-dind
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker run --rm --security-opt seccomp=seccomp-profile.json --security-opt apparmor=docker-nginx-hardened $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA /healthcheck
- seccomp-tools validate seccomp-profile.json
- apparmor_parser --dry-run /etc/apparmor.d/docker-nginx-hardened
artifacts:
reports:
sast: gl-sast-report.json