Linux-Server-Hardening: Sicherheits-Checkliste für KMU
CIS-Benchmarks, SELinux/AppArmor, auditd, automatische Updates und Fail2ban richtig kombinieren, um Linux-Server im KMU-Umfeld nachhaltig abzusichern.
Warum Hardening kein “Nice-to-have” ist
Ein frisch installierter Linux-Server ist nie fertig gehärtet – egal ob Ubuntu Server, Debian oder RHEL/Rocky. Die Standard-Installation priorisiert Kompatibilität und Bedienbarkeit, nicht Sicherheit. Genau das nutzen automatisierte Scanner aus: Innerhalb von Minuten nach dem ersten Internet-Kontakt registrieren SSH-Ports auf ungeschützten Servern tausende Brute-Force-Versuche pro Tag.
Für ein Schweizer KMU mit begrenztem IT-Team bedeutet das: Du kannst nicht jeden Server manuell nach Bauchgefühl absichern. Du brauchst eine wiederholbare, dokumentierte und im Idealfall automatisierte Checkliste – genau das liefern CIS-Benchmarks in Kombination mit den Werkzeugen in diesem Artikel.
CIS-Benchmark-Grundlagen
Das Center for Internet Security (CIS) veröffentlicht für praktisch jede relevante Distribution einen eigenen Benchmark – kostenlos als PDF unter cisecurity.org, mit rund 150–300 Einzelkontrollen je nach OS und Version. Die Kontrollen sind in zwei Profile aufgeteilt:
- Level 1 (L1): Praxistaugliche Basis-Härtung ohne relevante Funktionseinbussen. Für praktisch jeden Server geeignet – das ist dein Startpunkt.
- Level 2 (L2): Defense-in-Depth für Hochsicherheitsumgebungen. Kann Funktionalität einschränken (z.B. deaktivierte USB-Speicher, sehr restriktive Kernel-Parameter) – vorher testen.
Jede Kontrolle folgt demselben Schema: Beschreibung, Rationale, Audit-Befehl (wie prüfst du den Ist-Zustand), Remediation (wie behebst du Abweichungen) und Referenzen (z.B. MITRE ATT&CK, NIST 800-53).
Typische L1-Kontrollen im Überblick
| Bereich | Beispielkontrolle | Prüfbefehl |
|---|---|---|
| Dateisystem | /tmp mit noexec,nosuid mounten | mount | grep /tmp |
| Kernel-Module | Unnötige Protokolle (z.B. dccp, sctp) deaktivieren | modprobe -n -v dccp |
| Netzwerk | IP-Forwarding aus, wenn kein Router | sysctl net.ipv4.ip_forward |
| SSH | Root-Login per Passwort verboten | sshd -T | grep permitrootlogin |
| Auditing | auditd aktiv und Regeln geladen | auditctl -s |
| Zugriff | Passwort-Ablauf max. 365 Tage | grep PASS_MAX_DAYS /etc/login.defs |
| Dienste | Unnötige Dienste deaktiviert (avahi, cups, rpcbind) | systemctl is-enabled avahi-daemon |
Compliance automatisiert prüfen: OpenSCAP und Lynis
Statt jede Kontrolle manuell durchzuklicken, nutzt du Scanner, die gegen den Benchmark prüfen:
# OpenSCAP: offizielle SCAP-Content-Pakete für RHEL/Rocky/Ubuntu
sudo dnf install -y openscap-scanner scap-security-guide
# Verfügbare Profile auflisten (u.a. CIS-Profile)
oscap info /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml
# CIS-Level-1-Scan fahren und HTML-Report erzeugen
sudo oscap xccdf eval \
--profile xccdf_org.ssgproject.content_profile_cis \
--report /root/cis-report.html \
/usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml
# Lynis: schnellerer, distributionsunabhängiger Health-Check
sudo apt install -y lynis # Debian/Ubuntu
sudo lynis audit system
# Ergebnis: Hardening-Index (0-100) + priorisierte Empfehlungen
# Logfile für spätere Auswertung:
cat /var/log/lynis-report.dat
Lynis liefert dir einen “Hardening Index” als Kennzahl – ideal, um Fortschritt über Zeit zu dokumentieren (z.B. für interne Audits oder Kundennachweise). OpenSCAP ist formaler und mappt direkt auf CIS-Kontrollnummern, was für externe Auditoren oft verlangt wird.
SELinux vs. AppArmor: Mandatory Access Control richtig einsetzen
Klassische Unix-Rechte (rwx für User/Group/Other) sind Discretionary Access Control (DAC) – der Dateibesitzer entscheidet über Zugriff. Das Problem: Wird ein Prozess kompromittiert (z.B. eine verwundbare Webanwendung), erbt der Angreifer automatisch alle Rechte dieses Prozesses. Mandatory Access Control (MAC) setzt eine zusätzliche, vom Kernel erzwungene Ebene darüber, die selbst root nicht ohne Weiteres umgehen kann.
Beide Systeme sind Kernel-Module (Linux Security Modules, LSM) und schliessen sich gegenseitig aus – du kannst nicht beide gleichzeitig aktiv nutzen.
| Kriterium | SELinux | AppArmor |
|---|---|---|
| Modell | Label-basiert (Security-Context je Datei/Prozess) | Pfad-basiert (Profile pro Programmpfad) |
| Standard bei | RHEL, Rocky Linux, AlmaLinux, Fedora, CentOS Stream | Ubuntu, Debian, SUSE, openSUSE |
| Lernkurve | Steil – Contexts, Types, Booleans, Policy-Module | Flacher – Profile lesen sich fast wie Klartext |
| Granularität | Sehr fein (auch Netzwerk-Sockets, Capabilities) | Gröber, dateisystemorientiert |
| Troubleshooting | audit2allow, ausearch, SELinux-Logs in auditd | aa-logprof, dmesg, eigenes AppArmor-Log |
| Container-Isolation | Stärker (MCS trennt Container sauber voneinander) | Schwächer, kein MCS-Äquivalent |
| Typischer Modus in Produktion | enforcing | enforce |
SELinux in der Praxis
# Aktuellen Modus prüfen
getenforce
# Ergebnis: Enforcing / Permissive / Disabled
# Temporär auf Permissive schalten (nur für Troubleshooting!)
sudo setenforce 0
# Dauerhaft in /etc/selinux/config setzen
sudo sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config
# Security-Context einer Datei anzeigen
ls -Z /var/www/html/index.html
# Häufigstes Problem: Webserver kann Datei nicht lesen, obwohl DAC-Rechte passen
sudo semanage fcontext -a -t httpd_sys_content_t "/srv/webdata(/.*)?"
sudo restorecon -Rv /srv/webdata
# Verweigerte Zugriffe der letzten Stunde analysieren
sudo ausearch -m avc -ts recent
# Sauberer Workflow: aus Denials ein eigenes Policy-Modul bauen
sudo ausearch -m avc -ts recent | audit2allow -M mein_modul
sudo semodule -i mein_modul.pp
AppArmor in der Praxis
# Status und geladene Profile anzeigen
sudo aa-status
# Profil eines Programms im "complain mode" testen (loggt, blockiert aber nicht)
sudo aa-complain /usr/sbin/nginx
# Nach Testphase in den Enforce-Modus wechseln
sudo aa-enforce /usr/sbin/nginx
# Profil aus geloggten Ereignissen interaktiv verfeinern
sudo aa-logprof
Entscheidungshilfe für den KMU-Alltag: Bleib auf der Distribution, die dein Team bereits kennt – ein schlecht gepflegtes SELinux-System (weil “disabled” gesetzt) ist schlechter als ein sauber konfiguriertes AppArmor-System. Wenn du frei wählst und Container-Workloads (Docker/Kubernetes) im Fokus stehen, spricht die stärkere Container-Isolation für RHEL-Familie mit SELinux.
auditd: Sicherheitsrelevante Ereignisse lückenlos protokollieren
Standard-Syslog protokolliert, dass etwas passiert ist (“Service gestartet”). auditd protokolliert wer wann was mit welcher Datei oder welchem Systemaufruf gemacht hat – bis auf Kernel-Ebene, unveränderbar für normale User, und das ist genau das, was du für Incident-Response und Compliance-Nachweise brauchst.
# Installation (meist vorinstalliert, sonst nachholen)
sudo apt install -y auditd audispd-plugins # Debian/Ubuntu
sudo dnf install -y audit audit-libs # RHEL/Rocky
# Dienst aktivieren
sudo systemctl enable --now auditd
Sinnvolle Basis-Regeln für KMU-Server
Regeln liegen in /etc/audit/rules.d/ (persistente Regeln, überleben Neustart und werden von augenrules kompiliert):
# /etc/audit/rules.d/hardening.rules
## Alle Änderungen an Nutzer- und Gruppendatenbanken
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/group -p wa -k identity
-w /etc/sudoers -p wa -k sudoers_change
-w /etc/sudoers.d/ -p wa -k sudoers_change
## SSH-Konfigurationsänderungen
-w /etc/ssh/sshd_config -p wa -k sshd_config
## Fehlgeschlagene Zugriffsversuche auf Dateien (EACCES/EPERM)
-a always,exit -F arch=b64 -S open,openat -F exit=-EACCES -F auid>=1000 -F auid!=4294967295 -k access_denied
## Nutzung von privilegierten Befehlen (Rechteausweitung nachvollziehbar machen)
-a always,exit -F arch=b64 -S execve -F path=/usr/bin/sudo -k privilege_escalation
## Änderungen an Systemzeit (typisch bei Log-Manipulation)
-a always,exit -F arch=b64 -S adjtimex,settimeofday,clock_settime -k time_change
## Regeln nach dem Booten unveränderbar machen (nur nach ausgiebigem Testen!)
-e 2
# Regeln laden und Status prüfen
sudo augenrules --load
sudo auditctl -l
sudo systemctl restart auditd
# Ereignisse durchsuchen
sudo ausearch -k sudoers_change
sudo ausearch -k identity --start today
# Kompakte Zusammenfassung pro Regel-Key
sudo aureport --summary
sudo aureport -au # Authentifizierungs-Report
Die Zeile -e 2 am Ende macht die Audit-Konfiguration erst nach einem Neustart wieder änderbar – das verhindert, dass ein Angreifer mit root-Rechten seine Spuren durch Anpassen der Audit-Regeln verwischt. Setze das aber erst produktiv, wenn du sicher bist, dass die Regeln stimmen, sonst brauchst du für jede Anpassung einen Reboot.
Automatische Sicherheitsupdates: unattended-upgrades und dnf-automatic
Die statistisch häufigste Einfallschneise ist keine Zero-Day-Lücke, sondern eine seit Monaten bekannte, ungepatchte CVE. Automatisierte Security-Updates schliessen dieses Fenster, ohne dass du jeden Server einzeln per Hand patchen musst.
Debian/Ubuntu: unattended-upgrades
sudo apt install -y unattended-upgrades apt-listchanges
sudo dpkg-reconfigure --priority=low unattended-upgrades
# /etc/apt/apt.conf.d/50unattended-upgrades (Auszug)
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
"${distro_id}ESMApps:${distro_codename}-apps-security";
};
// Automatischer Reboot bei kernelrelevanten Updates
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "03:30";
// Nicht mehr benötigte Pakete gleich mit entfernen
Unattended-Upgrade::Remove-Unused-Dependencies "true";
// Bei Fehlern Mail an das IT-Team
Unattended-Upgrade::Mail "it-team@firma.ch";
Unattended-Upgrade::MailOnlyOnError "true";
# /etc/apt/apt.conf.d/20auto-upgrades
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
# Trockenlauf zur Kontrolle, bevor produktiv aktiviert wird
sudo unattended-upgrade --dry-run --debug
RHEL/Rocky/AlmaLinux: dnf-automatic
sudo dnf install -y dnf-automatic
# /etc/dnf/automatic.conf (Auszug)
[commands]
upgrade_type = security
apply_updates = yes
[emitters]
emit_via = stdio,command
sudo systemctl enable --now dnf-automatic.timer
systemctl list-timers dnf-automatic.timer
Für reine Nicht-Security-Updates (Funktions-Updates, neue Major-Versionen) empfiehlt sich weiterhin ein manuell getriggerter, getesteter Patch-Zyklus über eine zentrale Lösung – Details dazu unter WSUS & Patchmanagement (Prinzipien lassen sich auf Linux-Pendants wie Landscape oder Foreman/Katello übertragen).
Fail2ban und Intrusion Detection
Fail2ban überwacht Logdateien (SSH, Webserver, Mailserver, …) auf wiederholte Fehlversuche und sperrt die Quell-IP automatisch über die lokale Firewall. Es ersetzt keine echte Intrusion-Detection, reduziert aber automatisierte Brute-Force-Kampagnen drastisch – oft der grösste Teil des ungewollten Traffics auf öffentlich erreichbaren SSH-Ports.
sudo apt install -y fail2ban # Debian/Ubuntu
sudo dnf install -y fail2ban # RHEL/Rocky (Repo epel-release ggf. nötig)
# /etc/fail2ban/jail.local – NIEMALS jail.conf direkt editieren
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
# Eigene Management-IPs und VPN-Range nie sperren
ignoreip = 127.0.0.1/8 ::1 10.20.0.0/24
[sshd]
enabled = true
port = 2222
backend = systemd
[recidive]
# Wiederholungstäter (mehrfach gebannt) langfristig aussperren
enabled = true
bantime = 1w
findtime = 1d
maxretry = 5
sudo systemctl enable --now fail2ban
# Aktive Jails und gebannte IPs prüfen
sudo fail2ban-client status
sudo fail2ban-client status sshd
# IP manuell entsperren (z.B. eigener Aussendienst-Mitarbeiter ausgesperrt)
sudo fail2ban-client set sshd unbanip 203.0.113.44
Einordnung: Fail2ban vs. echte Intrusion Detection
Fail2ban ist reaktiv und regelbasiert (Log-Pattern-Matching), keine verhaltensbasierte Erkennung. Für tiefere Sichtbarkeit ergänzt du je nach Schutzbedarf:
| Werkzeug | Funktion | Einsatzschwerpunkt |
|---|---|---|
| Fail2ban | Log-Pattern → IP-Ban via Firewall | Brute-Force auf SSH/Web/Mail |
| AIDE / Tripwire | Datei-Integritätsprüfung (Host-based IDS) | Erkennung veränderter Binaries/Configs |
| Wazuh / OSSEC | Log-Korrelation, File Integrity, Rootkit-Check | Zentrales HIDS über viele Server |
| CrowdSec | Community-basierte, verteilte Bedrohungserkennung | Ergänzung/Ersatz für Fail2ban mit Threat-Intel |
| auditd + SIEM | Kernel-nahe Ereignisprotokollierung | Forensik, Compliance, Nachvollziehbarkeit |
Für ein typisches Schweizer KMU mit 5-30 Linux-Servern ist die Kombination Fail2ban + auditd + zentrales Log-Shipping in ein leichtgewichtiges SIEM (siehe SIEM & SOC Grundlagen) meist der richtige Sweet Spot zwischen Aufwand und Nutzen. AIDE lohnt sich zusätzlich für Server mit hohem Schutzbedarf (z.B. Zertifizierungsstelle, Finanzsysteme).
Minimal-Installation und Angriffsfläche reduzieren
Jeder installierte Dienst, jedes offene Paket ist potenzielle Angriffsfläche – auch wenn er “nur zufällig mitinstalliert” wurde. Das Prinzip lautet: so wenig wie möglich, so viel wie nötig.
Schritt-für-Schritt-Ablauf bei der Erstinstallation
- Minimal-ISO/Cloud-Image wählen statt Desktop- oder “Everything”-Variante (z.B.
ubuntu-24.04-live-server, RHEL “Minimal Install”-Gruppe). - Partitionierung mit getrennten Mountpoints –
/tmp,/var/log,/homeseparat mounten, damit du dortnoexec,nosuid,nodevsetzen kannst. - Unnötige Pakete direkt nach Installation entfernen:
# Unbenutzte Netzwerkdienste identifizieren sudo systemctl list-unit-files --state=enabled | grep -E 'avahi|cups|rpcbind' sudo systemctl disable --now avahi-daemon cups rpcbind sudo apt purge -y avahi-daemon cups rpcbind - Offene Ports inventarisieren und alles ohne klaren Zweck schliessen:
sudo ss -tulpn sudo firewall-cmd --list-all # RHEL/firewalld sudo ufw status verbose # Ubuntu/ufw - Unnötige Kernel-Module blockieren (Beispiel: seltene Netzwerkprotokolle, USB-Storage auf Servern ohne physischen Zugriff):
# /etc/modprobe.d/hardening.conf install dccp /bin/false install sctp /bin/false install usb-storage /bin/false - Root-Login und unnötige lokale Accounts deaktivieren:
sudo passwd -l root sudo usermod -L -e 1 gast_account # Sofort ablaufen lassen statt löschen (Audit-Spur) - Automatisierten Scan zur Bestätigung fahren (Lynis/OpenSCAP wie oben) und Ergebnis dokumentieren.
Entscheidungsbaum: Wie aggressiv härte ich diesen Server?
Ist der Server aus dem Internet erreichbar (Port 22/443 offen)?
├── Ja → CIS L1 + L2 wo praktikabel, Fail2ban Pflicht, auditd mit vollen Regeln,
│ automatische Security-Updates, MAC im enforcing/enforce-Modus
└── Nein, nur internes LAN
├── Verarbeitet er Finanz-/Personendaten (DSG/DSGVO-relevant)?
│ ├── Ja → CIS L1 + ausgewählte L2-Kontrollen, auditd Pflicht,
│ │ Updates automatisiert mit Testfenster, MAC enforcing
│ └── Nein → CIS L1 als Baseline, auditd Basis-Regeln,
│ Updates automatisiert, MAC im Default-Modus der Distro belassen
Checkliste zum Abhaken
- Minimal-Installation verwendet, unnötige Pakete/Dienste entfernt
- SSH: Key-Auth erzwungen, Root-Login und Passwort-Login deaktiviert, Port ggf. geändert
- Firewall aktiv mit Default-Deny-Policy (ufw/firewalld/nftables)
- MAC-System (SELinux/AppArmor) im enforcing/enforce-Modus, nicht disabled
- auditd aktiv mit Basis-Regeln für
/etc/passwd,/etc/sudoers, SSH-Config - Automatische Security-Updates konfiguriert und getestet (Dry-Run geprüft)
- Fail2ban aktiv für SSH und alle exponierten Dienste,
ignoreipkorrekt gepflegt - Lynis/OpenSCAP-Scan durchgeführt, Ergebnis dokumentiert und Baseline festgehalten
- Getrennte Partitionen für
/tmp,/var/log,/homemitnoexec/nosuidwo sinnvoll - Zentrales Log-Shipping an SIEM/Log-Server eingerichtet
Weiterlernen
- CIS Benchmarks – offizielle Übersicht
- Red Hat: SELinux User’s and Administrator’s Guide
- AppArmor Wiki (offizielles Projekt)
- Red Hat: Configure Linux system auditing with auditd
- Ubuntu Server Guide: Automatic Updates
- Fail2ban – offizielles GitHub-Repository
Verwandte Themen: SSH – Grundlagen & Schlüsselverwaltung, Linux Firewall: iptables & nftables, SIEM & SOC Grundlagen, NIS-2 für KMU Schweiz, Ansible: Playbooks, Inventory, Vault, IT-Security Grundlagen für KMU
Kommentare
Frage, Verbesserungsvorschlag oder eigene Erfahrung zu diesem Artikel? Schreib einen Kommentar. Neue Beiträge erscheinen nach kurzer Moderation.
- Lade Kommentare …