Wie er sein sollte
- Ein kleiner, separater Server, der SSH ausführt und sonst nichts: keine Datenbank, keine Website, keine Entwicklerwerkzeuge.
- Nur Schlüssel, mit automatischen Sicherheitsupdates.
- Keine privaten Schlüssel darauf. Ein Sprung macht das unnötig. Die Anmeldung am internen Server ist von Ihrem eigenen Rechner aus verschlüsselt, und der Bastion reicht die Daten nur weiter.
- Der einzige Weg hinein. Interne Server sollten SSH an der Firewall nur von der Adresse des Bastions annehmen.
Für die übrigen SSH-Einstellungen des Servers siehe wie Sie sshd_config absichern.
Die Benutzer anlegen
sudo groupadd jump
sudo useradd -m -G jump -s /bin/bash alice
sudo install -d -m 700 -o alice -g alice /home/alice/.ssh
sudo install -m 600 -o alice -g alice alice.pub /home/alice/.ssh/authorized_keys
Halten Sie Ihr eigenes Admin-Konto außerhalb der Gruppe jump, damit Sie weiterhin eine Shell haben.
Die sshd-Konfiguration
# /etc/ssh/sshd_config.d/10-bastion.conf
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
AllowAgentForwarding no
AllowTcpForwarding no
AllowStreamLocalForwarding no
X11Forwarding no
PermitTunnel no
GatewayPorts no
LogLevel VERBOSE
Match Group jump
AllowTcpForwarding local
PermitOpen 10.0.1.10:22 10.0.1.11:22
PermitTTY no
ForceCommand /usr/sbin/nologin
Jede Einstellung im Block hat eine Aufgabe:
AllowTcpForwarding localerlaubt Sprünge und-L, aber nicht-R.PermitOpennennt, wohin sie gehen dürfen. Listen Sie jeden Server auf:*kann für einen ganzen Host oder Port stehen, aber nicht für einen Teil einer Adresse wie10.0.1.*.PermitTTY noundForceCommandentfernen die Shell.ForceCommandallein stoppt die Weiterleitung nicht, und deshalb funktioniert es hier.
Legen Sie das in eine eigene Datei unter /etc/ssh/sshd_config.d/ und prüfen Sie zuerst, dass keine andere Datei dieselben Optionen früher setzt: sshd behält den ersten gelesenen Wert. Ein Match-Block in einer solchen Datei endet mit der Datei. Prüfen Sie dann und laden Sie neu, mit einer offen gelassenen Sitzung:
sudo sshd -t
sudo sshd -T -C user=alice,host=client,addr=203.0.113.10 | grep -iE '^(allowtcpforwarding|permitopen|permittty|forcecommand) '
sudo systemctl reload ssh
permittty no
allowtcpforwarding local
forcecommand /usr/sbin/nologin
permitopen 10.0.1.10:22 10.0.1.11:22
Der Pfad von nologin kann auf anderen Systemen /sbin/nologin sein, prüfen Sie ihn also mit command -v nologin.
DisableForwarding ist für andere Benutzer
DisableForwarding yes schaltet jede Weiterleitung ab und überstimmt die anderen Einstellungen, es ist also praktisch für eine Gruppe, die nie etwas weiterleiten darf. Verwenden Sie es nicht für Jump-Benutzer. Ein Sprung ist eine Weiterleitung, und in unserem Test scheiterte er mit stdio forwarding failed.
Darüber verbinden
ssh -J alice@bastion.example.com user@10.0.1.10
Oder, um Tipparbeit zu sparen, in ~/.ssh/config auf Ihrem eigenen Rechner:
Host bastion
HostName bastion.example.com
User alice
Host app1
HostName 10.0.1.10
User user
ProxyJump bastion
Führen Sie dann ssh app1 aus. Ihr Schlüssel muss auf dem Bastion und auf dem internen Server liegen. Mehr zur Client-Seite steht in Jump-Hosts und ProxyJump. Vermeiden Sie ForwardAgent, aus den Gründen in Risiken der Agent-Weiterleitung.
Testen, was abgelehnt wird
Das sind die Ergebnisse, die wir mit dieser Konfiguration erhielten, und Sie sollten dasselbe sehen:
| Test | Ergebnis |
|---|---|
ssh -J alice@bastion user@10.0.1.10 | Am internen Server angemeldet |
ssh -W 10.0.1.10:80 alice@bastion | stdio forwarding failed |
ssh -tt alice@bastion | PTY allocation request failed on channel 0 |
ssh alice@bastion id | This account is currently not available. |
ssh -N -o ExitOnForwardFailure=yes -R 8080:localhost:22 alice@bastion | Error: remote port forwarding failed for listen port 8080 |
Logging: was Sie bekommen und was nicht
Schon auf der Standardstufe wird jede Anmeldung mit dem Fingerprint ihres Schlüssels protokolliert, woran Sie erkennen, wer sich verbunden hat. LogLevel VERBOSE protokolliert auch abgelehnte Schlüssel. Eine Anmeldung sieht so aus:
Accepted publickey for alice from 203.0.113.10 port 51018 ssh2: ED25519 SHA256:NxFS05Q+k1zf...
Abgelehnte Ziele werden ebenfalls protokolliert:
Received request from 203.0.113.10 port 51036 to connect to host 10.0.1.10 port 80, but the request was denied.
Erfolgreiche Ziele werden nicht protokolliert, weder bei INFO noch bei VERBOSE. Wir haben es geprüft: Das Log des Bastions zeigt, dass alice sich verbunden hat, aber nicht, zu welchem Server sie weitergegangen ist. In unserem Test erschien das erst bei LogLevel DEBUG1, und das Handbuch warnt, dass Debug-Stufen private Angaben der Benutzer aufzeichnen können:
debug1: server_request_direct_tcpip: originator 127.0.0.1 port 65535, target 10.0.1.10 port 22
Lesen Sie also beide Seiten. Das Log des internen Servers zeigt, wer sich angemeldet hat und mit welchem Schlüssel, mit der Adresse des Bastions als Quelle. Führen Sie beide nach der Uhrzeit zusammen und senden Sie beide an einen Rechner außerhalb des Bastions, denn ein Angreifer mit root dort könnte die lokale Kopie bearbeiten. Wie Sie diese Logs lesen, steht in Anmeldeversuche prüfen.
Zugang entfernen
Nehmen Sie den öffentlichen Schlüssel des Benutzers vom Bastion, und er verliert diesen Weg zu allen Servern dahinter. Er kann weiterhin jeden internen Server nutzen, den er auf anderem Weg erreicht, entfernen Sie den Schlüssel also auch dort. Siehe Schlüssel sperren.
Fragen
Was ist der Unterschied zwischen Bastion-Host und Jump-Host?
Gering. Ein Jump-Host ist jeder Server, über den Sie einen anderen erreichen. Ein Bastion ist ein Jump-Host, der nur für diese Aufgabe eingerichtet und abgesichert ist, und der einzige Zugang von außen.
Braucht der Bastion meinen privaten Schlüssel?
Nein. Mit ProxyJump beginnt die Anmeldung am internen Server auf Ihrem eigenen Rechner und ist durchgehend verschlüsselt. Der Bastion leitet die Verbindung nur weiter.
Warum scheitert ssh -J mit stdio forwarding failed?
Der Bastion hat die Weiterleitung abgelehnt. Prüfen Sie, ob AllowTcpForwarding sie für Ihren Benutzer erlaubt, ob das Ziel in PermitOpen steht und ob DisableForwarding gesetzt ist.