Sobald Login per SSH-Key funktioniert und ein eigener Benutzer mit sudo-Rechten existiert, kommt der Härtungs-Schritt. Ziel: einen frischen Server so konfigurieren, dass automatisierte Brute-Force-Versuche keinerlei Angriffsfläche finden — Passwort-Login komplett aus, Zugriff auf bestimmte Benutzer beschränkt, MaxAuthTries und LoginGraceTime straff gesetzt, fail2ban als Fallback. Plus: ehrliche Einschätzung, ob der Port-Wechsel wirklich etwas bringt.

Warum SSH härten — auch mit Key-Login?

Wenn der Login bereits per Key läuft, sind klassische Passwort-Brute-Force-Angriffe ohnehin chancenlos. Trotzdem sind weitere Schritte sinnvoll:

  • Defense in Depth. Sicherheit basiert nicht auf einer einzigen Schicht. Falls ein privater Schlüssel kompromittiert wird oder eine OpenSSH-Schwachstelle auftritt, helfen die zusätzlichen Schichten, das Zeitfenster zu verkürzen.
  • Log-Hygiene. Ein offener SSH-Port wird ständig durchprobiert. Selbst wenn die Versuche scheitern, fluten sie die Logs und machen echte Anomalien schwer auffindbar. Hardening reduziert die Log-Last drastisch.
  • Compliance & Audit. Wenn der Server für Kunden- oder Geschäftsdaten genutzt wird, wird oft ein nachweislich abgesicherter SSH-Zugang verlangt — egal, ob praktisch nötig oder nicht.

Die Schritte hier sind drop-in-konform: alle Änderungen landen in /etc/ssh/sshd_config.d/, nicht in der Hauptdatei. Das vermeidet Konflikte mit Distro-Updates.

Passwort-Login komplett deaktivieren

Die kritischste Maßnahme. Solange der Server Passwörter akzeptiert, läuft im Hintergrund permanent ein Brute-Force-Wettlauf — auch wenn dein Account längst Key-only nutzt, bleiben System-Accounts wie admin, ubuntu, git ein attraktives Ziel.

Bash
sudo nano /etc/ssh/sshd_config.d/10-hardening.conf
Konfiguration /etc/ssh/sshd_config.d/10-hardening.conf
# Authentifizierung
PasswordAuthentication       no
KbdInteractiveAuthentication no
ChallengeResponseAuthentication no
UsePAM                       yes
PermitEmptyPasswords         no

Erklärung der einzelnen Zeilen:

  • PasswordAuthentication no — kein Passwort-Login, ausschließlich Key.
  • KbdInteractiveAuthentication no — schließt eine zweite Tür, durch die manche Distros sonst doch wieder Passwörter durchlassen (PAM-basiert).
  • ChallengeResponseAuthentication no — Legacy-Variante derselben Tür, sicherheitshalber explizit aus.
  • UsePAM yes — bleibt an, weil PAM für Account-Lockout, lastlog usw. zuständig ist. Sicherheitsrisiko ist es nur in Verbindung mit aktivem KbdInteractiveAuthentication.
  • PermitEmptyPasswords no — sollte nie auf yes stehen. Doppelt absichern schadet nicht.

Login-Versuche und Zeitfenster begrenzen

Ein Angreifer mit einem gestohlenen Key-Auswahl-Set kann pro Verbindung mehrere Keys ausprobieren. Außerdem hält ein nicht-authentifizierender Verbindungsversuch eine Slot offen — knappe Zeit-/Versuchs-Limits sind eine billige zweite Schicht.

Konfiguration /etc/ssh/sshd_config.d/10-hardening.conf (Fortsetzung)
# Versuche & Zeitfenster
MaxAuthTries     3
MaxSessions      4
LoginGraceTime   30
  • MaxAuthTries 3 — pro Verbindung maximal 3 Authentifizierungs-Versuche (Default 6). Bei 3 Versuchen wird die Verbindung getrennt.
  • MaxSessions 4 — maximal 4 parallele Multiplex-Sessions pro Verbindung. Default 10 ist großzügig; 4 reicht für die meisten realen Szenarien.
  • LoginGraceTime 30 — der Server schließt nicht authentifizierte Verbindungen nach 30 Sekunden. Default 120 ist zu großzügig — Brute-Force-Tools profitieren von langen Grace-Zeiten.

Zugriffsliste — wer darf überhaupt einloggen

Standardmäßig darf sich jeder Linux-Benutzer per SSH einloggen, sofern er einen Key hat. Auf einem produktiven Server ist das selten gewünscht — Service-Accounts (www-data, postgres, redis) sollen sich definitiv nicht interaktiv einloggen können.

Zwei Mechanismen, einer reicht meistens:

Konfiguration /etc/ssh/sshd_config.d/10-hardening.conf (Fortsetzung)
# Variante A — Whitelist über User-Namen
AllowUsers max alice

# Variante B — Whitelist über Gruppe (saubere Variante)
# AllowGroups ssh-users

AllowUsers ist der direkte Weg — perfekt, wenn nur eine Handvoll Personen Zugriff haben. AllowGroups skaliert besser: einmal eine Gruppe ssh-users anlegen, jeden berechtigten Account in die Gruppe aufnehmen, fertig.

Gruppe anlegen (nur falls Variante B):

Bash
sudo groupadd ssh-users
sudo usermod -aG ssh-users max

Wichtig: Sobald AllowUsers oder AllowGroups gesetzt sind, darf nur noch wer hier gelistet ist einloggen. Vergiss nicht, deinen eigenen Account hinzuzufügen — sonst sperrst du dich aus.

Port-Wechsel — bringt das was?

Der Port-Wechsel (Standard 22 auf etwas wie 22022 oder 2222) ist ein dauernd diskutiertes Thema. Ehrliche Einordnung:

Was ein Port-Wechsel tatsächlich bringt:

  • Drastisch weniger Logs. Das Internet-Untergrund-Skript-Repertoire pingt fast ausschließlich Port 22. Auf einem anderen Port verschwindet 90 % des Hintergrundrauschens.
  • Niedrigere CPU-Last. Jeder Verbindungsversuch kostet Krypto-Operationen. Auf einem kleinen VPS macht das einen messbaren Unterschied.

Was es nicht bringt:

  • Keine echte Sicherheit. Ein zielgerichteter Angreifer scannt alle 65535 Ports in unter einer Minute mit nmap oder masscan. Security-through-Obscurity allein hält niemanden auf.

Empfehlung: Wenn du den Port wechselst, dann nicht auf 2222 (gängigster Alternativ-Port — wird auch gescannt), sondern auf eine zufällige Zahl im 1024–49151-Range:

Konfiguration /etc/ssh/sshd_config.d/10-hardening.conf (Fortsetzung)
Port 47823

Firewall öffnen (Beispiel ufw):

Bash
sudo ufw allow 47823/tcp
# erst neuen Port testen, dann alten Port (22) schließen:
sudo ufw delete allow 22/tcp

Im Provider-Panel ggf. Cloud-Firewall ebenfalls anpassen. Und: ~/.ssh/config lokal aktualisieren, damit der Alias den neuen Port kennt.

fail2ban als Fallback

fail2ban liest SSH-Logs, erkennt wiederholte Fehlversuche und sperrt die Quell-IP per iptables/nftables. Auch wenn Passwort-Login aus ist, sperrt es Scanner aus, die mit ungültigen Keys/Usernames spammen.

Installation:

Bash Debian / Ubuntu
sudo apt install fail2ban -y
Bash RHEL-Familie
sudo dnf install epel-release -y
sudo dnf install fail2ban -y

Die Standard-Konfiguration /etc/fail2ban/jail.conf niemals direkt editieren — sie wird durch Updates überschrieben. Eigene Konfiguration kommt in /etc/fail2ban/jail.local:

Konfiguration /etc/fail2ban/jail.local
[DEFAULT]
# IPs, die nie gesperrt werden (eigene IP eintragen!)
ignoreip = 127.0.0.1/8 ::1

# Bantime, Findtime, Maxretry
bantime  = 1h
findtime = 10m
maxretry = 5

# Backend: systemd-journal statt /var/log
backend  = systemd

[sshd]
enabled = true
# bei nicht-Standard-Port: hier nachziehen
port    = ssh

Erklärung:

  • bantime 1h — gesperrte IP bleibt 1 Stunde gesperrt.
  • findtime 10m + maxretry 5 — 5 Fehlversuche in 10 Minuten triggern den Bann.
  • backend systemd — moderne Distros loggen über journald, nicht in /var/log/auth.log.

Service starten und Status prüfen:

Bash
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd

Konfiguration testen und übernehmen

Vor jedem Reload die Konfiguration validieren — ein Tippfehler in einer Hardening-Datei kann den SSH-Service crashen, was bei laufender Verbindung noch keine Aussperrung bedeutet, beim nächsten Restart aber sehr wohl.

Bash
sudo sshd -t

Kein Output = alles gut. Bei Fehlern wird die fehlerhafte Direktive samt Datei und Zeilennummer gemeldet.

Effektive Konfiguration prüfen — alle Defaults plus Drop-Ins zusammengefasst:

Bash
sudo sshd -T | grep -iE 'password|maxauth|allowusers|port|logingrace'

Wenn alles passt, reload (kein restart) — bestehende Sessions laufen weiter:

Bash
sudo systemctl reload ssh    # Debian/Ubuntu
sudo systemctl reload sshd   # RHEL-Familie

Verifikation aus einer zweiten Session — vor dem Schließen der ersten:

Bash lokaler Rechner
ssh max@203.0.113.42
# erfolgreicher Key-Login; falls Port geändert: -p <neuer port>

Sicherheits-Checkliste

  • PasswordAuthentication no und KbdInteractiveAuthentication no gesetzt, mit sshd -T verifiziert
  • MaxAuthTries 3, LoginGraceTime 30, MaxSessions 4 aktiv
  • AllowUsers oder AllowGroups gesetzt, eigener Account dort gelistet
  • Service-Accounts (www-data, postgres …) nicht in der Whitelist
  • Falls Port-Wechsel: Provider-Firewall und Host-Firewall (ufw/firewalld) angepasst, alter Port geschlossen
  • fail2ban läuft, fail2ban-client status sshd zeigt aktiven Jail
  • sshd -t bestanden, reload statt restart benutzt
  • Zweite Test-Session vor Verbindungs-Trennung erfolgreich

Häufige Fehler beim SSH-Hardening

Hauptdatei sshd_config editiert

Distros laden via Include /etc/ssh/sshd_config.d/*.conf. Eigene Direktiven gehören in eine Drop-in-Datei dort — im Hauptfile werden sie früher oder später durch Distro-Updates überschrieben oder geraten in Konflikt mit dem Default-Set.

AllowUsers ohne eigenen Account

Klassischer Self-Lock. Vor dem Reload zwingend prüfen, dass der eigene Username (oder die eigene Gruppe) in der Whitelist steht. Eine zweite SSH-Session offen lassen, falls der Reload schiefgeht.

fail2ban mit zu strengem Limit und vergessener Eigen-IP

Wenn bantime/maxretry knapp gesetzt sind und die eigene Heim-IP nicht in ignoreip steht, kann ein versehentlich kaputter Login zum Self-Bann führen. Eigene IP unbedingt freischalten — oder per VPN/Provider-Konsole einen Backup-Pfad sicherstellen.

Port-Wechsel ohne Firewall-Anpassung

Server lauscht auf dem neuen Port, ufw oder die Provider-Firewall lassen aber nur 22 durch — Login schlägt fehl, ohne dass es nach einem SSH-Problem aussieht. Beide Firewall-Schichten anpassen, alten Port erst nach erfolgreichem Test schließen.

PermitRootLogin yes vergessen abzuschalten

Wenn der Schritt aus dem User-/sudo-Artikel übersprungen wurde, ist der root-Zugang trotz Hardening weiter offen. Hier mit nachziehen: PermitRootLogin no in der Drop-in-Datei.

backend = auto in fail2ban auf systemd-Distros

Auf Distros, die nicht mehr in /var/log/auth.log schreiben (Ubuntu 22.04+ ohne rsyslog), findet auto keine Log-Quelle und fail2ban schweigt. backend = systemd ist heute der korrekte Default für moderne Systeme.

Verwandte Artikel

Externe Quellen

/ Weiter

Zurück zu Server-Bootstrap

Zur Übersicht