Subsections of SSH

Chrooted SFTP Server konfigurieren

Vorwort

Um Dateien auf und von einen Linux-Server zu laden stehen unzählbar viele Möglichkeiten zur Verfügung. In diesem Beispiel wird ein SFTP-Server konfiguriert, der:

  • nur bestimmten Benutzern, oder Gruppen den Zugang erlaubt
  • die Authentifizierung via Passwort, oder SSH-Schlüssel zulässt
  • das Startverzeichnis (Wurzelverzeichnis) fest vorschreibt

Sollte noch kein Openssh-Server installiert sein, kann dies einfach nachgeholt werden:

sudo pacman -Syu openssh
sudo apt update && sudo apt install openssh-server

Allgemein Hinweise zur Konfiguration

Alle Einstellungen werden in der typischen Konfigurationsdatei /etc/ssh/sshd_config vorgenommen. Nach Änderungen muss der SSH-Dienst neugestartet werden um diese zu laden. Bereits hergestellt Verbindungen werden von den Anpassungen nicht beeinträchtigt, sodass man bei Fehlkonfigurationen diese wieder rückgängig machen kann!

Hinweis

Es ist daher immer ratsam eine neue Verbindung aufzubauen um die neuen Einstellungen zu testen. Die existierende Verbindung sollte dann für die Korrektur und nötige Neustarts verwendet werden.

Konfiguriert man SSHd falsch und schließt alle Verbindungen, hat man sich wohlmöglich ausgesperrt!

Konfiguration

Die unten stehenden Einstellungen sollen hier etwas genauer beleuchtet werden:

Parameter Verwendung
ForceCommand Hierdurch ist eine SSH-Konsolen-Verbindung (Shell) nicht mehr möglich, denn es wird eine SFTP-Verbindung erzwungen. Somit kann der Benutzer keine Konsolen-Verbindung mehr aufbauen.
PasswordAuthentication erlaubt die Anmeldung mittels Passwort
ChrootDirectory Einstiegspunkt für die SFTP-Verbindung. Dies entspricht dem höchsten Verzeichnis in welches man zurückgehen kann. Der Inhalt von z.B. /srv/sftp_group_dir entspricht bei der Verbindung dem root (/).
# File: /etc/ssh/sshd_config

# Alle Einstellungen können bequem an das Ende der Datei gepackt werden!


# gilt nur für Benutzer der Linux-Gruppe sftpusers
# alle Benutzer teilen sich einen gemeinsamen Ordner
Match Group sftpusers
  PasswordAuthentication yes
  ChrootDirectory /srv/sftp_group_dir
  ForceCommand internal-sftp

# gilt nur für Benutzer der Linux-Gruppe individuals
# jeder Benutzer hat einen eigenen Ordner (%u wird durch Usernamen ersetzt)
Match Group individuals
  PasswordAuthentication yes
  ChrootDirectory /srv/individuals/%u
  ForceCommand internal-sftp

# gilt nur für den Benutzer myuser
Match User myuser
  PasswordAuthentication no
  ChrootDirectory /srv/sftp
  ForceCommand internal-sftp
  AllowTcpForwarding no
Hinweis

Die Reihenfolge der Konfiguration ist relevant! Ist ein Benutzer in z.B. beiden Gruppen (sftpusers und individuals), so gilt der erste Treffer und die weiteren Konfigurationen sind irrelevant!

Sollte die gruppen-basierte Konfiguration genutzt werden, achte darauf den Konsolen-Benutzer mit dem du Einstellungen tätigst nicht zur Gruppe hinzuzufügen. Andernfalls kannst du zukünftig keine Kommandozeile mehr via SSH öffnen, denn es wird SFTP erzwungen ;)! In diesem Fall wäre ein neuer Benutzer für SFTP Verbindungen ratsam.

Damit die Verbindung generell möglich ist, darf das gewählte Chroot-Directory für den verbindenen Benutzer nicht beschreibbar sein! Damit der Benutzer aber einen Ordner zum schreiben hat, sollte ein neuer Ordner angelegt werden. Hier ein Beispiel:

# Ordner rekursiv anlegen
mkdir -p /srv/sftp_group_dir/subdir

# Besitz auf root Benutzer und Gruppe anpassen
chown root:root /srv/sftp_group_dir

# nur Benutzer und Gruppe dürfen "alles"
chmod 755 /srv/sftp_group_dir

# der Besitz des Unterordner subdir wird auf den Benutzer myuser und die Gruppe sftpusers gesetzt
chown myuser:sftpusers /srv/sftp_group_dir/subdir

# Benutzer und Gruppe dürfen "alles"
chmod 770 /srv/sftp_group_dir/subdir

Um Problemen mit Dateiberechtigungen entgegen zu wirken, können Linux-Benutzer sich die gleiche ID teilen.
Dies ist bei SFTP besonders hilfreich, denn alle Benutzer können dann unterschiedliche Namen (und Passwörter), aber identische Schreibberechtigungen haben.
Bei Zugriffen auf Dateien teilen sie sich nämlich die selbe ID.
Hat jeder Benutzer eine individuelle ID, muss darauf geachtet werden, dass die Datei- und Ordnerberechtigung korrekt konfiguriert werden.
Geschieht dies nicht, können Benutzer Dateien eventuell nicht lesen und bearbeiten.
Deshalb ist es hilfreich die identische User-ID zu verwenden.


Port Forwarding

Remote Port per Tunnel lokal binden

Per SSH kann prinzipiell jeder TCP-Port getunnelt werden, den der Remote-Host erreicht.
Hierzu wird auf dem Client ein Port lokal gebunden und jeglicher Traffic der auf diesen eingeht, durch den Tunnel zum Remote-Host geleitet.
Dieser stellt dann stellvertredend die Verbindung zum Ziel her.

Syntax
ssh -L [local_bind_address:]port:host:hostport root@remote.host
Beispiel 1

MariaDB wird über diverse lokalen IP-Adressen und Ports verfügbar gemacht. Auf dem Remote-Host host1 ist MariaDB nur lokal erreichbar (127.0.0.1:3306).
Die linke Seite entspricht der lokalen IP (oder Port) des Clients.

ssh user@host1 -L 127.0.0.1:3306:127.0.0.1:3306
ssh user@host1 -L 192.168.123.2:3306:127.0.0.1:3306 
ssh user@host1 -L 192.168.123.2:13306:127.0.0.1:3306
ssh user@host1 -L 3306:127.0.0.1:3306
Beispiel 2

Ein Webserver (HTTP/S) läuft auf web1, welcher von host1 erreicht werden kann (ein typischer Jumphost):

  • IP-Adresse web1: 192.168.55.2
  • IP-Adresse host1: 192.168.55.1
ssh user@host1 -L 127.0.0.1:80:192.168.55.2:80
ssh user@host1 -L 127.0.0.1:443:192.168.55.2:443

Weil die Ports 80 und 443 zu den “well-known” Ports gehören, müssen diese ggf. mit root-Rechten gebunden werden (sudo vor dem ssh Befehl).
Deswegen kann es empfehlenswert sein, diese stattdessen auf Ports größer 1024 zu binden:

ssh user@host1 -L 127.0.0.1:8080:192.168.55.2:80
ssh user@host1 -L 127.0.0.1:8443:192.168.55.2:443

SSH SOCK5 Proxy

Anwendungen können (sofern unterstützt) über einen sogenannten Sock5-Proxy mit Servern kommunizieren.
Hierbei wird der Traffic an den Remote-Host gesendet und dieser schickt die Anfrage weiter zum Ziel.

Syntax
ssh user@host1 -D [lokale_bind_address:]port
Beispiel 1

Der Sock5-Proxy bindet sich lokal auf Port 5000.

ssh user@host1 -D 127.0.0.1:5000
Beispiel 2

Lokaler Proxy, der auch von anderen Clients genutzt werden kann, sofern Sie den Host und Port erreichen können.

ssh user@host1 -D 192.168.178.2:1337

SShuttle

Gerne als “poor man’s VPN” bezeichnet, kann SShuttle (eine Python Anwendung) bestimmte Ziel-Adressen (oder Netze) über SSH tunneln. Hierzu bindet SShuttle einen lokalen Port und hinterlegt Firewall-Regeln (nftables / iptables). Hierdurch werden Pakete zum Ziel an den lokalen SShuttle Port umgeleitet (DNAT), und SShuttle leitet diese wiederum zum Remote-Host.
Dieser schickt die Pakete dann dann zum Ziel(netz). Durch diese Technik können ganze IP-Netze hinter (Jump-)Hosts erreicht werden, solange es sich um TCP-Traffic handelt.

Syntax
sshuttle [-l [ip:]port] -r [user@]sshserver[:port] <subnets...>
Beispiel 1

Die Netze 10.20.30.0, 192.168.33.0/25 und die IP-Adresse 1.1.1.1 sollen über host1 verfügbar gemacht werden:

sshuttle -r user@host1 10.20.30.0/24 192.168.33.0/25 1.1.1.1

SSH Verbindung ohne Passwort (mit Key)

Für eine erhöhte Sicherheit beim SSH-Login bietet sich die Authentifizierung mittels SSH-Schlüssel an.
Zusätzlich wird der Login mittels Passwort deaktiviert.

In dieser Anleitung wird die Generierung auf Windows und Linux (auch WSL) beschrieben und abschließend, wie der öffentliche Schlüssel auf den Server zu legen und die SSH-Konfiguration vorzunehmen ist.

SSH Schlüssel auf Windows generieren

In neueren Windows 10 Versionen steht der OpenSSH-Client bereit. Falls dieser nicht installiert ist, kann dieser installiert werden.
Hierfür nutzt man unter Einstellungen “Apps & Features”, klickt auf “Optionale Features” und installiert mittels “Feature hinzufügen” den OpenSSH-Client.

Nach der Installation stehen die Kommandozeilen-Tools zur Verfügung und die Generierung kann durchgeführt werden.
Je nach Plattform die man unterstützten möchte, kann es notwendig sein den veralteten Standard (RSA) zu verwenden.
In diesem Fall sollte man einen möglichst großen Schlüssel verwenden (4096 Bit). Gemäß der Doku empfiehlt sich das Schlüsselverfahren ecdsa zu verwenden.

ssh-keygen -t ecdsa -b 521
ssh-keygen -t rsa -b 4096
ssh-keygen -t ed25519

Hier ein komplettes Beispiel in dem der Pfad mittels Enter bestätigt und ein Passwort für den Schlüssel festgelegt wird. Das Passwort schützt den Schlüssel im Fall von Diebstahl durch Datei-Kopieren!

# .ssh Ordner im $HOME anlegen und betreten
cd
mkdir .ssh
cd .ssh

# Key generieren
C:\Users\User\.ssh>ssh-keygen -t ecdsa -b 521

Generating public/private ecdsa key pair.
Enter file in which to save the key (C:\Users\User/.ssh/id_ecdsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in C:\Users\User/.ssh/id_ecdsa.
Your public key has been saved in C:\Users\User/.ssh/id_ecdsa.pub.
The key fingerprint is:
SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx User@PC
The key's randomart image is:
+---[ECDSA 521]---+
xxxxxxxxxxxxxxx
xxxxxxxxxxxxxxx
xxxxxxxxxxxxxxx
xxxxxxxxxxxxxxx
xxxxxxxxxxxxxxx
xxxxxxxxxxxxxxx
xxxxxxxxxxxxxxx
xxxxxxxxxxxxxxx
xxxxxxxxxxxxxxx
xxxxxxxxxxxxxxx
+----[SHA256]-----+

Nach der Generierung finden sich, je nach gewähltem Verfahren zwei Dateien im Verzeichnis .ssh:

  • id_$verfahren (privater Schlüssel)
  • id_$verfahren.pub (öffentlicher Schlüssel)

Die *.pub Datei ist nützlich, aber nicht zwingend notwendig, da diese immer wieder aus dem privaten Schlüssel generiert werden kann:

ssh-keygen -f $privater_schlüssel -y
# <Passwort eingeben>

ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAF1mthDNIv98jiT5qF85YCd9QmvgK+bTn/VLQVRmJyC12dOSjGpcam4c5Uu9t5dEXtr1bRSW9nCC7Ro6Exla0y86AALfgrTTAFysotLuqJD5bigQN5J50qpZJwUs8wlB12NehrNvAfCQiEYvmN6Bg0RugUyHSi21jlQ4kSj6RsDMAT9Xw==

SSH Schlüssel auf Linux (oder WSL) generieren

Im Regelfall sollte die Anwendung ssh-keygen bereits installiert sein. Ist dies nicht der Fall, müssen die Pakete dafür installiert werden. Wie immer für Ubuntu / Debian und Archlinux:

pacman -Syu openssh
apt update && apt install openssh-client

Im Anschluss wird wie unter Windows der Schlüssel generiert:

ssh-keygen -t ecdsa -b 521
ssh-keygen -t rsa -b 4096
ssh-keygen -t ed25519

Mehr Informationen dazu finden sich oben in der Windows-Anleitung.
Der Ausgabe-Pfad ist ebenfalls der $Benutzer-Ordner/.ssh.

ohne Passwort, aber per Key

Der öffentliche Schlüssel muss in das Home-Verzeichnis des Users gelegt werden, als der man sich einloggen möchte. In diesem Beispiel nennt er sich “user1”.
Den Inhalt der id_$verfahren.pub legt man nun in die authorized_keys Datei (/home/user1/.ssh/authorized_keys.
Diese Datei kann eine beliebige Menge von öffentlichen Schlüsseln enthalten.
Hinter dem Schlüssel können Kommentare hinzugefügt werden.

# Auflisten der Keys
cat /home/user1/.ssh/authorized_keys

ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAF1mthDNIv98jiT5qF85YCd9QmvgK+bTn/VLQVRmJyC12dOSjGpcam4c5Uu9t5dEXtr1bRSW9nCC7Ro6Exla0y86AALfgrTTAFysotLuqJD5bigQN5J50qpZJwUs8wlB12NehrNvAfCQiEYvmN6Bg0RugUyHSi21jlQ4kSj6RsDMAT9Xw== mein kommentar zum schlüssel

Funktionstest

Beim Verwenden des Schlüssels muss dieser mit dem gewählten Kennwort geöffnet werden:

ssh user1@server.host
Enter passphrase for key 'C:\Users\User/.ssh/id_ecdsa':
Last login: Sun Apr 25 22:34:34 2021 from x.x.x.x
user1@server ~

Möchte man nicht jedes mal das Kennwort eingeben, bietet sich ein SSH Agent an.
Dieser hält solange er läuft den SSH-Schlüssel bereit.
Deshalb muss man den privaten Schlüssel nur einmalig öffnen.

ssh-agent bash
ssh-add
# <Passwort eingeben>
``´

Unter Windows kann der Agent-Dienst deaktiviert sein, in diesem Fall muss man diesen vorab mittels Powershell (als Admin) aktivieren:

```powershell
Get-Service -Name ssh-agent | Set-Service -StartupType Manual

Passwort Authentifizierung deaktivieren

Unter bearbeitet man die OpenSSH-Server-Konfiguration und startet den Dienst neu. Falls etwas fehlschlägt, auf gar keinen Fall die Konsolenverbindung trennen.
Ein Neustart bricht eine existierende Verbindung nicht ab, sodass man die Fehlkonfiguration noch reparieren kann! In diesem Beispiel verwenden wir nano (auch wenn ich vim bevorzuge).
Nach Bearbeitung beendet man diesen mit “STRG + X”, “y”, “Enter”.

nano /etc/ssh/sshd_config

# verbietet root Login mittels Passwort
# (ohne SSH Key ist dann kein root Login mehr möglich)
PermitRootLogin prohibit-password

# verbiete generell Passwort-Authentifizierung
PasswordAuthentication no

Ausnahmen für bestimmte Benutzer

Es kann hilfreich sein, einzelnen Benutzern die Authentifizierung dennoch zu erlauben:

# erlaube für Benutzer "user2" Passwort-Authentifizierung
Match User user2
  PasswordAuthentication yes
  
# erlaube allen Benutzern der Gruppe sshpass Passwort-Authentifizierung
Match Group sshpass
  PasswordAuthentication yes

SSH-Daemon neustarten

systemctl restart sshd.service

# im Fehlerfall prüfen:
systemctl status sshd.service

https://www.ssh.com/academy/ssh/keygen