通过 SSH 隧道透明地使用 CVS

通过 SSH 隧道透明地使用 CVS

这看上去很简单,但我却陷入困境。

在 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 完成隧道处理后如何终止隧道,也因为我无法使用autosshsshpass所以我决定添加一个 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 重启可能完全没有必要,但无论如何,如果出现问题,这样做似乎是一种安全的做法。

相关内容