Docker and system hardening

← Back

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

https://www.bleepingcomputer.com/news/security/new-gputhor-attack-defeats-nvidia-ecc-protection-for-root-access/

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. 😭