Keys, Config und Härtung für produktive Linux-Server
Server, die SSH ausschließlich mit Passwort-Login und offenem Root-Zugang betreiben, sind ein bevorzugtes Ziel automatisierter Brute-Force-Angriffe aus dem gesamten Internet. Dieser Artikel zeigt praxisnah, wie Key-basierte Authentifizierung, eine konsequent gehärtete sshd_config, saubere Client-Konfiguration über host-spezifische Einträge und fail2ban als ergänzende Schutzschicht SSH-Zugänge auf produktiven Linux-Servern zuverlässig und dauerhaft absichern, ganz ohne exotische Zusatztools.
Inhaltsverzeichnis
- 1. Warum SSH die wichtigste Angriffsfläche ist
- 2. Key-basierte Authentifizierung statt Passwörter
- 3. sshd_config härten: PermitRootLogin und PasswordAuthentication
- 4. Protokoll- und Verschlüsselungsrestriktionen
- 5. Client-Konfiguration mit ~/.ssh/config
- 6. SSH-Agent und Key-Management
- 7. Ergänzender Schutz: fail2ban gegen Brute-Force
- 8. Monitoring und Logging von SSH-Zugriffen
- 9. SSH-Härtung im direkten Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Warum SSH die wichtigste Angriffsfläche ist
Auf praktisch jedem produktiven Linux-Server ist SSH der einzige offene Verwaltungszugang nach außen, und genau deshalb ist er das bevorzugte Ziel automatisierter Angriffe. Wer die Logs eines frisch aufgesetzten Servers mit offenem Port 22 beobachtet, sieht innerhalb weniger Minuten die ersten Brute-Force-Versuche aus Botnetzen, die systematisch Standardbenutzernamen wie root, admin oder ubuntu gegen gängige Passwörter durchprobieren. Diese Scans sind kein Einzelfall, sondern permanenter Hintergrundlärm im Internet.
Die gute Nachricht: Die wirksamsten Gegenmaßnahmen sind keine exotischen Zusatztools, sondern eine Handvoll gut dokumentierter Konfigurationsänderungen an sshd_config und der konsequente Wechsel von Passwort- zu Key-basierter Authentifizierung. Ein Server, der ausschließlich Public-Key-Auth erlaubt, keinen Root-Login über SSH zulässt und nur moderne Verschlüsselungsverfahren anbietet, reduziert die realistische Angriffsfläche auf nahezu null, selbst wenn Port 22 offen und öffentlich erreichbar bleibt. Die folgenden Abschnitte zeigen die konkrete Umsetzung, vom Schlüsselpaar bis zur produktionsreifen sshd_config.
2. Key-basierte Authentifizierung statt Passwörter
Ein SSH-Schlüsselpaar besteht aus einem privaten Schlüssel, der niemals den eigenen Rechner verlässt, und einem öffentlichen Schlüssel, der auf dem Zielserver in ~/.ssh/authorized_keys hinterlegt wird. Für neue Schlüssel ist der Algorithmus Ed25519 die richtige Wahl: kürzere Schlüssel als bei RSA, schnellere Signaturberechnung und keine bekannten praktischen Schwächen. RSA mit mindestens 4096 Bit bleibt als Fallback sinnvoll, wenn Zielsysteme sehr alt sind und Ed25519 nicht unterstützen.
Der Schlüssel sollte immer mit einer Passphrase geschützt werden, damit ein gestohlener privater Schlüssel allein nicht ausreicht. ssh-copy-id überträgt den öffentlichen Schlüssel sauber, ohne bestehende Berechtigungen zu verändern, und ist dem manuellen Anhängen per cat vorzuziehen, weil es Duplikate vermeidet. Wichtig sind korrekte Dateiberechtigungen: Das Verzeichnis ~/.ssh braucht 700, die Datei authorized_keys 600. Weichen diese Berechtigungen ab, verweigert sshd in der Standardkonfiguration die Schlüssel-Authentifizierung stillschweigend, ohne dass dies im Client sichtbar wird.
#!/usr/bin/env bash
# Generate a modern Ed25519 keypair (recommended over RSA for new keys)
ssh-keygen -t ed25519 -a 100 -C "deploy@mironsoft.de" -f ~/.ssh/id_ed25519_mironsoft
# Copy the public key to the target server (appends to authorized_keys)
ssh-copy-id -i ~/.ssh/id_ed25519_mironsoft.pub deploy@server.mironsoft.de
# Enforce strict permissions manually if the key was copied by other means
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod 600 ~/.ssh/id_ed25519_mironsoft
chmod 644 ~/.ssh/id_ed25519_mironsoft.pub
# Verify which key the client actually offers during the handshake
ssh -vv deploy@server.mironsoft.de 2>&1 | grep "Offering public key"
3. sshd_config härten: PermitRootLogin und PasswordAuthentication
Die zentrale Konfigurationsdatei /etc/ssh/sshd_config steuert das Verhalten des SSH-Servers, und zwei Direktiven haben den größten Sicherheitseffekt. PermitRootLogin no unterbindet jede direkte Root-Anmeldung über SSH, sodass Angreifer selbst mit einem korrekten Root-Passwort keinen Zugriff bekommen; administrative Aufgaben laufen stattdessen über einen normalen Benutzer mit sudo. PasswordAuthentication no deaktiviert Passwort-Logins vollständig und lässt ausschließlich Public-Key-Authentifizierung zu, womit klassische Brute-Force-Angriffe gegen SSH ins Leere laufen, weil kein Passwort mehr existiert, das erraten werden könnte.
Vor der Aktivierung dieser Einstellungen muss sichergestellt sein, dass mindestens ein funktionsfähiger Schlüssel für einen sudo-fähigen Benutzer hinterlegt ist, denn ein Fehler an dieser Stelle sperrt den einzigen Zugang zum Server aus. Bewährte Praxis: Änderungen in einer zweiten SSH-Sitzung testen, während die erste Sitzung geöffnet bleibt, und erst nach erfolgreichem Login mit dem neuen Schlüssel die alte Sitzung schließen. sshd -t prüft die Syntax der Konfigurationsdatei, bevor der Dienst neu geladen wird, und verhindert so, dass ein Tippfehler den SSH-Dienst komplett lahmlegt.
# /etc/ssh/sshd_config - core hardening directives
# Disable direct root login entirely, use sudo instead
PermitRootLogin no
# Disable password authentication, allow public key auth only
PasswordAuthentication no
PubkeyAuthentication yes
KbdInteractiveAuthentication no
ChallengeResponseAuthentication no
# Reject empty passwords outright (defense in depth)
PermitEmptyPasswords no
# Limit authentication attempts and time per connection
MaxAuthTries 3
LoginGraceTime 20
# Restrict SSH access to specific users or groups
AllowUsers deploy admin
# AllowGroups ssh-users
# Validate syntax before reloading the service:
# sshd -t && systemctl reload sshd
4. Protokoll- und Verschlüsselungsrestriktionen
Neben der Authentifizierungsmethode entscheidet die Auswahl der erlaubten Verschlüsselungs-, Schlüsselaustausch- und MAC-Algorithmen darüber, wie widerstandsfähig eine SSH-Verbindung gegen kryptografische Angriffe ist. Ältere OpenSSH-Versionen aktivieren aus Kompatibilitätsgründen standardmäßig auch schwächere Algorithmen wie diffie-hellman-group1-sha1 oder arcfour, die längst als unsicher gelten. Mit den Direktiven Ciphers, KexAlgorithms und MACs lässt sich die erlaubte Liste explizit auf moderne Verfahren wie chacha20-poly1305@openssh.com und aes256-gcm@openssh.com einschränken.
Der Befehl ssh -Q cipher, ssh -Q kex und ssh -Q mac listet auf dem lokalen System alle unterstützten Algorithmen auf und ist der schnellste Weg, eine Whitelist zusammenzustellen, ohne veraltete Dokumentation zu Rate ziehen zu müssen. Ein oft übersehener Punkt: Das Verschieben von Port 22 auf einen anderen Port reduziert zwar das Volumen an automatisiertem Scan-Rauschen in den Logs erheblich, ist aber keine echte Sicherheitsmaßnahme im kryptografischen Sinn, sondern reine Security-through-Obscurity und sollte nie als Ersatz für die eigentliche Härtung verstanden werden.
# /etc/ssh/sshd_config - restrict to modern, audited algorithms
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
# Only protocol 2 has been supported since OpenSSH 7.6, listed here for clarity
Protocol 2
# Optional: move off the default port to cut down automated scan noise
# Port 2222
# Disable features rarely needed on a hardened server
X11Forwarding no
AllowTcpForwarding no
AllowAgentForwarding no
5. Client-Konfiguration mit ~/.ssh/config
Auf der Client-Seite spart eine gepflegte ~/.ssh/config nicht nur Tipparbeit, sondern reduziert auch Fehlerquellen: Statt bei jedem Verbindungsaufbau Benutzername, Port und Schlüsseldatei manuell anzugeben, definiert man pro Host einen Alias mit allen nötigen Parametern. IdentityFile legt fest, welcher private Schlüssel für einen Host verwendet wird, und IdentitiesOnly yes verhindert, dass der SSH-Client zusätzlich alle im Agenten geladenen Schlüssel anbietet, was auf Servern mit begrenztem MaxAuthTries sonst schnell zur Aussperrung führen kann.
Für Server, die nur über einen Bastion- oder Jump-Host erreichbar sind, übernimmt ProxyJump die Weiterleitung automatisch und ersetzt die früher übliche, deutlich fehleranfälligere ProxyCommand-Syntax mit manuellem nc-Aufruf. HashKnownHosts yes speichert Host-Einträge in ~/.ssh/known_hosts gehasht statt im Klartext, sodass ein gestohlenes Known-Hosts-File keine Liste erreichbarer Server preisgibt. Mit Include lassen sich größere Konfigurationen zusätzlich in team- und projektspezifische Dateien aufteilen und versionieren.
# ~/.ssh/config - per-host client configuration
Host prod-shop
HostName server.mironsoft.de
User deploy
Port 2222
IdentityFile ~/.ssh/id_ed25519_mironsoft
IdentitiesOnly yes
AddKeysToAgent yes
Host db-internal
HostName 10.0.4.12
User dbadmin
ProxyJump prod-shop
IdentityFile ~/.ssh/id_ed25519_internal
IdentitiesOnly yes
# Global defaults applied to hosts without an explicit block
Host *
HashKnownHosts yes
ServerAliveInterval 30
ServerAliveCountMax 3
IdentitiesOnly yes
6. SSH-Agent und Key-Management
ssh-agent hält entschlüsselte private Schlüssel im Speicher, damit die Passphrase nicht bei jeder Verbindung erneut eingegeben werden muss. Das ist komfortabel, hat aber eine wichtige Kehrseite: AddKeysToAgent yes in der Client-Config und ssh-add -t 3600 mit einem Zeitlimit sorgen dafür, dass Schlüssel nicht dauerhaft, sondern nur für eine begrenzte Session im Speicher bleiben. Auf gemeinsam genutzten Systemen oder Jump-Hosts sollte Agent-Forwarding (ForwardAgent yes) nur gezielt für einzelne, vertrauenswürdige Hosts aktiviert werden, niemals global, da ein kompromittierter Zwischenserver sonst jeden weitergeleiteten Schlüssel missbrauchen kann.
Für Deployment-Pipelines gilt dieselbe Vorsicht: Deploy-Keys sollten pro Repository oder Zielsystem einzeln erstellt werden, statt einen persönlichen Schlüssel in CI/CD-Umgebungen zu hinterlegen. Rotiert man Schlüssel regelmäßig und entfernt alte Einträge konsequent aus authorized_keys, bleibt die Angriffsfläche auch bei wechselnden Teammitgliedern klein. Der Befehl ssh-keygen -y -f key prüft dabei, ob ein privater Schlüssel tatsächlich zum hinterlegten öffentlichen Schlüssel passt, bevor ein alter Eintrag gelöscht wird.
# .github/workflows/deploy.yml - load a dedicated deploy-only key via ssh-agent
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Start ssh-agent and load the deploy key
run: |
eval "$(ssh-agent -s)"
ssh-add - <<< "${{ secrets.DEPLOY_KEY_ED25519 }}"
echo "SSH_AUTH_SOCK=$SSH_AUTH_SOCK" >> "$GITHUB_ENV"
- name: Deploy over SSH
run: ssh -o StrictHostKeyChecking=yes deploy@server.mironsoft.de "bin/deploy.sh"
7. Ergänzender Schutz: fail2ban gegen Brute-Force
Auch mit deaktivierter Passwort-Authentifizierung lohnt sich eine zusätzliche Schutzschicht gegen die schiere Menge automatisierter Verbindungsversuche: fail2ban wertet /var/log/auth.log beziehungsweise journalctl -u ssh aus, erkennt wiederholte fehlgeschlagene Anmeldeversuche von derselben IP-Adresse und sperrt diese für eine konfigurierbare Zeit über iptables oder nftables. Das reduziert Log-Rauschen erheblich und entlastet den SSH-Daemon selbst, weil Verbindungsversuche gesperrter IP-Adressen den TCP-Handshake gar nicht erst erreichen.
Für SSH genügt in den meisten Fällen die mitgelieferte Jail-Vorlage, aktiviert über /etc/fail2ban/jail.local mit angepasstem maxretry und bantime. Wichtig: fail2ban ersetzt keine der vorherigen Maßnahmen, sondern ergänzt sie, denn ohne funktionierende Key-Authentifizierung wäre ein einzelner cleverer Angreifer mit niedriger Versuchsfrequenz weiterhin ein Risiko. Die vollständige Konfiguration von fail2ban mit eigenen Filtern und mehreren Jails ist ein eigenes Thema und würde den Rahmen dieses Artikels sprengen.
8. Monitoring und Logging von SSH-Zugriffen
Gehärtete Konfiguration allein reicht nicht, wenn niemand bemerkt, wenn sich das Zugriffsmuster ändert. journalctl -u ssh --since "1 hour ago" zeigt aktuelle Anmeldeversuche direkt aus dem systemd-Journal, während grep "Failed password" /var/log/auth.log | wc -l einen schnellen Überblick über die Zahl fehlgeschlagener Versuche liefert. Erfolgreiche Root-Logins, sofern sie überhaupt noch möglich sind, sollten in jedem Monitoring-System einen sofortigen Alarm auslösen, da sie fast immer entweder eine Fehlkonfiguration oder einen erfolgreichen Angriff bedeuten.
Für zentrales Logging über mehrere Server hinweg empfiehlt sich das Weiterleiten der Auth-Logs an einen zentralen Syslog-Server oder in einen Log-Aggregator wie Loki oder die ELK-Stack-Familie, damit Muster über die gesamte Infrastruktur hinweg sichtbar werden, statt in isolierten Einzel-Logs unterzugehen. last und lastlog liefern zusätzlich einen schnellen Überblick über erfolgreiche Logins der letzten Zeit und helfen, unerwartete Zugriffszeiten oder unbekannte Quell-IPs frühzeitig zu erkennen, bevor daraus ein größerer Vorfall wird.
9. SSH-Härtung im direkten Vergleich
Die folgende Übersicht fasst die wichtigsten Einstellungen zusammen, bei denen der Unterschied zwischen Standardkonfiguration und gehärtetem Setup besonders groß ausfällt.
| Einstellung | Standard / Unsicher | Empfohlene Härtung | Vorteil |
|---|---|---|---|
| Root-Login | PermitRootLogin yes |
PermitRootLogin no |
Kein direkter Root-Zugriff über SSH möglich |
| Authentifizierung | PasswordAuthentication yes |
PasswordAuthentication no |
Brute-Force gegen Passwörter läuft ins Leere |
| Login-Versuche | MaxAuthTries unbegrenzt |
MaxAuthTries 3 |
Automatisierte Versuchsketten brechen früh ab |
| Verschlüsselung | Default-Ciphers inkl. veralteter Verfahren | Ciphers chacha20-poly1305,aes256-gcm |
Keine bekannt schwachen Algorithmen aktiv |
| Brute-Force-Schutz | Kein aktives Rate-Limiting | fail2ban mit sshd-Jail aktiv | Auffällige IP-Adressen werden automatisch gesperrt |
Wer alle fünf Zeilen konsequent umsetzt, hat die realistischen Angriffsvektoren gegen SSH bereits auf ein Minimum reduziert. Der verbleibende Rest, etwa Zero-Day-Schwachstellen in OpenSSH selbst, lässt sich nur durch zeitnahes Patchen und einen aktuellen Paketstand abdecken, nicht durch Konfiguration allein.
Mironsoft
Server-Härtung, SSH-Sicherheit und Infrastruktur-Automatisierung für euren Linux-Stack
SSH-Zugänge professionell absichern?
Wir prüfen eure bestehende SSH-Konfiguration, schließen Lücken in sshd_config und Client-Setup und richten fail2ban sowie Monitoring ein, damit eure Linux-Server dauerhaft gegen automatisierte Angriffe abgesichert bleiben.
Security-Audit
Bestehende sshd_config und Key-Bestand systematisch prüfen
Config-Härtung
Key-Auth, Protokoll-Restriktionen und Client-Setup einrichten
Monitoring-Setup
fail2ban, zentrales Logging und Alerting für Anmeldeversuche
10. Zusammenfassung
Die wichtigsten Maßnahmen, um SSH-Verbindungen abzusichern, greifen ineinander: Key-basierte Authentifizierung mit Ed25519-Schlüsseln ersetzt Passwörter vollständig und macht klassische Brute-Force-Angriffe wirkungslos. PermitRootLogin no und PasswordAuthentication no in sshd_config schließen die beiden größten Einfallstore direkt an der Quelle. Eingeschränkte Ciphers, KexAlgorithms und MACs verhindern, dass veraltete, unsichere Verschlüsselungsverfahren überhaupt zur Wahl stehen. Eine gepflegte ~/.ssh/config macht die tägliche Arbeit sicherer und komfortabler zugleich.
fail2ban ergänzt diese Maßnahmen als zusätzliche Schutzschicht gegen die schiere Masse automatisierter Scans, ersetzt aber keine der vorherigen Schritte. Kontinuierliches Monitoring über journalctl, zentrale Logs und Alerts bei erfolgreichen Root-Logins stellt sicher, dass Abweichungen vom normalen Zugriffsmuster nicht erst Wochen später auffallen. Wer alle Bausteine konsequent umsetzt, reduziert die realistische Angriffsfläche eines Linux-Servers über SSH auf ein Minimum, unabhängig davon, ob der Standardport offen bleibt oder nicht.
SSH-Verbindungen absichern - Das Wichtigste auf einen Blick
Key-Authentifizierung
Ed25519-Schlüsselpaar mit Passphrase, ssh-copy-id und korrekte Berechtigungen (700/600) statt Passwort-Login.
sshd_config-Härtung
PermitRootLogin no, PasswordAuthentication no, MaxAuthTries 3 und eingeschränkte Ciphers/KexAlgorithms.
Client-Config
~/.ssh/config mit IdentityFile, ProxyJump und IdentitiesOnly yes pro Host.
Ergänzung & Monitoring
fail2ban gegen Brute-Force-Massen, journalctl und zentrales Logging für kontinuierliche Überwachung.