open:it:ssh
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
| Beide Seiten der vorigen RevisionVorhergehende ÜberarbeitungNächste Überarbeitung | Vorhergehende Überarbeitung | ||
| open:it:ssh [2024/08/15 15:25] – Externe Bearbeitung 127.0.0.1 | open:it:ssh [2025/12/13 09:59] (aktuell) – [SSH-Zugriff auf VPN beschränken] k@i | ||
|---|---|---|---|
| Zeile 1: | Zeile 1: | ||
| ====== SSH-Verbindungen ====== | ====== SSH-Verbindungen ====== | ||
| Secure Shell oder SSH bezeichnet ein kryptographisches Netzwerkprotokoll für den sicheren Betrieb von Netzwerkdiensten über ungesicherte Netzwerke. \\ | Secure Shell oder SSH bezeichnet ein kryptographisches Netzwerkprotokoll für den sicheren Betrieb von Netzwerkdiensten über ungesicherte Netzwerke. \\ | ||
| + | |||
| + | Hinweise: https:// | ||
| <WRAP important> | <WRAP important> | ||
| - | Empfehlenswert: | + | Empfehlenswerte Einstellungen für einen Server, der über das Internet erreichbar ist (z.B. ein Webserver): |
| - | * Direkter Login von root | + | * Den direkten Zugang für "root" von Außen ausschließen. |
| - | * Zugang nur mit Schlüssel | + | * Den Zugang mit Passwort von Außen generell ausschließen. |
| - | * Optional z.B. für Webserver: Beschränkter Zugriff über SFTP auf definierten Bereich | + | * Zugang nur mit Schlüssel. |
| + | * Optional z.B. für Webserver: Beschränkter Zugriff über SFTP auf definierte Bereiche | ||
| </ | </ | ||
| - | Hinweise: https:// | ||
| ===== SSH-Schlüssel ===== | ===== SSH-Schlüssel ===== | ||
| Zeile 23: | Zeile 25: | ||
| b = Schlüssellänge (hier 4096 Bit) \\ | b = Schlüssellänge (hier 4096 Bit) \\ | ||
| - | Schlüssel | + | Sofern nicht anders angegeben, |
| - | Den Schlüssel ohne Passwort zu generieren, vereinfacht das Login, da dann später | + | Den Schlüssel ohne Passwort zu generieren, vereinfacht das spätere |
| + | Soll der private Schlüssel | ||
| + | privater Schlüssel: .ssh/ | ||
| + | öffentl. Schlüssel: .ssh/ | ||
| <WRAP important> | <WRAP important> | ||
| - | **Der private Schlüssel muss unbedingt vor fremdem Zugriff geschützt bleiben!** | + | **Der private Schlüssel muss unbedingt vor fremdem Zugriff geschützt bleiben!** |
| + | Das betrifft auch den Transfer der Dateien (USB-Stick, E.Mail, etc.) \\ | ||
| + | Versand per E-Mail nur mit verschlüsselter E-Mail! \\ | ||
| </ | </ | ||
| - | Es werden 2 Dateien angelegt: | + | |
| + | Bei der Erstellung | ||
| * id_rsa (privater Schlüssel) | * id_rsa (privater Schlüssel) | ||
| * id_rsa.pub (öffentlicher Schlüssel) | * id_rsa.pub (öffentlicher Schlüssel) | ||
| Zeile 35: | Zeile 43: | ||
| Der öffentliche Schlüssel wird auf das entfernte System übertragen, | Der öffentliche Schlüssel wird auf das entfernte System übertragen, | ||
| Der private Schlüssel bleibt auf dem lokal System, auf dem er generiert wurde. Für jedes weitere (lokale) System sollte jeweils ein eigener Schlüssel generiert werden.\\ | Der private Schlüssel bleibt auf dem lokal System, auf dem er generiert wurde. Für jedes weitere (lokale) System sollte jeweils ein eigener Schlüssel generiert werden.\\ | ||
| + | Werden privater und öffentllicher Schlüssel auf einen anderen PC kopiert, kann auch von dort aus auf die Server zugegriffen werden - ohne das der öffentliche Schlüssel neu auf diese Server übertragen werden muss. \\ | ||
| Zur Übertragung auf einen Server muss der User bereits dort angelegt sein und der Zugriff ohne Schlüssel (mit Passwort) muss temporär freigegeben werden. \\ | Zur Übertragung auf einen Server muss der User bereits dort angelegt sein und der Zugriff ohne Schlüssel (mit Passwort) muss temporär freigegeben werden. \\ | ||
| Zeile 65: | Zeile 74: | ||
| - Load an existing private key file | - Load an existing private key file | ||
| - Save private key >> jetzt mit Endung .ppk | - Save private key >> jetzt mit Endung .ppk | ||
| + | |||
| + | ===== Server konfigurieren ===== | ||
| + | ==== SSH-Zugriffe ==== | ||
| + | Ggf. vorher Installieren | ||
| + | sudo apt-get install openssh-server | ||
| + | |||
| + | sudo nano / | ||
| + | |||
| + | ClientAliveInterval 1200 | ||
| + | ClientAliveCountMax 3 | ||
| + | | ||
| + | PermitRootLogin no | ||
| + | PasswordAuthentication no | ||
| + | Subsystem sftp internal-sftp | ||
| + | |||
| + | <WRAP important> | ||
| + | Um sich nicht selber auszusperren: | ||
| + | PermitRootLogin nur deaktivieren, | ||
| + | |||
| + | Möglicherweise gibt es Parameter in einem Unterordner, | ||
| + | z.B. / | ||
| + | Das muss dann angepasst werden. | ||
| + | </ | ||
| + | The **ClientAliveInterval** parameter specifies the time in seconds that the server will wait before sending a null packet to the client system to keep the connection alive. \\ | ||
| + | The **ClientAliveCountMax** parameter defines the number of client alive messages which are sent without getting any messages from the client. \\ | ||
| + | Timeout value = ClientAliveInterval * ClientAliveCountMax \\ | ||
| + | Beispiel: 1200 x 3 = 3600 ~ 1 Stunde. \\ | ||
| + | Nach Änderungen muss der SSH-Service neu gestartet werden. | ||
| + | sudo systemctl reload ssh | ||
| + | | ||
| + | ==== SSH-Zugriff auf VPN beschränken ==== | ||
| + | > Debian 13 Server (nur IPv6 öffentlich) | ||
| + | > SSH (und SFTP) ausschließlich über WireGuard-VPN (IPv4 10.8.0.0/ | ||
| + | > Firewall: UFW | ||
| + | === 🛡️ Zielbild (Soll-Zustand) === | ||
| + | * SSH nur erreichbar über WireGuard | ||
| + | * VPN-Netz: `10.8.0.0/ | ||
| + | * Kein öffentlicher SSH (weder IPv4 noch IPv6) | ||
| + | * UFW aktiv | ||
| + | * SSH zusätzlich hart an VPN gebunden | ||
| + | |||
| + | === ✅ Voraussetzungen === | ||
| + | * Du hast Konsolenzugriff oder funktionierenden VPN-Zugang | ||
| + | * WireGuard-Interface heißt `wg0` | ||
| + | * Server-VPN-IP z. B. `10.8.0.1` | ||
| + | |||
| + | === 🧩 1. WireGuard prüfen === | ||
| + | ip a show wg0 | ||
| + | |||
| + | Erwartet: | ||
| + | inet 10.8.0.1/24 scope global wg0 | ||
| + | |||
| + | === 🧩 2. UFW installieren & Grundregeln === | ||
| + | sudo apt update | ||
| + | |||
| + | sudo apt install ufw | ||
| + | |||
| + | Default-Policies: | ||
| + | sudo ufw default deny incoming | ||
| + | |||
| + | sudo ufw default allow outgoing | ||
| + | |||
| + | === 🧩 3. WireGuard selbst freigeben === | ||
| + | (typisch: UDP 51820 – ggf. anpassen) | ||
| + | sudo ufw allow 51820/udp | ||
| + | |||
| + | === 🧩 4. SSH nur über WireGuard erlauben === | ||
| + | (empfohlen: Interface-gebunden) | ||
| + | sudo ufw allow in on wg0 to any port 22 proto tcp | ||
| + | |||
| + | Alternativ: | ||
| + | sudo ufw allow from 10.8.0.0/24 to any port 22 proto tcp | ||
| + | |||
| + | === 🧩 5. Öffentlichen SSH entfernen (IPv4 + IPv6) === | ||
| + | Status anzeigen: | ||
| + | sudo ufw status numbered | ||
| + | |||
| + | Du wirst sehen: | ||
| + | 22/tcp (OpenSSH) | ||
| + | 22/tcp (OpenSSH (v6)) ALLOW IN Anywhere (v6) | ||
| + | Löschen: | ||
| + | sudo ufw delete allow ssh | ||
| + | |||
| + | oder gezielt per Nummer: | ||
| + | sudo ufw delete < | ||
| + | |||
| + | === 🧩 6. IPv6 in UFW deaktivieren (wichtig!) === | ||
| + | Da SSH nur über IPv4-VPN laufen soll: | ||
| + | sudo nano / | ||
| + | Ändern: | ||
| + | IPV6=no | ||
| + | |||
| + | Dann: | ||
| + | sudo ufw reload | ||
| + | |||
| + | === 🧩 7. UFW aktivieren === | ||
| + | sudo ufw enable | ||
| + | **Prüfen: | ||
| + | sudo ufw status verbose | ||
| + | |||
| + | **Soll:** | ||
| + | 22/ | ||
| + | 51820/ | ||
| + | |||
| + | === 🧩 8. SSH hart an WireGuard binden === | ||
| + | 👉 Das ist der entscheidende Sicherheitsanker. | ||
| + | sudo nano / | ||
| + | Eintragen: | ||
| + | AddressFamily inet | ||
| + | ListenAddress 10.8.0.1 | ||
| + | Dann: | ||
| + | sudo systemctl restart ssh | ||
| + | |||
| + | === 🧪 9. Tests (Pflicht!) === | ||
| + | ❌ Ohne VPN | ||
| + | ssh user@SERVER_IPV6 | ||
| + | |||
| + | ➡️ **muss fehlschlagen** | ||
| + | |||
| + | ✅ Mit VPN | ||
| + | |||
| + | ssh user@10.8.0.1 | ||
| + | |||
| + | ➡️ **muss funktionieren** | ||
| + | |||
| + | |||
| + | === 🔎 10. Finale Kontrolle === | ||
| + | sudo ss -tlnp | grep :22 | ||
| + | |||
| + | **Soll:** | ||
| + | LISTEN 10.8.0.1:22 | ||
| + | |||
| + | ❌ **nicht erlaubt**: | ||
| + | |||
| + | 0.0.0.0:22 | ||
| + | [::]:22 | ||
| + | |||
| + | 🧠 Warum dieses Setup Best Practice ist | ||
| + | | Ebene | Schutz | ||
| + | | WireGuard | ||
| + | | UFW | Filtert Traffic | ||
| + | | SSH `ListenAddress` | verhindert offenen Port technisch | ||
| + | | IPv6 deaktiviert | ||
| + | |||
| + | ➡️ **Selbst bei Firewall-Fehlern kein öffentlicher SSH möglich** | ||
| + | |||
| + | 🧾 Kurzfassung (Merkliste) | ||
| + | - VPN zuerst testen | ||
| + | - SSH nur wg0 erlauben | ||
| + | - OpenSSH (v6) löschen | ||
| + | - IPv6 in UFW deaktivieren | ||
| + | - SSH an 10.8.0.1 binden | ||
| + | |||
| + | ==== Schutz vor Angriffen mit fail2ban ==== | ||
| + | [[https:// | ||
| + | [[https:// | ||
| + | [[https:// | ||
| + | [[https:// | ||
| + | |||
| + | fail2ban installieren | ||
| + | sudo apt update | ||
| + | |||
| + | sudo apt install fail2ban | ||
| + | |||
| + | Conf-Dateien kopieren | ||
| + | sudo cp / | ||
| + | |||
| + | sudo cp / | ||
| + | |||
| + | nur die .local-Dateien bearbeiten | ||
| + | sudo nano / | ||
| + | |||
| + | Ändern (nach [sshd]) suchen: \\ | ||
| + | [sshd] | ||
| + | backend=systemd | ||
| + | enabled = true | ||
| + | port = ssh | ||
| + | filter = sshd | ||
| + | logpath = / | ||
| + | maxretry = 3 | ||
| + | |||
| + | Über die Zeit-Parameter in der Datei / | ||
| + | # " | ||
| + | # Beispiel: Sperrung(banned) für 1 Stunde, wenn maxrtry innerhalb findtime erreicht wurde \\ | ||
| + | **bantime = 3600** \\ | ||
| + | # A host is banned if it has generated " | ||
| + | # Beispiel: Zeit (hier 3 Minuten). \\ | ||
| + | **findtime = 180** \\ | ||
| + | # " | ||
| + | **maxretry = 5** \\ | ||
| + | |||
| + | Installieren | ||
| + | sudo apt install python3-systemd | ||
| + | |||
| + | fail2ban neu starten | ||
| + | sudo systemctl restart fail2ban | ||
| + | Autostart mit System | ||
| + | sudo systemctl enable fail2ban | ||
| + | |||
| + | Protokoll der (temporär) verbanten IP-Adressen | ||
| + | sudo zgrep ' | ||
| + | |||
| + | ==== Verbindungs-Protokolle ==== | ||
| + | Quelle: https:// | ||
| + | |||
| + | If you want to view ssh logs from a specific time range, you can use the since and until flags. Some examples: | ||
| + | sudo journalctl -u ssh --since yesterday | ||
| + | |||
| + | sudo journalctl -u ssh --since -3d --until -2d # logs from three days ago | ||
| + | |||
| + | sudo journalctl -u ssh --since -1h # logs from the last hour | ||
| + | |||
| + | sudo journalctl -u ssh --until " | ||
| + | |||
| + | To watch the ssh logs in realtime, use the follow flag: | ||
| + | sudo journalctl -fu ssh | ||
| + | |||
| + | Use Ctrl-C to exit out of the log monitor. | ||
| ===== Login ===== | ===== Login ===== | ||
| ==== Login über Linux-Shell ==== | ==== Login über Linux-Shell ==== | ||
| - | Login mit Passwort | + | Login mit Passwort: |
| ssh < | ssh < | ||
| - | < | + | < |
| + | < | ||
| - | Beim ersten | + | Login mit Key wenn der key im < |
| - | ssh -i ~/ | + | ssh -i < |
| + | |||
| + | < | ||
| + | Standardpfad für den Key ist: .ssh/id_rsa wenn er dort liegt, kann "-i < | ||
| + | i = identity_file \\ | ||
| - | * ~/.ssh/id_rsa = (relativer) Pfad und Name privater Schlüssel | + | Beim ersten Login, wenn der public-key noch nicht auf dem Server ist oder dieser sich geändert hat, muss dieser im Remote-Server registriert werden. |
| - | | + | |
| + | | ||
| Beim ersten Login erfolgt eine Validierung mit dem Passwort des Systems. Bei Folgeaufrufen nur noch mit dem PW des SSH-Keys bzw. wenn keines vergeben wurde, ohne PW. \\ | Beim ersten Login erfolgt eine Validierung mit dem Passwort des Systems. Bei Folgeaufrufen nur noch mit dem PW des SSH-Keys bzw. wenn keines vergeben wurde, ohne PW. \\ | ||
| - | Beim ersten Login werden die dann bekannten Hosts lokal in **~/ | + | Beim ersten Login werden die dann bekannten Hosts lokal in **~/ |
| Wurde der Schlüssel am Server geändert, oder der Server neu eingerichtet, | Wurde der Schlüssel am Server geändert, oder der Server neu eingerichtet, | ||
| Zeile 106: | Zeile 339: | ||
| Verbindungsart: | Verbindungsart: | ||
| - | ===== SSH-Zugriff am Server konfigurieren ===== | ||
| - | sudo nano / | ||
| - | |||
| - | ClientAliveInterval 1200 | ||
| - | ClientAliveCountMax 3 | ||
| - | | ||
| - | PermitRootLogin no | ||
| - | PasswordAuthentication no | ||
| - | Subsystem sftp internal-sftp | ||
| - | |||
| - | <WRAP important> | ||
| - | Um sich nicht selber auszusperren: | ||
| - | PermitRootLogin nur deaktivieren, | ||
| - | Möglicherweise gibt es Parameter in einem Unterordner, | ||
| - | Das muss dann angepasst werden. | ||
| - | </ | ||
| - | The **ClientAliveInterval** parameter specifies the time in seconds that the server will wait before sending a null packet to the client system to keep the connection alive. \\ | ||
| - | The **ClientAliveCountMax** parameter defines the number of client alive messages which are sent without getting any messages from the client. \\ | ||
| - | Timeout value = ClientAliveInterval * ClientAliveCountMax \\ | ||
| - | Beispiel: 1200 x 3 = 3600 ~ 1 Stunde. \\ | ||
| - | Nach Änderungen muss der SSH-Service neu gestartet werden. | ||
| - | |||
| - | sudo systemctl reload ssh | ||
| ===== Dateien kopieren über SSH ===== | ===== Dateien kopieren über SSH ===== | ||
| Dafür __nicht__ vorab auf dem Remote-Server einloggen, sondern vom lokalen Rechner ausführen. | Dafür __nicht__ vorab auf dem Remote-Server einloggen, sondern vom lokalen Rechner ausführen. | ||
| Zeile 142: | Zeile 352: | ||
| Kopieren des Verzeichnisses “foo” vom lokalen Rechner in das Verzeichnis “bar” eines entfernten Rechners. | Kopieren des Verzeichnisses “foo” vom lokalen Rechner in das Verzeichnis “bar” eines entfernten Rechners. | ||
| scp -r foo < | scp -r foo < | ||
| + | |||
| Quelle: https:// | Quelle: https:// | ||
| - | |||
open/it/ssh.1723728326.txt.gz · Zuletzt geändert: von 127.0.0.1
