Ich habe 3 Hosts:
- Mein Computer.
- Ein Jump Host (auch Bastion genannt) mit einer statischen IP.
- Ein Server mit einer dynamischen IP; hinter einem NAT-Router/einer NAT-Firewall, ohne geöffnete eingehende Ports.
Der Server stellt derzeit eine Verbindung zum Jump-Host her und baut einen SSH-Tunnel über auf -R "0:localhost:22"
, sodass der Port dynamisch vom Jump-Host zugewiesen wird (dies war bisher sehr zuverlässig).
Mit etwasSteckdosenmagie, ich habe die dynamisch zugewiesene Portnummer in einer Datei auf dem Jump Host aufgezeichnet.
Damit kann ich per SSH auf den Jump Host zugreifen undssh -p $(cat /path/to/port-file) localhost
Aber ist es möglich, diesen zusätzlichen Schritt zu überspringen?
Dies wäre für Ansible nützlich, wo inventory.yml
die Portnummer aktualisiert werden muss:
server:
# /usr/bin/ssh jh cat /path/to/port-file
ansible_port: "34625"
ansible_host: "localhost"
ansible_ssh_common_args: "-o ProxyCommand='ssh -q -W %h:%p jh' -o StrictHostKeyChecking=no"
Möglicherweise könnten Sie Folgendes verwenden ProxyCommand
:
Es kann (irgendwie) eine Befehlsersetzung auf die ~/.ssh/config
Datei meines Computers anwenden:
Host server
ProxyCommand ssh -q -W localhost:$(echo "34625") jh
Dies funktioniert (auch ohne echo -n
), wobei die Ersetzung auf meinem lokalen Computer zu erfolgen scheint.
Und trotz der Ineffizienz, SSH zu verwenden, um zuerst die Portnummer zu erhalten, funktioniert dies nicht:
Host server
ProxyCommand ssh -q -W localhost:$(ssh jh cat /path/to/port-file) jh
Es fuehrt zu:
Bad packet length 1349676916.
ssh_dispatch_run_fatal: Connection to UNKNOWN port 65535: message authentication code incorrect
Und seltsamerweise vermerkt der Server (am Ende der Kette) Folgendes in seinen Authentifizierungsprotokollen:
sshd[5558]: Bad protocol version identification '' from ::1 port 36048
Das bedeutet, dass die Portnummer zurückgegeben wird. Aber keine Ahnung, warum es an dieser Stelle abbricht.
Und ssh -vvv
zeigt, dass es den Hostschlüssel in meinem identifiziert ~/.ssh/known_hosts
.
Ich habe außerdem versucht, auf dem Jump Host eine benutzerdefinierte „ssh_config“-Datei ssh -F /path/to/ssh_config
mit folgendem Inhalt zu erstellen:
Host tunnel.server
HostName localhost
Port 34625
Aber ich glaube nicht, dass ich das mit dem verwenden kann ProxyCommand
.
Ich vermute auch, dass es StrictHostKeyChecking=no
möglicherweise irgendwann eingeführt werden muss, wenn sich die Portnummer ändert.
Antwort1
Zweite Teillösung, inspiriert von @anx...
Erstellen einer Socket-Datei
ssh -R '/path/to/socket-file:localhost:22' tunnel@jh
Um diesen Socket (vom Jump Host) zu verwenden, kann ich dann Folgendes verwenden socat
:
ssh -o "ProxyCommand socat - UNIX-CLIENT:/path/to/socket-file" localhost
Die Verwendung von socat
scheint ein unnötiger Schritt zu sein, da es sicher eine Möglichkeit geben muss, den ssh
Befehl dazu zu bringen, die Socket-Datei direkt zu verwenden, die ich aber noch nicht finden kann.
Ich habe auch nicht herausgefunden, wie ich diese Socket-Datei von meinem Computer aus verwenden kann (da ProxyCommand auf dem lokalen Host und nicht auf dem JumpHost ausgeführt wird).
Ich sollte auch beachten: Da das tunnel
Konto (auf dem Jump Host) sehr eingeschränkt ist (es ist nur dazu da, diese Tunnelverbindungen herzustellen), muss ich es StreamLocalBindMask=0111
so einrichten, dass mein Konto auf dem Jump Host diese Socket-Datei verwenden kann. Ebenso sollte die alte Socket-Datei entfernt werden, wenn eine neue Verbindung hergestellt wird, über StreamLocalBindUnlink=yes
.
Beide Optionen müssen auf dem Jump Host in „/etc/ssh/sshd_config“ festgelegt werden:
Match User tunnel
StreamLocalBindMask 0111
StreamLocalBindUnlink yes
Leider Match
werden Regeln in "/etc/ssh/sshd_config.d/tunnel.conf" vor OpenSSH 8.4, veröffentlicht am 27. September 2020, ignoriert (Fehlerbericht), und dies ist derzeit unter Ubuntu 20.04.1 LTS nicht verfügbar.
Antwort2
Vorübergehende Lösung, nicht ideal ...
Fügen Sie auf meinem Computer einen stündlichen Cron-Job hinzu, der die Portnummer(n) vom Jump-Host sammelt und eine neue ~/.ssh/config_tunnels
Datei erstellt.
#!/bin/bash
set -u;
config_path="${HOME}/.ssh/config_tunnels";
port=$(/bin/ssh jh /bin/cat /path/to/port-file 2> /dev/null | /bin/sed 's/[^0-9]//g');
if [[ "${port}" -lt 1024 ]]; then
exit; # Probably a blank/zero value (e.g. connection issue).
fi
{
echo "";
echo "Host server";
echo " ProxyCommand ssh -q -W localhost:${port} jh";
echo "";
} > "${config_path}";
chown user:group "${config_path}";
chmod 600 "${config_path}";
Die Hauptdatei ~/.ssh/config
kann dann verwenden Include ~/.ssh/config_tunnels
.
Beachten Sie, dass ich sed
sicher bin, dass ich eine Nummer zurückbekomme. Wenn mein Jump Host kompromittiert werden sollte, möchte ich nicht, dass die Port-Datei eine zusätzliche (bösartige) SSH-Konfiguration enthält.