当我向 Google 询问 ssh 代理转发如何工作时,它给我提供了许多 SEO 优化垃圾链接,解释了如何配置 ssh-agent。这不是我问的。
我目前遇到一个问题,在 VPN 连接远端的屏幕会话中启动的作业会失败,因为在 VPN 发生故障后它们无法通过 ssh 连接。
通常这些作业依赖于来自源客户端的代理转发来进行连接。我怀疑这里出了什么问题,但更好地了解整个代理转发会有所帮助。
当我从 host0 连接到 hosta 时,host0 上的 ssh-agent 会将我的私钥提供给 host0 上的 ssh 客户端。在 hosta 上,我看到 SSH_AUTH_SOCK 已填充,引用本地套接字。如果我在 hosta 上 ssh hostb,ssh 客户端会以某种方式连接到 host0 上的 ssh-agent。大概是使用 host0-hosta ssh 连接中的备用通道。
hosta 上的 $SSH_AUTH_SOCK 发生了什么?
(fuser $SSH_AUTH_SOCK 表明没有任何东西打开)
就我的屏幕会话而言,如果启动屏幕会话的 ssh 会话已结束,并且我从 host0 到 hosta 启动新的 ssh 会话,那么来自屏幕会话的密钥请求是否会通过新连接发送?
好吧,任何需要 SSH 代理的东西都会查找环境变量
SSH_AUTH_SOCK
来找出用于访问代理的 Unix 套接字的路径。至少在 的手册页ssh-add
中提到了这一点。(该路径可能看起来像/tmp/ssh-XXXXi1AqzV/agent.1149174
。)当您启动代理时,它会打印出一组命令来设置该环境变量和其他环境变量。此外,当您使用 连接到某个地方时
ssh -A
,客户端会请求代理转发,远程 SSH 服务器会为会话设置该环境变量。但是...当您运行 screen 时,screen 会话内的进程看不到 screen 外的会话设置的环境变量。它们所拥有的只是
SSH_AUTH_SOCK
screen 会话启动时设置的变量(如果有的话)。进程启动时,环境变量从父进程继承,并且不能从外部更改,因此您无法自动为 screen 内的进程提供新路径。(您可以检查新路径并将其分别分配给每个 shell,但这很快就会让人厌烦。)任何解决方案都要求环境变量在屏幕会话的整个生命周期内保持不变。幸运的是,Unix 套接字只是文件,因此您可以让环境变量指向具有已知路径的符号链接,并在打开新的 SSH 会话时更改链接目标。
我的解决方案大致如下:
~/.screenrc
:~/.ssh/rc
:可能还有其他方法。这种方法的一个缺点是链接始终指向上次打开的 SSH 会话(使用代理转发)创建的套接字。因此,如果我打开两个会话并关闭第二个会话,则 screen 中的进程将无法找到代理。
当@ikkachu 向我指出一个解决方案时,我在这里分享我实施的细节。
首先要注意的是,在本地机器上运行的 ssh-agent 不仅仅是密钥的存储库;它处理用于协商(对称)会话密钥的非对称加密/解密。因此,您的私钥不会暴露在本地机器以外的任何地方(我提到这一点是因为我在 Google 为我找到的结果中没有看到这一点)。值得记住的是,ssh 会在使用的每个小时重新协商密钥。
为了允许恢复,我将其添加到 ssh 服务器上的 bash_profile 中:
为了便于维持连接,我编写了一个 ssh 包装器,它将在以下情况下自动重新连接:
此外,我将 connectTimeout 设置为 10 秒,将 clientAliveInterval 设置为 10 秒。此处另一个有用的功能是结合语音合成,当事情没有按计划进行时提醒我:
总的来说,这些并不能阻止远程主机的 ssh 继续传输失败,但可以大大减少这种情况发生的时间。当最小化/后台窗口中的任务失败时,我应该几乎立即意识到。