SSH ist der Standard für Fernzugriff auf Linux-Systeme. Die Standardkonfiguration ist funktionsfähig, aber nicht für exponierte Systeme gedacht. Wer einen SSH-Port ins Internet stellt, sieht binnen Stunden Zugriffsversuche – Härtung ist keine Kür.

\n

Die Grundkonfiguration

\n
# /etc/ssh/sshd_config.d/10-haertung.conf\n# (Auf neueren Systemen liegt eine solche Datei im Verzeichnis\n#  sshd_config.d und wird von sshd_config eingebunden. Die\n#  erste passende Anweisung in der Gesamtreihenfolge gewinnt!)\n\n# ---- Anmeldung ------------------------------------------------\nPermitRootLogin no                 # NIEMALS root direkt per SSH\nPasswordAuthentication no          # nur Schluessel!\nKbdInteractiveAuthentication no\nPermitEmptyPasswords no\nMaxAuthTries 3\nLoginGraceTime 20\nMaxSessions 10\n\n# ---- Benutzer -------------------------------------------------\nAllowUsers devon deploy@10.0.0.0/24\nAllowGroups ssh-users\nDenyUsers backup\n#   Ohne AllowUsers/AllowGroups darf JEDES Konto anmelden -\n#   auch solche, die nie dafuer gedacht waren.\n\n# ---- Schluessel -----------------------------------------------\nPubkeyAuthentication yes\nAuthorizedKeysFile .ssh/authorized_keys\n#   In der richtigen Datei liegt bei ausgeschaltetem Passwort\n#   die GESAMTE Zugangskontrolle.\n\n# ---- Weiterleitungen ------------------------------------------\n#   Ein Tunnel ist ein vollstaendiger Zugang zum internen Netz.\nAllowTcpForwarding no              # nur wenn wirklich gebraucht\nX11Forwarding no\nAllowAgentForwarding no\nPermitTunnel no                    # tun-Geraete (VPN!) verbieten\nGatewayPorts no                    # keine Weiterleitung an 0.0.0.0\n\n# ---- Sitzung --------------------------------------------------\nClientAliveInterval 300\nClientAliveCountMax 2              # tote Sitzungen nach 10 min schliessen\nLogLevel VERBOSE                   # Fingerabdruecke der Schluessel protokollieren\n\n# ---- Protokolle -----------------------------------------------\n#   Wer wann mit welchem Schluessel verbunden war, steht\n#   im Systemjournal. Bei einem Vorfall ist das Gold wert.
\n

Schlüssel: der ganze Zugang hängt daran

\n
# Schluesselpaar erzeugen - ED25519 ist Standard, RSA als Ausweich\nssh-keygen -t ed25519 -a 100 -C "devon@arbeitsplatz" -f ~/.ssh/id_ed25519\n#   -a 100: 100 Runden Schluesselableitung (schuetzt bei\n#           schwacher Passphrase)\n#   Die Passphrase auf dem Schluessel ist PFLICHT (schuetzt\n#   bei Verlust des Arbeitsplatzes), auch wenn sie unbequem ist.\n\nssh-keygen -t rsa -b 4096 -o -a 100 -f ~/.ssh/id_rsa       # Alternative\n\n# Oeffentlichen Schluessel auf den Server bringen\nssh-copy-id -i ~/.ssh/id_ed25519.pub devon@server\n\n# Fingerabdruecke pruefen - VOR dem ersten Verbinden!\nssh-keygen -lf ~/.ssh/id_ed25519.pub\n#   Den Server-Fingerabdruck beim Anbieter/Administrator\n#   abgleichen und in known_hosts bestaetigen.\n#   Ein ungepruefter Fingerabdruck ist eine offene Einfahrt.\n\n# Der Server erzeugt seinen Gastgeberschluessel selbst:\nssh-keyscan -t ed25519 server > /tmp/scanbuch\n#   ACHTUNG: keyscan beweist nichts - nur der Anbieter kann\n#   den echten Fingerabdruck bestaetigen.\n\n# Agent fuer die Passphrase (bequem und sicher)\neval "$(ssh-agent -s)"\nssh-add -t 8h ~/.ssh/id_ed25519\nssh-add -l                            # welche Schluessel geladen?\n\n# WICHTIG: Agent-Weiterleitung ist gefaehrlich\n#   Wer Zugriff auf den Zielrechner hat, kann ueber den Agent\n#   ueberall dorthin, wo der Schluessel passt. Besser:\n#     ssh -J sprung@bastion ziel        # ProxyJump\n#   ProxyJump braucht keine Agent-Weiterleitung.
\n

Zwei-Faktor: der große Gewinn

\n
# Ein gestohlener Schluessel ist nutzlos ohne zweiten Faktor.\n# Das ist die wirksamste Massnahme ueberhaupt.\n\n# /etc/ssh/sshd_config.d/20-mfa.conf\nKbdInteractiveAuthentication yes\nAuthenticationMethods publickey,keyboard-interactive\n\n# /etc/pam.d/sshd - TOTP pruefen (google-authenticator oder oathtool)\nauth required pam_google_authenticator.so nullok\n\n# Einrichtung je Benutzer (erzeugt ~/.google_authenticator)\ngoogle-authenticator --time-based --disallow-reuse \\\n  --rate-limit=3 --rate-time=30 --window-size=3\n#   Notfallcodes sicher verwahren - ohne sie ist der Zugang\n#   bei Verlust des Telefons verloren.\n\n# Fuer Skripte und Automatisierung: eigene Konten mit\n#   publickey allein und eingeschraenktem Befehl\n#   (siehe Befehlsbeschraenkung unten)
\n

Zugang einschränken – nicht nur die Anmeldung

\n
# Ein Schluessel darf nur EINEN Befehl ausfuehren (z. B. Sicherung)\n# In ~/.ssh/authorized_keys (eine lange Zeile!):\n#   command="/usr/local/bin/sicherung.sh",no-port-forwarding,\n#   no-agent-forwarding,no-pty,no-X11-forwarding ssh-ed25519 AAAA...\n#\n#   Damit ist der Schluessel auch bei Verlust nur so gefaehrlich\n#   wie der eine Befehl. Das Muster ist bei Sicherungen und\n#   Automatisierung deutlich besser als ein voller Zugang.\n\n# Chroot: Ein Benutzer sieht nur sein Verzeichnis\nMatch User uebertragung\n    ChrootDirectory /srv/uebertragung\n    ForceCommand internal-sftp\n    AllowTcpForwarding no\n    PasswordAuthentication no\n\n# Unterschiedliche Regeln je Konto/Netz (Reihenfolge beachten!)\nMatch Address 10.0.0.0/8\n    PasswordAuthentication no\n    PermitRootLogin no\n\n# Fuer Konten, die nur Tunnel brauchen\nMatch User tunneluser\n    PermitTTY no\n    ForceCommand /bin/false\n    AllowTcpForwarding yes\n    PermitOpen db.intern:5432         # NUR dieser eine Zielpunkt!\n\n# Automatisierung ohne Benutzerkonten (moderne Variante):\n#   SSH-Zertifikate mit der eigenen Zertifizierungsstelle.\n#   - Kurze Gueltigkeit (Stunden statt Jahre)\n#   - Zentraler Widerruf\n#   - Keine authorized_keys-Pflege auf jedem Server
\n

Fail2ban: Brute-Force begrenzen

\n
# /etc/fail2ban/jail.d/sshd.local\n[sshd]\nenabled   = true\nport      = ssh\nmode      = aggressive              # strengere Mustererkennung\nmaxretry  = 3\nfindtime  = 10m\nbantime   = 1h\nbantime.increment = true            # Wiederholungstaster verlaengern\nbantime.factor    = 2\nbantime.maxtime   = 1w\nignoreip  = 127.0.0.1/8 10.0.0.0/8  # eigene Netze ausnehmen!\n#   ACHTUNG: Bei ignoreip versehentlich 0.0.0.0/0 eintragen\n#   deaktiviert den Schutz vollstaendig.\n\n# Umstellung auf nftables (statt iptables)\nbanaction = nftables-multiport\nbanaction_allports = nftables-allports\n\nfail2ban-client status sshd\nfail2ban-client status sshd | grep -E 'Banned|Total'\nfail2ban-client set sshd unbanip 203.0.113.5\nfail2ban-client banned                # alle Sperren
\n

Prüfen und überwachen

\n
# Konfiguration pruefen\nsshd -t\nsshd -T | grep -Ei 'permitrootlogin|passwordauth|allowusers|maxauth'\n\n# Effektive Konfiguration anzeigen (alle Quellen zusammengefuehrt)\nsshd -T | head -50\n\n# Wer ist angemeldet?\nwho\nw\nlast -n 20\nlastb -n 20                           # fehlgeschlagene Anmeldungen\n\n# Fehlgeschlagene Versuche zaehlen\njournalctl -u ssh --since "24 hours ago" | grep -c "Failed password"\njournalctl -u ssh --since "1 hour ago" | grep -E "Invalid user|Failed" | tail -20\n\n# Welche Schluessel wurden benutzt?\njournalctl -u ssh | grep -i "Accepted publickey" | tail -20\n\n# Von wo kommen die Versuche?\njournalctl -u ssh | grep "Failed password" | \\\n  awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head\n\n# Test NACH jeder Aenderung - in einer ZWEITEN Sitzung!\n#   1. Aenderung speichern\n#   2. sshd -t   (Syntax)\n#   3. systemctl reload ssh\n#   4. In einer NEUEN Sitzung anmelden und pruefen\n#   5. Erst dann die ALTE Sitzung schliessen\n#   Wer das nicht macht, sperrt sich aus.
\n

Prüfliste

\n
    \n
  1. Ist PermitRootLogin no gesetzt?
  2. \n
  3. Ist die Passwortanmeldung abgeschaltet (nur Schlüssel)?
  4. \n
  5. Ist AllowUsers oder AllowGroups gesetzt?
  6. \n
  7. Haben alle Schlüssel eine Passphrase?
  8. \n
  9. Sind die Server-Fingerabdrücke abgeglichen und in known_hosts?
  10. \n
  11. Ist ein zweiter Faktor für exponierte Systeme aktiv?
  12. \n
  13. Sind Agent-Weiterleitung und X11-Weiterleitung abgeschaltet, wenn sie nicht gebraucht werden?
  14. \n
  15. Ist Fail2ban aktiv UND die eigenen Netze ausgenommen (ohne Sperre gegen sich selbst)?
  16. \n
  17. Ist der Zugang über einen Sprungserver (Bastion) statt direkt möglich?
  18. \n
  19. Ist ein Notfallweg dokumentiert (Konsole, ausfallsicherer Nachbarzugang)?
  20. \n
  21. Wird sshd -T nach Änderungen geprüft?
  22. \n
  23. Werden Anmeldungen protokolliert und ausgewertet?
  24. \n
\n

Häufige Fehler

\n
    \n
  1. PasswordAuthentication nicht abgeschaltet. Damit ist der Schlüssel wertlos und das System offen für Erraten.
  2. \n
  3. Ausgesperrt nach Änderung. Immer in zweiter Sitzung testen, bevor die erste geschlossen wird. Bei Providern mit Konsole: dort prüfen, wie man wieder hineinkommt.
  4. \n
  5. Schlüssel ohne Passphrase. Bei Verlust des Arbeitsplatzes ist der Zugang verloren. Die Passphrase mit Agent bequem machen, nicht weglassen.
  6. \n
  7. Agent-Weiterleitung aktiviert. Der Zielrechner erhält damit Zugang überall dorthin, wo der Schlüssel passt. ProxyJump nutzen.
  8. \n
  9. Kein AllowUsers. Jedes vorhandene Konto ist erreichbar, auch vergessene Dienstkonten.
  10. \n
  11. Fail2ban sperrt die eigenen Verbindungen. Nach Passwortwechsel oder fehlerhafter Automatisierung sperrt man sich selbst. ignoreip ist Teil der Konfiguration, nicht optional.
  12. \n
  13. Port ändern als Ersatz für Härtung. Ein anderer Port reduziert nur die Protokollzeilen, nicht die Angriffsfläche. Kein Ersatz für die Maßnahmen oben.
  14. \n
  15. Konfiguration in mehreren Dateien. Auf Systemen mit sshd_config.d gewinnt die erste passende Anweisung. Wer eine Regel im Match-Block vergeblich sucht, nimmt sshd -T.
  16. \n
  17. Sicherung der Zugänge fehlt. Wer Aussperrrisiken eingeht, braucht einen dokumentierten Ausweg.
  18. \n
\n

Verwandte Grundlagen: SSH, SSH-Befehle, Fail2ban, Zero Trust.