Einleitung: Warum Boot-Chain-Sicherheit und Service-Härtung 2026 unverzichtbar sind
Mal ehrlich — wenn man sich die Zahlen anschaut, wird einem schon etwas mulmig. 2025 wurden 5.530 Kernel-CVEs veröffentlicht, das sind 28 Prozent mehr als im Vorjahr. Ransomware-Gruppen wie BlackCat und LockBit werden immer raffinierter und setzen gezielt auf Kernel-Exploits, um Sicherheitsmechanismen direkt auf Betriebssystemebene auszuhebeln. Und wenn der Bootprozess einmal kompromittiert ist? Dann sind alle darüber liegenden Schutzschichten — von SELinux bis zur Application-Level-Firewall — praktisch wirkungslos.
Dazu kommt ein ziemlich konkretes Problem: Im Dezember 2025 hat die NSA eine aktualisierte Richtlinie zur UEFI-Secure-Boot-Konfiguration herausgegeben. Die klare Empfehlung: benutzerdefinierte Schlüssel statt der vorinstallierten Herstellerschlüssel verwenden. Der Hintergrund ist ernst — am 26. Juni 2026 läuft das Microsoft UEFI CA-Zertifikat von 2011 aus. Ja, genau das Zertifikat, das praktisch alle Linux-Distributionen zum Signieren ihrer Bootloader nutzen. Wer hier nicht rechtzeitig reagiert, riskiert, dass Systeme nach einem Firmware-Update schlicht nicht mehr hochfahren.
Gleichzeitig hat sich systemd als Standard-Init-System auf so gut wie allen Enterprise-Linux-Distributionen durchgesetzt. Die Sicherheitsdirektiven, die systemd mitbringt, sind beeindruckend — werden aber erschreckend selten genutzt. Über 70 Prozent aller produktiven systemd-Service-Units haben nicht eine einzige Härtungsmaßnahme konfiguriert. Das ist im Grunde eine offene Einladung für jeden Angreifer, der bereits einen Fuß in der Tür hat.
In diesem Leitfaden gehen wir die komplette Sicherheitskette durch: vom allerersten Firmware-Befehl beim Einschalten bis zur gehärteten Ausführung einzelner Dienste im laufenden Betrieb. Keine reine Theorie — Sie bekommen praxiserprobte Befehle und Konfigurationen, die Sie direkt einsetzen können.
UEFI Secure Boot verstehen
Was ist UEFI Secure Boot?
UEFI Secure Boot ist ein Sicherheitsmechanismus in der UEFI-Firmware, der dafür sorgt, dass beim Bootvorgang nur Software ausgeführt wird, die mit einem vertrauenswürdigen kryptografischen Schlüssel signiert wurde. Klingt simpel, ist aber enorm wirkungsvoll: Es verhindert, dass Bootkits, Rootkits oder manipulierte Bootloader den Startprozess kapern, bevor das Betriebssystem überhaupt geladen ist.
Die Boot-Chain im Detail
So sieht der gesicherte Bootprozess auf einem typischen Linux-System aus:
- UEFI-Firmware: Die Firmware initialisiert die Hardware und prüft die Signatur des ersten Bootloaders. Nur bei erfolgreicher Validierung gegen die gespeicherten Schlüssel geht's weiter.
- Shim: Ein kleiner, von Microsoft signierter Bootloader, der zwischen UEFI-Firmware und dem eigentlichen Bootloader vermittelt. Shim enthält den öffentlichen Schlüssel der jeweiligen Linux-Distribution und kann zusätzliche Machine Owner Keys (MOK) laden.
- GRUB2: Der eigentliche Bootloader, verifiziert durch Shim. GRUB2 lädt die Kernel-Konfiguration, zeigt das Boot-Menü und übergibt dann die Kontrolle an den Linux-Kernel.
- Linux-Kernel: Wird von GRUB2 verifiziert und geladen. Ab hier übernimmt der Kernel — und kann über Mechanismen wie das IMA-Subsystem (Integrity Measurement Architecture) die Integrität weiterer Dateien sicherstellen.
Die Schlüsselhierarchie: PK, KEK, DB und DBX
Das Sicherheitsmodell basiert auf einer hierarchischen Schlüsselstruktur. Wer hier den Überblick hat, versteht Secure Boot wirklich:
- Platform Key (PK): Der Wurzelschlüssel der gesamten Vertrauenskette. Wird typischerweise vom Hardwarehersteller gesetzt. Auf selbst verwalteten Systemen sollten Sie unbedingt Ihren eigenen PK einrollen.
- Key Exchange Key (KEK): Autorisiert Änderungen an den Signaturdatenbanken DB und DBX. Sowohl Microsoft als auch der Hardwarehersteller können KEKs hinterlegen.
- Signature Database (DB): Enthält die vertrauenswürdigen Zertifikate und Hashes, gegen die Boot-Software verifiziert wird — typischerweise das Microsoft-Zertifikat und die Zertifikate der Linux-Distributionen.
- Forbidden Signature Database (DBX): Die Widerrufsliste. Hier landen Hashes oder Zertifikate, denen nicht mehr vertraut werden soll, etwa nach einer Schwachstelle in einem Bootloader.
Wichtig: Wer den PK kontrolliert, kontrolliert die gesamte Vertrauenskette. In Enterprise-Umgebungen sollten Sie ernsthaft darüber nachdenken, den herstellerseitigen PK durch einen eigenen zu ersetzen und eine vollständig selbst verwaltete Schlüsselhierarchie aufzubauen.
Secure Boot auf Linux konfigurieren
Aktuellen Status überprüfen
Bevor Sie irgendetwas an der Secure-Boot-Konfiguration ändern, schauen Sie sich erstmal den aktuellen Zustand an:
# Secure Boot Status prüfen
mokutil --sb-state
# Erwartete Ausgabe bei aktiviertem Secure Boot:
# SecureBoot enabled
# Alle eingerollten Schlüssel anzeigen
mokutil --list-enrolled
# UEFI-Variablen direkt abfragen
efi-readvar
Falls mokutil --sb-state die Ausgabe SecureBoot disabled liefert, müssen Sie Secure Boot zunächst im UEFI-Setup aktivieren. Aber Vorsicht: Bei laufenden Systemen braucht das sorgfältige Planung, denn nicht signierte Kernel und Module werden danach nicht mehr geladen.
Eigene Schlüssel mit sbctl erstellen und verwalten
Das Tool sbctl macht die Verwaltung eigener Secure-Boot-Schlüssel deutlich angenehmer. Es wurde speziell für Linux entwickelt und automatisiert viele der sonst recht mühsamen manuellen Schritte:
# sbctl installieren (Arch Linux)
pacman -S sbctl
# sbctl installieren (Ubuntu/Debian - aus den Quellen)
apt install golang-go
go install github.com/foxboron/sbctl/cmd/sbctl@latest
# Status prüfen
sbctl status
# Neue Schlüssel generieren (PK, KEK, DB)
sbctl create-keys
# Die Schlüssel werden standardmäßig unter /usr/share/secureboot/ abgelegt
ls -la /usr/share/secureboot/keys/
# Schlüssel in die Firmware einrollen
# ACHTUNG: Dies erfordert, dass Secure Boot im Setup Mode ist
sbctl enroll-keys
# Mit Microsoft-Schlüsseln kombiniert einrollen (empfohlen für Dual-Boot)
sbctl enroll-keys --microsoft
Kernel und Bootloader signieren
Sobald die eigenen Schlüssel stehen, müssen alle relevanten Boot-Komponenten signiert werden:
# Alle zu signierenden Dateien anzeigen
sbctl verify
# Kernel signieren
sbctl sign -s /boot/vmlinuz-linux
sbctl sign -s /boot/vmlinuz-linux-lts
# GRUB-Bootloader signieren
sbctl sign -s /boot/EFI/BOOT/BOOTX64.EFI
sbctl sign -s /boot/EFI/systemd/systemd-bootx64.efi
# Initramfs muss nicht signiert werden, wenn es in den
# Unified Kernel Image eingebettet wird (siehe Abschnitt UKI)
# Alle registrierten Dateien anzeigen
sbctl list-files
# sbctl kann beim Kernel-Update automatisch neu signieren
# durch den pacman-Hook (Arch) oder den kernel-install-Hook
Machine Owner Keys (MOK) einrollen
Der MOK-Mechanismus ist besonders praktisch, wenn Sie den herstellerseitigen PK beibehalten, aber trotzdem eigene Module oder Kernel signieren möchten. Er ermöglicht das Einrollen zusätzlicher Schlüssel, ohne die Firmware-Variablen direkt anfassen zu müssen:
# Neuen MOK-Schlüssel generieren
openssl req -new -x509 -newkey rsa:2048 -keyout MOK.key \
-out MOK.crt -nodes -days 3650 \
-subj "/CN=Mein Unternehmen Secure Boot Schlüssel/"
# In DER-Format konvertieren (für mokutil benötigt)
openssl x509 -in MOK.crt -out MOK.der -outform DER
# MOK einrollen (erfordert Neustart und physischen Zugang)
mokutil --import MOK.der
# Nach dem Neustart erscheint der MokManager im Pre-Boot-Bereich
# Dort muss das Einrollen manuell bestätigt werden
# Eingerollte MOKs überprüfen
mokutil --list-enrolled
DKMS-Module mit Secure Boot
Dynamisch kompilierte Kernelmodule (DKMS) sind eine besondere Herausforderung — sie müssen nach jeder Kernel-Aktualisierung neu gebaut und signiert werden. Das kann schnell nervig werden, lässt sich aber gut automatisieren:
# DKMS-Signierungsskript erstellen
cat > /etc/dkms/sign_helper.sh <<'SCRIPT'
#!/bin/bash
/usr/lib/linux-kbuild-$(uname -r | cut -d. -f1-2)/scripts/sign-file \
sha256 \
/var/lib/shim-signed/mok/MOK.priv \
/var/lib/shim-signed/mok/MOK.der \
"$1"
SCRIPT
chmod +x /etc/dkms/sign_helper.sh
# In /etc/dkms/framework.conf eintragen:
# sign_tool="/etc/dkms/sign_helper.sh"
# Manuell ein einzelnes Modul signieren
kmodsign sha256 /var/lib/shim-signed/mok/MOK.priv \
/var/lib/shim-signed/mok/MOK.der \
/lib/modules/$(uname -r)/updates/dkms/vboxdrv.ko
# Überprüfen, ob ein Modul signiert ist
modinfo vboxdrv | grep sig
Die Microsoft-Zertifikat-Krise 2026
Jetzt wird's richtig spannend (und ein bisschen beunruhigend). Am 26. Juni 2026 läuft das Microsoft Corporation UEFI CA 2011-Zertifikat aus. Dieses Zertifikat ist die Grundlage dafür, dass nahezu alle Linux-Distributionen auf Hardware mit aktiviertem Secure Boot überhaupt booten können. Der Shim-Bootloader von Red Hat, Canonical, SUSE und Co. — alle mit diesem Microsoft-Zertifikat signiert.
Was bedeutet das konkret?
Nach dem Ablaufdatum werden Firmware-Implementierungen, die den Ablauf korrekt prüfen, die Shim-Signatur als ungültig betrachten. Das Tückische: Nicht alle UEFI-Implementierungen prüfen das Ablaufdatum — das Verhalten variiert je nach Hersteller und Firmware-Version. Das Ergebnis ist eine ziemlich fragmentierte Situation:
- Einige Systeme werden nach einem Firmware-Update plötzlich nicht mehr booten
- Andere Systeme ignorieren das Ablaufdatum und laufen einfach weiter
- Neue Hardware ab Mitte 2026 wird wahrscheinlich nur noch das neue Zertifikat akzeptieren
Wie reagieren die Distributionen?
Red Hat / RHEL: Red Hat hat bereits mit RHEL 9.4 einen neuen Shim veröffentlicht, signiert mit dem Microsoft UEFI CA 2023-Zertifikat. Bestehende RHEL 8-Systeme bekommen Backport-Updates. Stellen Sie sicher, dass shim-x64 und grub2-efi-x64 aktuell sind.
Ubuntu / Canonical: Ubuntu 24.04 LTS und 22.04 LTS erhalten aktualisierte Shim-Pakete über die regulären Sicherheitsupdates. Canonical empfiehlt zusätzlich, die DBX-Datenbank nach dem Update zu aktualisieren, um alte Shim-Versionen zu widerrufen.
SUSE / openSUSE: SUSE hat einen cleveren Ansatz gewählt — ein doppelt signierter Shim, der sowohl das 2011er als auch das 2023er Zertifikat unterstützt. So soll der Übergang möglichst nahtlos klappen.
Empfohlene Maßnahmen für Administratoren
# 1. Aktuellen Shim-Status prüfen
rpm -q shim-x64 # RHEL/Fedora/SUSE
dpkg -l shim-signed # Ubuntu/Debian
# 2. Prüfen, welche Zertifikate in der Firmware DB sind
efi-readvar -v db | grep "Microsoft"
# 3. Shim und GRUB aktualisieren
# RHEL/Fedora:
dnf update shim-x64 grub2-efi-x64
# Ubuntu/Debian:
apt update && apt upgrade shim-signed grub-efi-amd64-signed
# 4. DBX-Datenbank aktualisieren
fwupdmgr get-updates
fwupdmgr update
# 5. Nach dem Update verifizieren
mokutil --sb-state
bootctl status # bei systemd-boot
Dringend empfohlen: Testen Sie alle Updates zuerst auf einem Staging-System! Ein fehlgeschlagenes Secure-Boot-Update kann dazu führen, dass ein System nicht mehr bootfähig ist — und dann brauchen Sie physischen Zugang für die Reparatur.
Measured Boot und TPM-Integration
Wie Measured Boot funktioniert
Secure Boot trifft eine binäre Entscheidung: Booten erlauben oder blockieren. Measured Boot geht einen entscheidenden Schritt weiter — jede Stufe des Bootvorgangs wird kryptografisch gemessen und in den Platform Configuration Registers (PCR) des TPM 2.0 gespeichert. Diese Messungen lassen sich später von lokalen oder entfernten Diensten überprüfen, um die Integrität des gesamten Bootvorgangs nachzuweisen.
Die wichtigsten PCR-Register und was sie bedeuten:
- PCR 0: UEFI-Firmware-Code (BIOS/EFI)
- PCR 1: UEFI-Firmware-Konfiguration
- PCR 2: Option-ROMs (Erweiterungskarten)
- PCR 3: Option-ROM-Konfiguration
- PCR 4: MBR/Bootloader-Code (IPL-Code)
- PCR 5: MBR/Bootloader-Konfiguration (IPL-Konfiguration)
- PCR 7: Secure-Boot-Zustand und -Richtlinien
- PCR 8-9: Kernel-Kommandozeile und initramfs (bei systemd-boot)
- PCR 11: Unified Kernel Image Hash
- PCR 12: Kernel-Kommandozeilenparameter (Overrides)
- PCR 14: MOK-Zertifikate und Hashes
TPM-Messungen mit tpm2-tools überprüfen
# tpm2-tools installieren
# RHEL/Fedora:
dnf install tpm2-tools
# Ubuntu/Debian:
apt install tpm2-tools
# Alle PCR-Werte auslesen
tpm2_pcrread
# Nur bestimmte PCR-Register auslesen (SHA-256 Bank)
tpm2_pcrread sha256:0,1,4,7
# TPM-Eventlog auslesen und decodieren
tpm2_eventlog /sys/kernel/security/tpm0/binary_bios_measurements
# PCR-Werte gegen erwartete Referenzwerte prüfen
# (Nützlich für Remote Attestation)
tpm2_pcrread sha256:0,1,2,3,4,5,6,7 -o pcr_values.bin
sha256sum pcr_values.bin
Secure Boot und Measured Boot kombinieren: Defense in Depth
Erst die Kombination beider Mechanismen ergibt eine wirklich robuste Verteidigung:
- Secure Boot verhindert die Ausführung unsignierter Software während des Bootvorgangs
- Measured Boot protokolliert den genauen Zustand jeder Boot-Stufe — so lässt sich nachvollziehen, was tatsächlich geladen wurde
- LUKS mit TPM-Bindung koppelt die Festplattenverschlüsselung an einen bekannten, integren Boot-Zustand
# LUKS-Schlüssel an PCR-Werte binden (systemd-cryptenroll)
systemd-cryptenroll --tpm2-device=auto \
--tpm2-pcrs=0+1+4+7 \
/dev/sda2
# Dies bewirkt, dass die Festplatte nur entschlüsselt wird,
# wenn Firmware, Konfiguration, Bootloader und Secure-Boot-Zustand
# den erwarteten Werten entsprechen
systemd Service-Härtung: Grundlagen
Warum systemd-Härtung entscheidend ist
Selbst wenn die Boot-Chain komplett abgesichert ist — was passiert, wenn ein laufender Dienst kompromittiert wird? Genau hier kommt systemd ins Spiel. Es bietet über 40 verschiedene Sicherheitsdirektiven, die den Zugriff eines Dienstes auf Systemressourcen granular einschränken. Im Kern implementieren diese Direktiven das Principle of Least Privilege auf Prozessebene und nutzen dafür Linux-Kernel-Mechanismen wie Namespaces, Capabilities, Seccomp und Cgroups.
systemd-analyze security: Der erste Schritt
Bevor Sie wild Direktiven in Ihre Unit-Dateien schreiben, verschaffen Sie sich erstmal einen Überblick. systemd-analyze security zeigt den Härtungsgrad aller aktiven Service-Units:
# Übersicht aller Services und ihre Sicherheitsbewertung
systemd-analyze security
# Detaillierte Analyse eines einzelnen Services
systemd-analyze security nginx.service
# Ausgabeformat: Jede Direktive wird bewertet
# EXPOSURE zeigt den Gesamtwert von 0.0 (sicher) bis 10.0 (unsicher)
# Beispielausgabe:
# NAME DESCRIPTION EXPOSURE
# nginx.service nginx web server 9.2 UNSAFE
Ein Exposure-Score von 9.2 — das ist schon ziemlich heftig. Unser Ziel: unter 2.0, was systemd als OK einstuft.
Wichtige systemd-Sicherheitsdirektiven
Dateisystem-Isolation
ProtectSystem=strict mountet das gesamte Dateisystem als schreibgeschützt. Der Dienst kann dann nur noch in explizit freigegebene Verzeichnisse schreiben:
[Service]
# Das gesamte Dateisystem ist nur lesbar
ProtectSystem=strict
# Explizit Schreibzugriff für bestimmte Verzeichnisse erlauben
ReadWritePaths=/var/log/nginx /var/cache/nginx /run/nginx
# Alternativ: Nur /usr und /boot schreibschützen
# ProtectSystem=full
# Oder: Nur /usr schreibschützen
# ProtectSystem=yes
ProtectHome=yes sperrt den Zugriff auf /home, /root und /run/user komplett. Mit ProtectHome=read-only wird nur der Schreibzugriff unterbunden, und ProtectHome=tmpfs legt ein leeres tmpfs über diese Verzeichnisse:
[Service]
ProtectHome=yes
PrivateTmp=yes erstellt einen privaten /tmp- und /var/tmp-Namespace. Andere Dienste und Benutzer können die temporären Dateien dieses Dienstes schlicht nicht sehen:
[Service]
PrivateTmp=yes
Kernel-Schutzmaßnahmen
ProtectKernelModules=yes verhindert, dass der Dienst Kernelmodule laden oder entladen kann — inklusive des Zugriffs auf /lib/modules:
[Service]
ProtectKernelModules=yes
ProtectKernelTunables=yes macht alle Kernel-Tunables in /proc/sys, /sys und ähnlichen virtuellen Dateisystemen schreibgeschützt. Damit kann ein kompromittierter Dienst keine Kernel-Parameter mehr verändern:
[Service]
ProtectKernelTunables=yes
ProtectKernelLogs=yes sperrt den Zugriff auf den Kernel-Log-Ring-Buffer (/dev/kmsg) und schützt so vor dem Auslesen sensibler Kernel-Meldungen:
[Service]
ProtectKernelLogs=yes
ProtectControlGroups=yes macht die Cgroup-Hierarchie unter /sys/fs/cgroup schreibgeschützt:
[Service]
ProtectControlGroups=yes
Privilegieneinschränkung
NoNewPrivileges=yes — das ist meiner Meinung nach eine der wichtigsten Direktiven überhaupt. Sie stellt sicher, dass der Prozess und alle Kindprozesse niemals neue Privilegien erlangen können, weder durch setuid-Binaries noch durch Capabilities:
[Service]
NoNewPrivileges=yes
RestrictSUIDSGID=yes verhindert, dass der Dienst SUID- oder SGID-Bits auf Dateien setzen kann:
[Service]
RestrictSUIDSGID=yes
CapabilityBoundingSet= begrenzt die verfügbaren Linux-Capabilities. Ein leerer Wert entfernt alle:
[Service]
# Nur die absolut notwendigen Capabilities erlauben
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_DAC_READ_SEARCH
# Oder: Alle Capabilities entfernen
# CapabilityBoundingSet=
Namespace-Isolation
RestrictNamespaces=yes verhindert die Erstellung neuer Linux-Namespaces. Das betrifft User-, PID-, Network- und Mount-Namespaces — und erschwert Container-Ausbrüche erheblich:
[Service]
RestrictNamespaces=yes
# Alternativ: Nur bestimmte Namespaces erlauben
# RestrictNamespaces=~user pid net
Systemaufruf-Filterung
SystemCallFilter= nutzt Seccomp, um die verfügbaren Systemaufrufe einzuschränken. systemd bietet praktische vordefinierte Gruppen:
[Service]
# Nur grundlegende Systemaufrufe und Netzwerk-I/O erlauben
SystemCallFilter=@system-service
# Gefährliche Systemaufrufe explizit verbieten
SystemCallFilter=~@mount @clock @debug @module @raw-io @reboot @swap
# Verfügbare Systemaufruf-Gruppen anzeigen:
# systemd-analyze syscall-filter
Dateisystem-Zugriffskontrolle
ReadWritePaths=, ReadOnlyPaths= und InaccessiblePaths= geben granulare Kontrolle über den Dateisystemzugriff:
[Service]
ProtectSystem=strict
ReadWritePaths=/var/lib/myapp /var/log/myapp
ReadOnlyPaths=/etc/myapp
InaccessiblePaths=/home /root /var/lib/other-sensitive-app
Dynamische Benutzer
DynamicUser=yes weist dem Dienst einen transienten, dynamisch zugewiesenen Benutzer zu. Dieser existiert nur während der Laufzeit — keine persistente Spur auf dem System:
[Service]
DynamicUser=yes
# Persistenter Zustandsspeicher für DynamicUser
StateDirectory=myapp
CacheDirectory=myapp
LogsDirectory=myapp
Hinweis:DynamicUser=yesimpliziert automatischProtectSystem=strict,ProtectHome=read-only,PrivateTmp=yesundRemoveIPC=yes. Ehrlich gesagt ist es eine der wirkungsvollsten einzelnen Härtungsmaßnahmen, die systemd bietet.
Praxisbeispiel: Einen Webserver-Dienst härten
Vorher: Standard-nginx-Unit-Datei
So sieht eine typische, ungehärtete nginx-Service-Unit aus — und das ist leider bei vielen Installationen genau das, was man in der Praxis vorfindet:
# /etc/systemd/system/nginx.service (VORHER - UNGEHÄRTET)
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
# Sicherheitsbewertung VOR der Härtung
systemd-analyze security nginx.service
# Ausgabe (gekürzt):
# Overall exposure level for nginx.service: 9.2 UNSAFE
Nachher: Vollständig gehärtete Unit-Datei
Und so sieht das Ganze nach der Härtung aus. Die Unterschiede sind beachtlich:
# /etc/systemd/system/nginx.service (NACHHER - GEHÄRTET)
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
# === Dateisystem-Isolation ===
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
ReadWritePaths=/var/log/nginx /var/cache/nginx /run
# === Kernel-Schutz ===
ProtectKernelModules=yes
ProtectKernelTunables=yes
ProtectKernelLogs=yes
ProtectControlGroups=yes
# === Netzwerk ===
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
# === Privilegien ===
NoNewPrivileges=yes
RestrictSUIDSGID=yes
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_DAC_READ_SEARCH CAP_SETUID CAP_SETGID
AmbientCapabilities=CAP_NET_BIND_SERVICE
# === Namespaces und Systemaufrufe ===
RestrictNamespaces=yes
SystemCallFilter=@system-service
SystemCallFilter=~@mount @debug @module @raw-io @reboot @swap @clock
SystemCallArchitectures=native
# === Verschiedenes ===
LockPersonality=yes
MemoryDenyWriteExecute=yes
ProtectHostname=yes
ProtectClock=yes
ProtectProc=invisible
ProcSubset=pid
RestrictRealtime=yes
PrivateDevices=yes
DevicePolicy=closed
UMask=0077
[Install]
WantedBy=multi-user.target
# Sicherheitsbewertung NACH der Härtung
systemd-analyze security nginx.service
# Ausgabe (gekürzt):
# Overall exposure level for nginx.service: 1.8 OK
# Service neu laden und testen
systemctl daemon-reload
systemctl restart nginx.service
systemctl status nginx.service
# Funktionalität verifizieren
curl -I http://localhost
Von 9.2 auf 1.8 — das sind über 80 Prozent Reduktion. Und das Beste: nginx läuft weiterhin einwandfrei. Der Dienst hat nur drastisch eingeschränkte Möglichkeiten, das System zu kompromittieren, falls er tatsächlich angegriffen wird.
Schrittweises Vorgehen bei der Härtung
Beim Härten produktiver Dienste sollten Sie nicht alles auf einmal umstellen. Ein schrittweises Vorgehen hat sich in der Praxis bewährt:
- Starten Sie mit
systemd-analyze security dienstname.service, um den Ist-Zustand zu ermitteln - Fügen Sie zunächst die risikoarmen Direktiven hinzu:
ProtectHome=yes,ProtectKernelModules=yes,ProtectKernelTunables=yes,NoNewPrivileges=yes - Testen Sie nach jeder Änderung die Funktionalität gründlich
- Fügen Sie dann restriktivere Direktiven wie
ProtectSystem=strictmit passendenReadWritePaths=hinzu - Implementieren Sie zuletzt
SystemCallFilter=undCapabilityBoundingSet=— die verursachen am ehesten Probleme - Nutzen Sie
journalctl -u dienstname.service, um auf seccomp-Fehler oder Permission-Denied-Meldungen zu achten
Fortgeschrittene Techniken
Secure Boot kombiniert mit dm-verity: Unveränderliches Root-Dateisystem
dm-verity bietet kryptografische Integritätsüberprüfung für Block-Devices auf Basis von Merkle-Bäumen. Kombiniert mit Secure Boot entsteht eine lückenlose Vertrauenskette vom Einschalten bis zum laufenden Root-Dateisystem — das ist wirklich das Nonplusultra in Sachen Boot-Integrität:
# dm-verity Hash-Baum für ein Root-Device erstellen
veritysetup format /dev/sda3 /dev/sda4
# Ausgabe enthält den Root-Hash, z.B.:
# Root hash: 4a2e8b3f...
# dm-verity Device aktivieren
veritysetup open /dev/sda3 verified-root /dev/sda4 \
4a2e8b3f... # Root-Hash hier einfügen
# Das verifizierte Device ist nun unter /dev/mapper/verified-root verfügbar
mount -o ro /dev/mapper/verified-root /mnt
# Den Root-Hash in die Kernel-Kommandozeile einbetten:
# root=/dev/dm-0 dm-mod.create="verified-root,,0,ro,0 $(blockdev --getsz /dev/sda3) verity 1 /dev/sda3 /dev/sda4 4096 4096 $(expr $(blockdev --getsz /dev/sda3) / 8) 1 sha256 ROOT_HASH_HIER salt-"
# Für Produktionsumgebungen: Den Root-Hash im UKI einbetten
# (siehe nächster Abschnitt)
In dieser Konfiguration wird jeder einzelne Block des Root-Dateisystems beim Lesen verifiziert. Manipulation wird sofort erkannt und führt zu einem I/O-Fehler. Rootkits haben so keine Chance, Systemdateien unbemerkt zu ändern.
systemd-creds: Verschlüsselte Dienst-Credentials
systemd-creds ist ein Feature, das meiner Erfahrung nach noch viel zu wenig Beachtung bekommt. Es ermöglicht die verschlüsselte Speicherung von Dienstzugangsdaten, gebunden an den TPM und die spezifische Service-Unit:
# Ein Credential verschlüsseln (an TPM und Host-ID gebunden)
systemd-creds encrypt --name=db-password \
--with-key=tpm2 \
- /etc/credstore.encrypted/myapp-db-password.cred \
<<<"SuperGeheimesPasswort123"
# In der Service-Unit auf das Credential zugreifen:
# [Service]
# SetCredentialEncrypted=db-password:/etc/credstore.encrypted/myapp-db-password.cred
# Im Dienst ist das Credential dann unter diesem Pfad verfügbar:
# $CREDENTIALS_DIRECTORY/db-password
# Beispiel: Vollständige Service-Unit mit Credentials
cat > /etc/systemd/system/myapp.service <<'EOF'
[Service]
Type=simple
ExecStart=/usr/local/bin/myapp
SetCredentialEncrypted=db-password:/etc/credstore.encrypted/myapp-db-password.cred
SetCredentialEncrypted=api-key:/etc/credstore.encrypted/myapp-api-key.cred
# Das Credential ist im Dienst verfügbar als:
# /run/credentials/myapp.service/db-password
# /run/credentials/myapp.service/api-key
EOF
# Alle verfügbaren Credentials auflisten
systemd-creds list
Der entscheidende Vorteil gegenüber Umgebungsvariablen oder Klartext-Konfigurationsdateien: Die Credentials können nur auf dem spezifischen Host, mit dem spezifischen TPM und für den spezifischen Dienst entschlüsselt werden. Selbst wenn ein Angreifer die verschlüsselte Datei kopiert — auf einem anderen System ist sie wertlos.
Unified Kernel Images (UKI): Manipulationssicherer Boot
Unified Kernel Images bündeln Kernel, initramfs, Kernel-Kommandozeile und optional weitere Ressourcen in einer einzigen, signierten EFI-Binary. Das beseitigt gleich mehrere Angriffsvektoren der traditionellen Boot-Chain auf einen Schlag:
# UKI manuell mit ukify erstellen
/usr/lib/systemd/ukify build \
--linux=/boot/vmlinuz-6.12 \
--initrd=/boot/initramfs-6.12.img \
--cmdline="root=UUID=xxxx ro quiet" \
--os-release=@/etc/os-release \
--splash=/usr/share/systemd/bootctl/splash-arch.bmp \
--secureboot-private-key=/usr/share/secureboot/keys/db/db.key \
--secureboot-certificate=/usr/share/secureboot/keys/db/db.pem \
--pcr-private-key=/usr/share/secureboot/keys/tpm2-pcr-private.pem \
--pcr-banks=sha256 \
--output=/boot/EFI/Linux/arch-6.12.efi
# UKI-Erstellung automatisieren via /etc/kernel/install.d/
# oder über die Konfiguration in /etc/kernel/uki.conf
# kernel-install für automatische UKI-Erstellung konfigurieren
cat > /etc/kernel/install.conf <<'EOF'
layout=uki
initrd_generator=dracut
uki_generator=ukify
EOF
# UKI-spezifische Konfiguration
cat > /etc/kernel/uki.conf <<'EOF'
[UKI]
SecureBootSigningTool=/usr/bin/sbsign
SecureBootPrivateKey=/usr/share/secureboot/keys/db/db.key
SecureBootCertificate=/usr/share/secureboot/keys/db/db.pem
PCRPKey=/usr/share/secureboot/keys/tpm2-pcr-public.pem
EOF
# Bei der nächsten Kernelinstallation wird automatisch ein
# signiertes UKI erstellt und in der ESP abgelegt
Die Vorteile von UKIs auf einen Blick:
- Keine separate Kernel-Kommandozeile: Die Kommandozeile ist im UKI eingebettet und signiert. Ein Angreifer kann keine Boot-Parameter wie
init=/bin/basheinschleusen. - Kein separater Bootloader nötig: Das UKI wird direkt von der Firmware oder systemd-boot geladen. GRUB wird überflüssig — und damit auch dessen Angriffsfläche.
- TPM-PCR-Vorhersage: Die erwarteten PCR-Werte lassen sich im Voraus berechnen und für LUKS-Entschlüsselung nutzen.
- Atomare Updates: Ein neuer Kernel wird als einzelne Datei ausgeliefert — entweder ganz oder gar nicht.
Automatisierung und Compliance
OpenSCAP für Boot-Chain- und Service-Härtungsüberprüfung
OpenSCAP ist das Standard-Tool für automatisierte Compliance-Prüfungen unter Linux und unterstützt Profile wie CIS Benchmarks und DISA STIGs. Für regelmäßige Audits ist es quasi unverzichtbar:
# OpenSCAP installieren
# RHEL/Fedora:
dnf install openscap-scanner scap-security-guide
# Ubuntu/Debian:
apt install libopenscap8 ssg-debian ssg-ubuntu
# Verfügbare Profile anzeigen
oscap info /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml
# System gegen CIS-Benchmark scannen
oscap xccdf eval \
--profile cis_server_l1 \
--results scan-results.xml \
--report scan-report.html \
/usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml
# Bericht im Browser öffnen
xdg-open scan-report.html
Benutzerdefiniertes Audit-Skript für die gesamte Flotte
Für eine umfassende Prüfung von Boot-Chain-Sicherheit und Service-Härtung über viele Server hinweg habe ich ein Skript zusammengestellt, das Sie als Ausgangspunkt verwenden können:
#!/bin/bash
# boot-and-service-audit.sh
# Umfassendes Audit-Skript für Boot-Chain und Service-Härtung
set -euo pipefail
REPORT_FILE="/var/log/security-audit-$(date +%Y%m%d-%H%M%S).json"
HOSTNAME=$(hostname -f)
ERRORS=0
echo "{ \"hostname\": \"${HOSTNAME}\", \"timestamp\": \"$(date -Is)\", \"checks\": [" > "${REPORT_FILE}"
# --- Boot-Chain Checks ---
# 1. Secure Boot Status
SB_STATE=$(mokutil --sb-state 2>/dev/null || echo "nicht verfügbar")
if echo "${SB_STATE}" | grep -q "enabled"; then
SB_OK="true"
else
SB_OK="false"
((ERRORS++))
fi
echo " {\"check\": \"secure_boot\", \"status\": ${SB_OK}, \"detail\": \"${SB_STATE}\"}," >> "${REPORT_FILE}"
# 2. TPM 2.0 Verfügbarkeit
if [ -c /dev/tpm0 ]; then
TPM_OK="true"
TPM_DETAIL="TPM 2.0 device vorhanden"
else
TPM_OK="false"
TPM_DETAIL="Kein TPM-Device gefunden"
((ERRORS++))
fi
echo " {\"check\": \"tpm_available\", \"status\": ${TPM_OK}, \"detail\": \"${TPM_DETAIL}\"}," >> "${REPORT_FILE}"
# 3. Kernel-Lockdown-Modus
LOCKDOWN=$(cat /sys/kernel/security/lockdown 2>/dev/null || echo "nicht verfügbar")
if echo "${LOCKDOWN}" | grep -q "\[integrity\]\|confidentiality"; then
LD_OK="true"
else
LD_OK="false"
((ERRORS++))
fi
echo " {\"check\": \"kernel_lockdown\", \"status\": ${LD_OK}, \"detail\": \"${LOCKDOWN}\"}," >> "${REPORT_FILE}"
# --- Service-Härtungs-Checks ---
# 4. Alle Services mit hohem Exposure-Score finden
echo " {\"check\": \"service_hardening\", \"unsafe_services\": [" >> "${REPORT_FILE}"
FIRST=true
while IFS= read -r line; do
SERVICE=$(echo "$line" | awk '{print $1}')
SCORE=$(echo "$line" | awk '{print $2}')
# Score > 5.0 als unsicher betrachten
SCORE_INT=$(echo "$SCORE" | cut -d. -f1)
if [ "${SCORE_INT}" -ge 5 ] 2>/dev/null; then
if [ "${FIRST}" = true ]; then
FIRST=false
else
echo "," >> "${REPORT_FILE}"
fi
echo -n " {\"service\": \"${SERVICE}\", \"score\": \"${SCORE}\"}" >> "${REPORT_FILE}"
((ERRORS++))
fi
done < <(systemd-analyze security --no-pager 2>/dev/null | tail -n +2 | head -50)
echo "" >> "${REPORT_FILE}"
echo " ]}," >> "${REPORT_FILE}"
# 5. Shim-Version prüfen
SHIM_VER=$(rpm -q shim-x64 2>/dev/null || dpkg -l shim-signed 2>/dev/null | grep shim | awk '{print $3}' || echo "nicht installiert")
echo " {\"check\": \"shim_version\", \"version\": \"${SHIM_VER}\"}" >> "${REPORT_FILE}"
# Abschluss
echo "], \"total_errors\": ${ERRORS} }" >> "${REPORT_FILE}"
echo "Audit abgeschlossen. ${ERRORS} Probleme gefunden."
echo "Bericht gespeichert unter: ${REPORT_FILE}"
# Exit-Code spiegelt gefundene Probleme wider
exit $(( ERRORS > 0 ? 1 : 0 ))
Integration in CI/CD-Pipelines
Für Infrastructure-as-Code-Umgebungen gehören Sicherheitsprüfungen in die CI/CD-Pipeline — das ist keine Kür, sondern Pflicht. Hier ein Beispiel mit GitLab CI:
# .gitlab-ci.yml - Sicherheits-Checks für systemd Service-Units
stages:
- lint
- security
- deploy
systemd-unit-lint:
stage: lint
image: registry.example.com/systemd-toolbox:latest
script:
- |
# Alle Service-Unit-Dateien syntaktisch prüfen
for unit in deploy/systemd/*.service; do
echo "Prüfe ${unit}..."
systemd-analyze verify "${unit}" || exit 1
done
service-hardening-check:
stage: security
image: registry.example.com/systemd-toolbox:latest
script:
- |
# Temporäre systemd-Instanz für die Analyse starten
for unit in deploy/systemd/*.service; do
SERVICE_NAME=$(basename "${unit}")
cp "${unit}" /etc/systemd/system/
systemctl daemon-reload
# Sicherheitsbewertung prüfen
SCORE=$(systemd-analyze security "${SERVICE_NAME}" 2>/dev/null \
| grep "Overall exposure" \
| grep -oP '[\d.]+')
echo "${SERVICE_NAME}: Exposure Score = ${SCORE}"
# Pipeline fehlschlagen lassen, wenn Score > 4.0
if (( $(echo "${SCORE} > 4.0" | bc -l) )); then
echo "FEHLER: ${SERVICE_NAME} hat einen zu hohen Exposure Score!"
systemd-analyze security "${SERVICE_NAME}"
exit 1
fi
done
allow_failure: false
secure-boot-verification:
stage: security
tags:
- bare-metal # Benötigt physischen Zugang zu UEFI
script:
- |
# Alle Kernel- und Bootloader-Binaries verifizieren
sbctl verify
if [ $? -ne 0 ]; then
echo "FEHLER: Unsignierte Boot-Dateien gefunden!"
exit 1
fi
- |
# UKI-Integrität prüfen
for uki in /boot/EFI/Linux/*.efi; do
sbverify --cert /usr/share/secureboot/keys/db/db.pem "${uki}" || exit 1
echo "OK: ${uki} korrekt signiert"
done
Ansible-Playbook zur flottenweiten Service-Härtung
Wenn Sie die Härtung über eine ganze Serverflotte ausrollen wollen, ist Ansible Ihr bester Freund. Hier ein Playbook als Ausgangspunkt:
# harden-systemd-services.yml
---
- name: systemd Services härten
hosts: all
become: yes
vars:
hardening_directives:
- ProtectSystem=strict
- ProtectHome=yes
- PrivateTmp=yes
- NoNewPrivileges=yes
- ProtectKernelModules=yes
- ProtectKernelTunables=yes
- ProtectKernelLogs=yes
- ProtectControlGroups=yes
- RestrictNamespaces=yes
- RestrictSUIDSGID=yes
- LockPersonality=yes
- ProtectHostname=yes
- ProtectClock=yes
services_to_harden:
- name: nginx
extra_readwrite:
- /var/log/nginx
- /var/cache/nginx
- /run
capabilities:
- CAP_NET_BIND_SERVICE
- CAP_DAC_READ_SEARCH
- name: postgresql
extra_readwrite:
- /var/lib/postgresql
- /var/log/postgresql
- /run/postgresql
capabilities:
- CAP_DAC_READ_SEARCH
tasks:
- name: Erstelle systemd Override-Verzeichnis
file:
path: "/etc/systemd/system/{{ item.name }}.service.d"
state: directory
mode: '0755'
loop: "{{ services_to_harden }}"
- name: Schreibe Härtungs-Override-Datei
template:
src: hardening-override.conf.j2
dest: "/etc/systemd/system/{{ item.name }}.service.d/hardening.conf"
mode: '0644'
loop: "{{ services_to_harden }}"
notify: reload systemd
- name: Prüfe Service-Exposure-Score
command: "systemd-analyze security {{ item.name }}.service"
loop: "{{ services_to_harden }}"
register: security_scores
changed_when: false
handlers:
- name: reload systemd
systemd:
daemon_reload: yes
Fazit und Checkliste
Die Absicherung eines Linux-Systems ist kein einzelner Schalter, den man umlegt — es ist ein durchgängiger Prozess, der beim ersten Firmware-Befehl beginnt und sich bis zur Ausführung einzelner Dienste erstreckt. Was wir in diesem Leitfaden durchgegangen sind, bildet zusammen eine mehrstufige Verteidigungsstrategie (Defense in Depth). Das Versagen einer einzelnen Schicht führt dabei nicht zum Totalverlust.
Besonders dringend ist 2026 die Vorbereitung auf den Ablauf des Microsoft UEFI CA 2011-Zertifikats. Wer hier zu spät dran ist, riskiert ernsthafte Betriebsunterbrechungen. Genauso sollte die systematische Härtung aller systemd-Service-Units ab sofort zum Standard in jedem Deployment-Prozess gehören.
Vollständige Sicherheits-Checkliste
Boot-Chain-Sicherheit:
- UEFI Secure Boot ist aktiviert und verifiziert (
mokutil --sb-state) - Eigene Secure-Boot-Schlüssel sind erstellt und eingerollt (oder die Distributions-Schlüssel sind aktuell)
- Alle Kernel-Images und Bootloader sind kryptografisch signiert
- Die DBX-Datenbank ist aktuell und widerruft bekannte unsichere Bootloader
- Shim und GRUB sind auf die neueste Version aktualisiert (Microsoft UEFI CA 2023-Kompatibilität)
- DKMS-Module werden automatisch nach jedem Build signiert
- Ein Rollback-Plan für fehlgeschlagene Secure-Boot-Updates existiert
TPM und Measured Boot:
- TPM 2.0 ist aktiviert und vom System erkannt
- Measured Boot ist aktiv und PCR-Werte werden korrekt geschrieben
- LUKS-Volumes sind an TPM-PCR-Werte gebunden (mindestens PCR 0, 1, 4, 7)
- PCR-Referenzwerte werden dokumentiert und bei Updates aktualisiert
- systemd-creds wird für sensitive Dienstzugangsdaten verwendet
Unified Kernel Images:
- UKIs werden für alle produktiven Systeme erstellt
- Die Kernel-Kommandozeile ist im UKI eingebettet (keine externe Manipulation möglich)
- ukify und kernel-install sind für automatische UKI-Erstellung konfiguriert
- UKIs sind mit den eigenen Secure-Boot-Schlüsseln signiert
systemd Service-Härtung:
- Alle produktiven Services haben einen Exposure-Score unter 4.0
- Kritische Direktiven sind gesetzt:
ProtectSystem=strict,NoNewPrivileges=yes,PrivateTmp=yes - Kernel-Schutzdirektiven sind aktiviert:
ProtectKernelModules,ProtectKernelTunables,ProtectKernelLogs SystemCallFilter=ist auf die minimal notwendigen Systemaufrufe beschränktCapabilityBoundingSet=enthält nur die wirklich benötigten CapabilitiesReadWritePaths=beschränkt den Schreibzugriff auf die notwendigen VerzeichnisseDynamicUser=yeswird wo immer möglich eingesetztRestrictNamespaces=yesundRestrictAddressFamilies=sind konfiguriert
Automatisierung und Compliance:
- OpenSCAP-Scans laufen regelmäßig (mindestens wöchentlich)
- Das Boot-Chain-Audit-Skript wird auf allen Systemen ausgeführt
- CI/CD-Pipelines prüfen Exposure-Scores vor dem Deployment
- Ansible oder ein vergleichbares Tool rollt Härtungsmaßnahmen flottenübergreifend aus
- Abweichungen von der Baseline werden automatisch erkannt und gemeldet
- Alle Sicherheitsmaßnahmen sind als Code versioniert und reproduzierbar
Zum Schluss: Sicherheit ist kein einmaliges Projekt, sondern ein fortlaufender Prozess. Die Bedrohungslandschaft entwickelt sich ständig weiter — und Ihre Verteidigung muss das auch tun. Planen Sie regelmäßige Reviews Ihrer Boot-Chain-Konfiguration und Service-Härtung ein, bleiben Sie bei neuen Kernel-CVEs und Firmware-Updates am Ball. Die Werkzeuge und Techniken aus diesem Leitfaden geben Ihnen das Fundament, um Ihre Linux-Infrastruktur auch 2026 und darüber hinaus wirksam zu schützen.