At first I've wanted to write specifically about the syscalls and seccomp, but Docker has quite a lot of configuration options, so I've decided to include all of it into a single post.
Arch
I'm using Arch Linux on the server. The default kernel doesn't have the AppArmor module included, so I had to install a Linux-hardened kernel.
Install
sudo pacman -S linux-hardened linux-hardened-headers
List blocks
lsblk
Read PARTUUID
blkid /dev/sda1
Add new boot entry
nano /boot/loader/entries/arch-hardened.conf
title Arch Linux (Hardened)
linux /vmlinuz-linux-hardened
initrd /initramfs-linux-hardened.img
options root=PARTUUID=your_partuuid rw rootfstype=ext4 apparmor=1 security=apparmor
Update (8/21/26):
Auditd has started complaining and according to this issue the changes to the boot config are needed
https://github.com/CachyOS/linux-cachyos/issues/878#issuecomment-5075213172
options root=PARTUUID=your_partuuid rw rootfstype=ext4 apparmor=1 security=apparmor lsm=capability,landlock,lockdown,yama,apparmor,bpf
Update (8/27/26):
A new GPUHammer-like attack has been discovered
Enable IOMMU
AMD
options root=PARTUUID=your_partuuid rw rootfstype=ext4 apparmor=1 security=apparmor lsm=capability,landlock,lockdown,yama,apparmor,bpf amd_iommu=on iommu=on
Intel
options root=PARTUUID=your_partuuid rw rootfstype=ext4 apparmor=1 security=apparmor lsm=capability,landlock,lockdown,yama,apparmor,bpf intel_iommu=on iommu=on
Verify
dmesg | grep -i iommu
Also, Nvidia additionally recommends iommu=force and disabling IOMMU passthrough mode (iommu.passthrough=0), which is the default but is sometimes overridden by distribution defaults or driver packaging.
AMD
options root=PARTUUID=your_partuuid rw rootfstype=ext4 apparmor=1 security=apparmor lsm=capability,landlock,lockdown,yama,apparmor,bpf amd_iommu=on iommu=force iommu.passthrough=0
Intel
options root=PARTUUID=your_partuuid rw rootfstype=ext4 apparmor=1 security=apparmor lsm=capability,landlock,lockdown,yama,apparmor,bpf intel_iommu=on iommu=force iommu.passthrough=0
Switch kernel
sudo bootctl set-default arch-hardened.conf
Reboot
sudo reboot now
Check version
uname -r
Daemon
By default, Docker's bridge driver allows inter-container communication, which may be useful, but poses a security risk. If containers need shared networking, it's better to create a separate network and assign it to them.
Here's a daemon config that has Nvidia support, global limits, and disabled ICC.
sudo tee /etc/docker/daemon.json >/dev/null <<'EOF'
{
"default-runtime": "nvidia",
"default-ulimits": {
"nofile": {
"Hard": 65536,
"Name": "nofile",
"Soft": 32768
},
"nproc": {
"Hard": 512,
"Name": "nproc",
"Soft": 256
}
},
"icc": false,
"live-restore": true,
"no-new-privileges": true,
"runtimes": {
"nvidia": {
"args": [],
"path": "nvidia-container-runtime"
}
},
"storage-driver": "overlay2",
"userland-proxy": false
}
EOF
For Nvidia to work you'd need a container toolkit.
sudo pacman -Syu nvidia-container-toolkit
To enable Nvidia GPU support in Compose:
services:
server:
deploy:
resources:
reservations:
devices:
- driver: nvidia
device_ids: ["0"] # Modify for multiple GPUs: ["0", "1"]
capabilities: [gpu]
Enable Nvidia driver before Docker:
sudo systemctl enable nvidia-persistenced
Inspect default bridge configuration
sudo docker network inspect bridge
List networks
sudo docker network ls
Create a network
sudo docker network create --driver bridge new-network-name
Create a network with Compose
networks:
new-network-name:
external: false
services:
server:
networks:
- new-network-name
AppArmor
At first I've tried to make gen-prof work within a container, but it didn't go well. Then I took a manual approach. It should be possible to automate the whole process by writing a bash script that would continuously read dmesg logs, update the profile, and restart the container though...
Create a new profile
sudo tee /etc/apparmor.d/docker-your-container-name >/dev/null <<'EOF'
#include <tunables/global>
profile docker-your-container-name flags=(attach_disconnected, mediate_deleted) {
#include <abstractions/base>
# Capabilities
capability setuid,
capability setgid,
deny capability dac_override,
capability net_bind_service,
capability chown,
capability fowner,
capability fsetid,
capability setfcap,
}
EOF
Set it to complain mode
sudo aa-complain docker-your-container-name
Attach it to a container
service:
security_opt:
- no-new-privileges:true
- apparmor:docker-mineru
Read logs
sudo dmesg | grep -F 'apparmor="DENIED"'
Then update the profile accordingly, parse it, and restart the container. Repeat until there are no errors left.
sudo apparmor_parser -r /etc/apparmor.d/docker-your-container-name
There should've been a section dedicated to eBPF and seccomp, but I've failed understanding it. 😭