AppArmor und seccomp in Docker - Systemaufrufe einschränken

AppArmor und seccomp in Docker - Systemaufrufe einschränken

Docker-Container teilen den Host-Kernel – wer den Angriffsfläche minimieren will, schränkt Systemaufrufe und Dateizugriffe mit seccomp und AppArmor ein.

Was sind seccomp und AppArmor?

seccomp (Secure Computing Mode): Filtert Systemaufrufe (syscalls) auf Kernel-Ebene. Ein Container darf nur die explizit erlaubten syscalls ausführen. Alle anderen werden blockiert.

AppArmor: Mandatory Access Control für Linux. Kontrolliert welche Dateien, Netzwerke und Capabilities ein Prozess nutzen darf – per Profil definiert.

seccomp: Docker-Standard-Profil

Docker wendet auf jeden Container automatisch ein Standard-seccomp-Profil an, das ~44 gefährliche Syscalls blockiert:

# Aktives seccomp-Profil eines Containers prüfen
docker inspect mycontainer --format '{{.HostConfig.SecurityOpt}}'
# [seccomp={"defaultAction":"SCMP_ACT_ERRNO",...}]

Das Standard-Profil ist für die meisten Anwendungen ausreichend. Für Container die Untrusted Input verarbeiten (z.B. Code-Execution-Dienste) kann ein restriktiveres Custom-Profil sinnvoll sein.

Eigenes seccomp-Profil erstellen

// /etc/docker/seccomp/strict.json
{
  "defaultAction": "SCMP_ACT_ERRNO",
  "architectures": ["SCMP_ARCH_X86_64"],
  "syscalls": [
    {
      "names": [
        "read", "write", "open", "close",
        "stat", "fstat", "mmap", "mprotect",
        "brk", "exit_group", "futex",
        "accept", "connect", "socket",
        "sendto", "recvfrom", "bind", "listen"
      ],
      "action": "SCMP_ACT_ALLOW"
    }
  ]
}
# Profil anwenden
docker run --security-opt seccomp=/etc/docker/seccomp/strict.json myimage

In Compose:

services:
  app:
    image: myapp
    security_opt:
      - seccomp:/etc/docker/seccomp/strict.json

seccomp deaktivieren (für Debugging)

# Alle Syscalls erlauben – nur für Debugging, nie in Produktion
docker run --security-opt seccomp=unconfined myimage

AppArmor: Standard-Profil

Docker wendet das docker-default AppArmor-Profil an, wenn AppArmor auf dem Host aktiv ist:

# AppArmor-Status prüfen
aa-status

# Profil eines Containers prüfen
docker inspect mycontainer --format '{{.AppArmorProfile}}'

Eigenes AppArmor-Profil

# /etc/apparmor.d/docker-myapp
#include <tunables/global>

profile docker-myapp flags=(attach_disconnected,mediate_deleted) {
  #include <abstractions/base>

  # Netzwerk erlauben
  network inet tcp,
  network inet udp,

  # Nur bestimmte Verzeichnisse beschreibbar
  /app/uploads/** rw,
  /tmp/** rw,

  # Rest der Filesystem nur lesend
  /** r,

  # Bestimmte Capabilities verbieten
  deny capability mknod,
  deny capability net_admin,
}
# Profil laden
apparmor_parser -r /etc/apparmor.d/docker-myapp

# Container mit Profil starten
docker run --security-opt apparmor=docker-myapp myimage

Praktische Anwendungsfälle

Code-Execution-Container (z.B. online Code-Judge): seccomp-Profil das nur Lese-/Schreib-Syscalls und keine Netzwerk-Syscalls erlaubt.

Web-Scraper: AppArmor-Profil das nur HTTP/HTTPS-Zugriff erlaubt, keine Dateisystemzugriffe außer /tmp.

Datenbank: seccomp-Profil ohne ptrace, process_vm_readv, kexec_load.

Capabilities ergänzend einschränken

Zusammen mit seccomp und AppArmor:

# Alle Capabilities entfernen, nur die nötigsten erlauben
docker run \
  --cap-drop ALL \
  --cap-add NET_BIND_SERVICE \
  --security-opt seccomp=/etc/docker/seccomp/strict.json \
  myimage

Diese Kombination aus --cap-drop ALL, einem restriktiven seccomp-Profil und einem AppArmor-Profil liefert maximale Isolation für Container mit Untrusted Input.

Weiterführend

AppArmor und seccomp sind Linux-Kernfunktionen, die unabhängig von Docker existieren. Weiterführendes zu Linux-Sicherheit und Systemhärtung findet sich auf nolr.nexon.cyou.