Konfigurations- und Optimierungsmöglichkeiten von SSH

Andri im Ops One Büro an seinem Arbeitsplatz.

In den meisten Fällen funktioniert SSH unbemerkt im Hintergrund. Sobald ein Private Key generiert und dessen Public Key auf dem richtigen Server hinterlegt wurde, wird weiteren Konfigurations- und Optimierungsmöglichkeiten keine Beachtung mehr geschenkt. Weil SSH aber noch zahlreiche weitere Möglichkeiten mit sich bringt – und auch einige sicherheitsrelevante Fallstricke – möchten wir uns in diesem Artikel etwas tiefer damit beschäftigen.

Als Webentwickler kommst du früher oder später mit SSH in Kontakt. Sei es, um dich zu Analysezwecken mit einem entfernten Rechner zu verbinden, oder um innerhalb eines Continuos Deployment Jobs Daten auf einen Server zu kopieren – sobald Aktionen auf einem externen System durchgeführt werden sollen, ist die Secure Shell das Tool der Wahl.

SSH wurde bereits 1995 als Ersatz für damals verwendete Protokolle wie rsh oder Telnet entwickelt. Im Unterschied zu diesen Vorgängern ist die Kommunikation von SSH verschlüsselt und somit geschützt vor unerlaubten Mitlesern.

Dank der mehrstufigen Architektur lassen sich Teile von SSH auch in anderen Programmen verwenden, zum Beispiel zum Dateiabgleich per rsync, welches im Hintergrund SSH für den Datentransfer nutzt. 

Durch die für nahezu jede Architektur verfügbaren Implementationen ist es ausserdem möglich, eine Verbindung oder einen Datenabgleich zwischen vielen verschiedenen Systemen durchzuführen, zum Beispiel von deiner Windows-Arbeitsstation auf einen Linux Server bei uns.

Auf die verschiedenen Konfigurations- und Optimierungsmöglichkeiten von SSH gehen wir im Folgenden kurz ein.

Authentifizierung

Wie alles andere, ist auch die Authentifizierung in SSH modular aufgebaut:

  • password: Anmeldung per Benutzername & Passwort
  • publickey: Anmeldung per Private/Public Key (siehe unten)
  • keyboard-interactive: (zusätzliche) Anmeldung mit weiteren Sicherheitsmerkmalen, z. B. TOTP, Yubikey, SecurID, usw.
  • GSSAPI: Single Sign on per Kerberos oder NTLM für Enterprise-Umgebungen

password

Im Webumfeld sind primär die Methoden «password» und «publickey» relevant. Je nach Serverkonfiguration steht vielleicht nur ein Teil der Methoden zur Verfügung. Auf unseren Servern haben wir die «password»-Methode bewusst deaktiviert, weil wir aus Sicherheitsgründen die Anmeldung per Public Key für alle Kundinnen und Kunden voraussetzen.

publickey

Neben der Anmeldung per Benutzername und Passwort ist die Key-Authentifizierung die zweite Anmeldemethode, die du wahrscheinlich bei deiner Arbeit antreffen wirst. Einerseits wird mit einer Anmeldung per Schlüssel die Sicherheit erhöht, und andererseits lassen sich damit auch Verbindungen automatisieren und so zum Beispiel in einem Deployment-Job nutzen.

Des Weiteren lässt sich ein einzelnes Keypaar für viele verschiedene Verbindungen nutzen, sodass du dir nicht mehr ein einzelnes Passwort für jede SSH-Verbindung merken musst, sondern immer denselben Schlüssel mit demselben Passwort zur Anmeldung verwenden kannst.

Für die Nutzung erstellst du erst einmal ein Schlüsselpaar auf deinem Client. Wenn du ein Betriebssystem mit installiertem OpenSSH nutzt, kannst du dieses auf der Kommandozeile wie folgt generieren:

ssh-keygen -t ed25519 -C 'name@example.net'

Damit wird ein Schlüssel mit dem heute modernen Algorithmus Ed25519 erstellt. Für aktuelle Empfehlungen, sowie viele weitere Tipps, empfehlen wir jeweils die Konsultation der OpenSSH Guidelines von Mozilla.

Nach der Ausführung des oben genannten Kommandos werden zwei Dateien im Unterordner .ssh​ erstellt. In der Datei id_ed25519​ ist dein privater Schlüssel gespeichert. Dieser sollte zusätzlich mit einem Passwort versehen werden (wird beim Generieren abgefragt). Wie durch den Namen bereits klar, sollte der Schlüssel nur privat zugänglich gespeichert werden. 

Es ist natürlich erlaubt, Sicherungskopien auf eigenen Medien oder Cloudspeichern zu erstellen, aber der private Schlüssel sollte nie auf extern zugänglichen Systemen oder Laufwerken gespeichert und schon gar nicht per E-Mail versendet werden.

Der öffentliche Schlüssel wird in der Datei id_ed25519.pub​ gespeichert, und ist – wie es der Name sagt – wirklich öffentlich und kann beliebig verteilt werden. Mein bei GitHub hinterlegter Schlüssel ist beispielsweise unter https://github.com/andristeiner.keys öffentlich verfügbar. Falls du selbst ein GitHub oder GitLab-Konto hast, kannst du das auch mit deinem eigenen oder einem fremden Benutzernamen nachvollziehen und wirst die dazugehörigen öffentlichen Schlüssel sehen.

keyboard-interactive

Um die Sicherheit weiter zu erhöhen, verwenden wir für unsere eigenen Zugänge zudem die "keyboard-interactive" Methode und verifizieren uns zusätzlich per Yubikey am System.

Wenn du nicht selbst für die Administration des betroffenen Systems verantwortlich bist, hast du hier in der Regel keine grossen Auswahlmöglichkeiten und musst dich mit den angebotenen Methoden arrangieren.

Agent & Schlüssel-Weiterleitung

Oben haben wir besprochen, dass der private Schlüssel nie auf ein externes System kopiert werden sollte. Es wäre aber sehr praktisch, wenn ich Daten von einem Server direkt auf einen anderen kopieren könnte, ohne dabei einen Umweg über mein lokales System zu machen. Oder vielleicht möchtest du dich mit einem Server verbinden, der nur von einem anderen Server aus, aber nicht aus dem Internet, erreichbar ist.

Damit das möglich ist, brauchen wir lokal einen SSH-Agent. In der Regel ist dieser bereits Bestandteil deines Betriebssystems, und ermöglicht es, deinen privaten Schlüssel im Arbeitsspeicher vorzuhalten.

Nachdem du deinen SSH-Schlüssel in den SSH Agent geladen hast (abhängig vom Betriebssystem, z. B. mit ssh-add⁣), kannst du dich ohne weitere Passworteingabe auf ein System verbinden.

Wenn du auf dieser Verbindung das Agent Forwarding aktivierst (ssh -A​), wird dein Agent ausserdem direkt an das entfernte System weitergeleitet und steht dann dort – wie lokal gewohnt – zur Verfügung. Damit kannst du nun von diesem zweiten System weitere SSH-Verbindungen herstellen, und dazu den SSH Agent mit den Keys von deinem lokalen Computer nutzen.

Der grosse Nachteil dieser Variante ist, dass damit alle Benutzer mit Zugriff auf das zweite System deinen SSH Agent mitnutzen können. Solange der Benutzer auf dem zweiten System exklusiv nur durch dich verwendet werden kann, ist das kein Problem. In den meisten Fällen wird es aber der Fall sein, dass dieser Benutzer durch mehrere Personen oder sogar Firmen verwendet werden kann, weil es ein generischer Benutzer zum Weiterspringen ist, oder z. B. der Benutzer einer einzelnen Website auf einem Webserver. In all diesen Fällen musst du dir bewusst sein, dass dieser Personenkreis deinen SSH Agent nutzen kann, als wären diese lokal auf deinem Computer aktiv.

Eine Möglichkeit, dieses Problem etwas zu entschärfen, ist es, deinen privaten Schlüssel lokal mit Bestätigung zu laden (ssh-add -c​). Damit fragt dein SSH Agent lokal bei jeder Nutzung des Schlüssels nach, ob du das erlauben willst. Es ist technisch leider nicht möglich, dass angezeigt wird, wo der Schlüssel genutzt werden möchte, aber immerhin hast du so die Möglichkeit, jede Nutzung zu bestätigen und damit unerlaubte Zugriffe zu verhindern. Abgesehen davon bleibt nur übrig, sich der Problematik bewusst zu sein, und den SSH Agent nur dann weiterzuleiten, wenn es wirklich nötig ist.

Jumpserver

Wenn du gar keine SSH-Aktion direkt auf dem zweiten Server ausführen musst, sondern diesen einfach zum Weiterspringen auf ein drittes System verwenden möchtest, ist die Jumpserver-Konfiguration die richtige Option. Damit ist das Weiterleiten des SSH Agents auf den Mittelserver nicht notwendig und die oben geschilderten Sicherheitsprobleme werden somit vermieden.

Im Gegensatz zur manuellen Variante mit Agent Forwarding wird mit einem Jumpserver die Verbindung direkt vom Client zum Server aufgebaut. Der Server dazwischen wird dabei nur für die Weiterleitung der TCP-Verbindung zwischen den beiden Endpunkten verwendet, die Authentifizierung erfolgt dabei jeweils vom Client zum Zwischensystem, und dann erneut vom Client zum Zielsystem, sodass der SSH Key und Agent die Arbeitsstation nie verlassen.

Server Konfiguration

In der SSH-Serverkonfiguration werden unter anderem Einstellungen zu möglichen Authentifizierungen und der Protokollierung vorgenommen. 

Was du ebenfalls auf dem Server konfigurieren kannst, ist das Hinterlegen der zur Anmeldung erlaubten öffentlichen Schlüssel. In der Regel erfolgt dies durch das manuelle Hinzufügen des Schlüssels in eine Zeile in der Datei ~/.ssh/authorized_keys​. 

Es gibt aber auch Server wie unsere, wo diese Datei an einem anderen, nicht durch den Benutzer veränderbaren Ort gespeichert wird. Unsere Kundinnen und Kunden müssen die erlaubten Schlüssel deshalb über unser Cockpit auf einer Website, einem Server oder einem Kunden/einer Kundin hinterlegen.

So können wir einerseits denselben Schlüssel auf vielen Systemen gleichzeitig hinterlegen, und haben anderseits die volle Kontrolle, wer wann welchen Schlüssel hinzugefügt oder verändert hat.

Unabhängig vom Ort der Konfiguration können einem Schlüssel in authorized_keys​ zahlreiche Optionen mitgegeben werden. Es ist damit unter anderem möglich, die Nutzung eines Keys auf bestimmte Quelladressen einzuschränken, Funktionen zu deaktivieren oder ein festes Kommando zu hinterlegen. Wir empfehlen deshalb, bei jedem Key zu prüfen, wofür dieser effektiv verwendet wird, und dessen Nutzung so weit wie möglich einzuschränken.

Damit kann man das Risiko beim Verlust eines Keys massiv reduzieren. Wenn der betroffene Schlüssel zum Beispiel nur ein Deployment starten, aber ansonsten keine Befehle ausführen darf, sind die Auswirkungen eines Verlustes viel geringer, als wenn mit diesem sämtliche Aktionen auf dem betroffenen System möglich wären. 

Konfigurationsdatei

Wir haben jetzt bereits viel über mögliche Konfigurationen gesprochen. Wahrscheinlich hast du verschiedene Kundinnen und Kunden, und deren Server sind bei verschiedenen Anbietern verteilt, die unterschiedliche Einstellungen voraussetzen. Damit du dir diese nicht alle einzeln merken musst, gibt es die SSH-Clientkonfiguration in der Datei ~/.ssh/config, wo sich sämtliche SSH-CLI-Optionen pro Host hinterlegen lassen. Da es sich dabei um eine einfache Textdatei handelt, lässt sich diese ausserdem perfekt per Git versionieren, sodass du Änderungen nachvollziehen und die Konfiguration einfach mit deinen Arbeitskolleginnen und -kollegen teilen kannst.

# Zugriff auf den intranet.customer.local erfolgt über seine interne IP Adresse und einen davorliegenden Jumpserver
Host intranet.customer.local
	HostName	10.0.0.1
	User		intranet
	ProxyJump	supplier@jumpserver.example.net

# erlauben von RSA Host & Publickeys für ein einzelnes, veraltetes System
Host ancient.example.net
	HostkeyAlgorithms        +ssh-rsa
	PubkeyAcceptedAlgorithms +ssh-rsa

# bei allen Servern eines bestimmten Kunden wird immer derselbe Benutzername & Port verwendet
Host *.customer.example.net
	User		xy
	Port		23245

# alle anderen Verbindungen werden über den zentralen Jumpserver erstellt
# dort erfolgt zusätzliche Authentifizierung, Logging, usw.
Host *
	User		devop
	ProxyJump	jump.example.net

Weitere Beispiele

Die zahlreichen Konfigurationsmöglichkeiten von SSH bieten viele weitere Möglichkeiten, wovon wir dir ein paar unserer Lieblingsbeispiele vorstellen möchten:

Shell Pipelines

Wenn SSH direkt auf der Shell ausgeführt wird, lassen sich damit Kommandos auf verschiedenen Servern per Pipelines verbinden:

  • Export einer MySQL-Datenbank auf einem Server, und direkter Import auf einem zweiten System (ohne Umweg über eine Datei, die hin- und herkopiert werden muss)
ssh old@server1.example.net mysqldump exampledb | ssh new@server2.example.net mysql
  • selbes Kommando, doch der Import wird direkt per SSH vom Quell- auf den Zielserver kopiert (ohne Umweg über deinen lokalen PC)
ssh old@server1.example.net "mysqldump exampledb | ssh new@server2.example.net mysql"

Port Weiterleitungen

Um einen lokalen TCP Port auf dem Server zur Verfügung zu haben (oder umgekehrt), können Portweiterleitungen verwendet werden:

  • lokalen TCP Port auf einen TCP Port auf dem Server verbinden:
ssh -L 3306:127.0.0.1:3306 server1.example.net
  • entfernten TCP Port auf dem Server auf einen lokalen TCP Port verbinden:
ssh -R 9003:127.0.0.1:9003 server1.example.net

Im ersten Beispiel kannst du damit den MySQL Port vom Server auf deinen PC verbinden, um mit lokalen Tools wie MySQL Workbench auf eine entfernte Datenbank zuzugreifen. 

Im zweiten Beispiel verbindest du den Port 9003 für XDebug PHP Debugging vom entfernten Server auf deine lokale Entwicklungsumgebung, damit du XDebug auf dem Server direkt aus deiner Entwicklungsumgebung ansprechen kannst.

Socks Proxy

Wenn du nicht nur eine einzelne TCP-Verbindung weiterleiten, sondern den Server als Proxy für beliebige Verbindungen verwenden möchtest, kannst du dafür einen Socks Proxy einrichten:

ssh -D 9090 server.example.net
curl --socks5 localhost:9090 https://example.net/

Mit dem ersten Kommando erstellst du einen lokalen Socks Proxy auf Port 9090. 

Mit dem zweiten Kommando führst du eine HTTP-Anfrage über diesen Proxy durch. Ein Socks Proxy kann in vielen Applikationen konfiguriert werden. Wir nutzen dies zum Beispiel, um Mailkonfigurationen per Thunderbird zu überprüfen, genau so wie diese auf dem Server initiiert werden.

Multiplexer

Wenn die TCP-Verbindung deiner SSH-Sitzung aus irgendeinem Grund abbricht, ist es nicht mehr direkt möglich, die laufende Ausgabe zu übernehmen. Damit du in einem solchen Fall nahtlos weiterarbeiten kannst, kannst du einen Multiplexer wie screen oder tmux verwenden. Damit ist es möglich, eine laufende Shell (vom selben Benutzer) an einen anderen Ort zu übernehmen und direkt weiterzuführen. Zusätzlich kannst du die Shell auch mit anderen Personen teilen, beispielsweise um gemeinsam an der Analyse eines Problems zu arbeiten.

Dateitransfer

Dank des modularen Aufbaus von SSH kann das SSH-Protokoll auch für andere Aktionen verwendet werden. Ein Beispiel dafür ist der Dateitransfer per scp (für vollständige Kopien einzelner Dateien und Ordner) oder rsync (kopiert/vergleicht nur Änderungen). Bei der Kopie per scp spricht man dabei von SFTP (Secure File Transfer Protocol). 

Dies führt immer wieder zu Verwirrung, weil es mit FTPS auch eine per TLS verschlüsselte Variante des FTP-Protokolls gibt, welche zwar auch Dateien kopiert, aber ein völlig anderes Protokoll mit anderen Funktionen und meistens auch anderen Benutzern ist. Darum: Falls du mal mit einem Problem konfrontiert bist, bei dem der FTPS- oder SFTP-Zugriff nicht funktioniert, lohnt es sich, zuerst abzuklären, ob alle beteiligten Personen vom selben sprechen und wirklich das richtige Protokoll verwendet wird.

Weitere Informationen

Ich hoffe, dass du damit einen guten Überblick über die verschiedenen Konfigurationsmöglichkeiten bekommen, und bereits eigene Ideen für die Optimierung deiner Konfiguration erhalten hast. Gerne unterstützen wir dich und dein Team bei weiteren Fragen oder konkreten Projekten im Rahmen einer Supportanfrage oder Schulung. Wenn du dich selbst tiefer mit SSH befassen möchtest, ist das OpenSSH Buch auf Wikibooks eine gute Anlaufstelle für detailliertere Informationen.