我有 3 個主機:
- 我的電腦。
- 具有靜態 IP 的跳轉主機(又稱堡壘)。
- 具有動態IP的伺服器;在 NAT 路由器/防火牆後面,沒有開啟入站連接埠。
伺服器目前連接到Jump Host,並透過 建立SSH隧道-R "0:localhost:22"
,因此連接埠由Jump Host動態分配(到目前為止這已經非常可靠)。
和一些套接字魔法,我將動態分配的連接埠號碼記錄在跳轉主機上的一個檔案中。
有了這個,我可以透過 SSH 連接到 Jump Host,然後運行ssh -p $(cat /path/to/port-file) localhost
但是否可以跳過這個額外的步驟呢?
這對於 Ansible 很有用,我inventory.yml
需要更新連接埠號碼:
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"
或許可以使用ProxyCommand
:
它可以(某種程度上)在我的電腦~/.ssh/config
檔案上使用命令替換:
Host server
ProxyCommand ssh -q -W localhost:$(echo "34625") jh
echo -n
當替換似乎發生在我的本機電腦上時,這可以工作(即使沒有)。
儘管首先使用 SSH 獲取連接埠號碼的效率很低,但這不起作用:
Host server
ProxyCommand ssh -q -W localhost:$(ssh jh cat /path/to/port-file) jh
結果是:
Bad packet length 1349676916.
ssh_dispatch_run_fatal: Connection to UNKNOWN port 65535: message authentication code incorrect
奇怪的是,伺服器(在鏈的末尾)確實在其身份驗證日誌中註意到了這一點:
sshd[5558]: Bad protocol version identification '' from ::1 port 36048
這意味著正在返回連接埠號。但不知道為什麼它會在此時破裂。
並ssh -vvv
表明它識別了我的~/.ssh/known_hosts
.
我還嘗試使用 , 在跳轉主機上建立自訂「ssh_config」文件,其ssh -F /path/to/ssh_config
內容為:
Host tunnel.server
HostName localhost
Port 34625
但我認為我不能將其與ProxyCommand
.
我還懷疑StrictHostKeyChecking=no
當連接埠號碼發生變化時,可能需要在某個時候引入。
答案1
第二個部分解決方案,受到@anx的啟發...
建立套接字文件
ssh -R '/path/to/socket-file:localhost:22' tunnel@jh
然後,要使用此套接字(來自 Jump Host),我可以使用socat
:
ssh -o "ProxyCommand socat - UNIX-CLIENT:/path/to/socket-file" localhost
使用socat
似乎是一個不必要的步驟,我確信一定有一種方法可以讓命令ssh
直接使用套接字文件,但我還找不到它。
我還沒有找到如何從我的電腦使用此套接字檔案(因為 ProxyCommand 在本機上運行,而不是在 JumpHost 上運行)。
我還應該注意;由於tunnel
帳戶(在跳轉主機上)非常受限制(它只能建立這些隧道連接),我需要進行設置,StreamLocalBindMask=0111
以便我在跳轉主機上的帳戶可以使用此套接字檔案。同樣,如果透過 建立新連接,則應刪除舊的套接字檔案StreamLocalBindUnlink=yes
。
這兩個選項都需要在跳轉主機上的「/etc/ssh/sshd_config」中設定:
Match User tunnel
StreamLocalBindMask 0111
StreamLocalBindUnlink yes
不幸的是,Match
在 2020 年 9 月 27 日發布的 OpenSSH 8.4 之前,「/etc/ssh/sshd_config.d/tunnel.conf」中的規則被忽略(錯誤報告),並且目前在 Ubuntu 20.04.1 LTS 上不可用。
答案2
臨時解決方案,不太理想...
在我的電腦上新增每小時一次的 cron 作業,它從跳轉主機收集連接埠號,並建立一個新~/.ssh/config_tunnels
檔案。
#!/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}";
然後主~/.ssh/config
文件就可以使用Include ~/.ssh/config_tunnels
.
請注意,我用來sed
確保我能得到一個號碼。如果我的跳轉主機受到威脅,我不希望連接埠檔案包含一些額外的(惡意)SSH 配置。