这看上去很简单,但我却陷入困境。
在 Ubuntu 机器上,要 ssh 到特定的REMOTE_HOST
机器,到目前为止我可以这样做
ssh REMOTE_HOST
正如预期的那样(所有密钥都设置好了)。现在,我不得不通过一台特定的BRIDGE_HOST
机器设置一个 ssh 隧道,
ssh -L 2222:REMOTE_HOST:22 BRIDGE_HOST -N -f
然后我可以使用 ssh 连接到 REMOTE_HOST
ssh -p 2222 localhost
虽然事情有点复杂,但效果很好。以下是一些问题:
localhost
运行 OpenSSH_7.2p2,所以没有 -J / ProxyJump 选项,如果这有帮助的话。我无法更新 OpenSSH,或者至少我更愿意避免它。我必须
REMOTE_HOST
使用以下方式登录密码所以我需要使用sshpass
(请不要告诉我我不应该这样做,我无法控制这一点)。因此,ssh
上面的第一个命令并不像所示的那样,而是更复杂;然而,我认为它并没有增加任何内容来显示更复杂的版本。但这是我的一个限制,我担心,这会阻止一些更清晰的解决方案。没有打开任何 shell
REMOTE_HOST
,并且据我所知(或我理解)我只被允许设置隧道。
无论如何,我可以通过这两个步骤 ssh 进入REMOTE_HOST
,但我想做的是隐藏所有这些.ssh/config
以使其透明(特别是对于 CVS,见下文)。类似这样的操作似乎没问题:
Host REMOTE_HOST
Hostname localhost
Port 2222
ProxyCommand tcsh -c "ssh -L 2222:REMOTE_HOST:22 BRIDGE_HOST -N -f; nc %h %p"
如果我现在跑
ssh REMOTE_HOST
我可以 ssh 进入,REMOTE_HOST
就好像隧道不存在一样。太好了。
最后一个复杂因素(也是问题)是我想将此 ssh 连接也用于 CVS。从 CVS 方面来看,一切都设置得很好(例如,当我不需要使用 时,它就可以正常工作BRIDGE_HOST
)。如果我现在运行
cvs up
在适当的目录中,一切似乎都运行良好……但cvs
命令在正确完成其工作后永远不会终止。我似乎明白这是因为创建隧道的 ssh 在最后仍在运行。我很乐意杀死它,但我不知道该怎么做。相关地,请注意,如果我省略了ProxyCommand
并且.ssh/config
如果之前手动设置了隧道,则一切都很好,CVS 运行顺利(并终止)。我会忘记ProxyCommand
并设置autossh
但我知道它不适用于sshpass
。我可以设置一个 cron 作业或一些手动保持隧道活动的脚本,但我认为(或希望)一定有更好的方法……
实现我想要的结果的正确、最简单、最干净的方法是什么?也就是说,尽管我无法控制cvs
插入,但还是像往常一样使用?BRIDGE_HOST
答案1
localhost 运行 OpenSSH_7.2p2,因此没有 -J / ProxyJump 选项,如果这有帮助的话。我无法更新 OpenSSH,或者至少我更愿意避免这样做。
与 ProxyJump 相近的版本是:
Host REMOTE_HOST
ProxyCommand "ssh -W %h:%p BRIDGE_HOST"
这实际上是 ProxyJump 在后台执行的操作。两者之间唯一真正的区别是 ProxyJump 会自动将某些其他选项(例如详细-v
模式)复制到所有相关连接。
如果桥接服务器允许使用创建隧道,-L
那么它会自动允许-W
(并且-D
也允许),因为它们都使用相同的 SSHv2 通道类型;服务器不知道其中的区别。
这应该也可以使用 sshpass 作为命令。或者,为了避免多次重新输入密码,您可以对桥接主机使用连接多路复用:
Host BRIDGE_HOST
ControlMaster auto
ControlPath ~/.ssh/S.%r@%h:%p
第一次连接到 BRIDGE_HOST 将会在后台留下一个进程;或者,您可以使用ssh -fNM BRIDGE_HOST
(如果需要,可以使用 sshpass)来启动后台进程,将来它将ssh -w ... BRIDGE_HOST
自动使用。
在您的 tcsh+nc 示例中,该命令最好写成:
Host REMOTE_HOST
ProxyCommand tcsh -c "ssh -L 2222:%h:%p BRIDGE_HOST -N -f; nc localhost 2222"
答案2
由于我无法理解 CVS 完成隧道处理后如何终止隧道,也因为我无法使用autossh
,sshpass
所以我决定添加一个 cron 作业。
我首先创建了一个小脚本,将网上找到的一堆食谱和想法整合在一起。脚本如下:
myself=${BASH_SOURCE[0]}
for pid in $(pgrep -d " " $myself); do
if [ $pid != $$ ]; then
kill -9 $pid
fi
done
while true
do
pkill -f "sshpass.*2222:"
sshpass -p PASSWORD ssh -o ServerAliveInterval=60 -L 2222:REMOTE_HOST:22 BRIDGE_HOST -l USER -N
sleep 1
done
本质上,它首先会终止自身的任何其他副本,然后终止同一端口上的现有隧道并启动所需隧道,并在每次ssh
终止时永远重复此操作。它是一种穷人版的autossh
。
与此.ssh/config
文件一起
Host REMOTE_HOST
Hostname localhost
Port 2222
这使得ssh
(和 CVS)表现得好像 REMOTE_HOST 仍然可直接访问。
可以通过以下方式方便地调用该脚本cron
:
@reboot /PATH/TO/THE/SCRIPT &
30 4 * * * /PATH/TO/THE/SCRIPT &
每天凌晨 4:30 重启可能完全没有必要,但无论如何,如果出现问题,这样做似乎是一种安全的做法。