答案1
理论
您寻求的功能称为“SSH 代理转发”。它的工作原理如下:
- 您的本地计算机中正在运行一个代理(通常是一个程序
ssh-agent
)(或已从其他地方转发)。其他程序可以通过 UNIX 域套接字与代理通信,只要它们知道套接字的路径即可。正确的设置可提供正确的路径。 - 您可以根据需要向代理添加密钥(
ssh-add …
),或者像程序一样ssh
添加他们使用的密钥(如果已配置为这样做)。 - 程序使用代理,而不是自己使用密钥。在我的这个答案我们会说他们要求代理人为他们解决难题。
- 您使用
ssh -A
本地连接到 SSH 服务器。您在服务器上运行的程序将能够与您的本地代理通信。您运行的任何知道如何与代理通信或ssh
在后台使用的东西都将能够使用您的本地代理。代理在另一台计算机上的事实对他们来说并不重要。
启动代理
启动代理的方法有以下几种:
某些系统配置为在用户登录时启动代理。每个用户都有自己的代理。您的操作系统可能已经为您启动了代理。在 shell 中调用:
env | grep '^SSH_AUTH_SOCK='
非空输出表示
SSH_AUTH_SOCK
变量在环境中。它的值是(或至少应该是)允许程序与已运行代理进行通信的 UNIX 域套接字的路径。程序通过检查此确切的环境变量来查找套接字。变量的存在通常意味着代理正在运行并准备就绪。命名的变量SSH_AUTH_SOCK
没有指向正在运行的代理的套接字是不正常的(出了问题)。如果您看到变量,则很可能有代理为您服务。继续阅读本回答的下一部分。
您可以通过在 shell 中调用来启动代理
ssh-agent
,但不要直接这样做。您希望程序能够在环境中找到正确的变量。Solessh-agent
无法改变其父 shell 的环境。它打印旨在由 shell 评估的命令,因此 shell 本身会更改其自己的环境。您可以调用ssh-agent
以查看它打印的内容,然后kill
从输出中了解 PID,否则无用的代理将继续徒劳无功地运行。正确的命令是:
eval "`ssh-agent`"
有几件事需要解释:
eval
可能很危险您可能听说过“eval
是邪恶的”。在这里,这是正确的,因为ssh-agent
它是少数专门设计用于eval
安全使用的工具之一。不同的 shell 需要不同的语法。
ssh-agent
打印的内容需要与 shell 匹配。该工具打印在sh
(和具有类似语法的 shell,例如 Bash) 或csh
(和具有类似语法的 shell) 中有效的 shell 代码。ssh-agent
通过检查变量来猜测正确的样式SHELL
;如果它无法猜测,那么它将为 生成代码。您可以使用(对于-like shell) 或(对于-like shell)sh
明确告诉它您需要什么样式。命令将类似于:-s
sh
-c
csh
eval "`ssh-agent -s`"
如果你想看到差异,请调用
ssh-agent -s
和ssh-agent -c
而不调用eval
。之后不要忘记kill
正确的 PID。如今我们经常使用
$()
而不是反引号(这是正确的做法,$()
更好),但$()
在 中不起作用。此答案使用反引号在类似 shellcsh
中同样有用sh
和类似csh
贝壳。
命令执行后
eval …
,env | grep '^SSH_AUTH_SOCK='
应该会显示一些内容。代理将一直运行,直到您将其杀死。杀死代理的最正确方法是:eval "`ssh-agent -k`"
在与之前相同的 shell 中(如果需要,请使用
-s
xor-c
)。没有eval
该命令可以终止代理,但变量将保留在 shell 的环境中。无论您在此 shell 中执行什么操作,变量都将保留在继承它们并仍在运行的子进程的环境中。启动代理的另一种方法是这样的:
ssh-agent some_command …
该工具将启动代理,然后
some_command …
在正确的环境中运行。some_command
可能是bash
,即如果你这样做:ssh-agent bash
然后你会发现自己处于一个已经在环境中的交互式 Bash 中
SSH_AUTH_SOCK
(注意,如果你的原始 shell 也是 Bash,那么该命令可能看起来什么都没做;就像bash
从 Bash 调用可能看起来没有任何操作,直到你exit
发现你仍然在 Bash 中)。代理
some_command
终止时自动退出,无需维护。这种方法相当简单。如果你只需要一个本地代理,
ssh
那么some_command
可能是ssh
。在你的情况下,你需要ssh -A
:ssh-agent ssh -A …
根据您要使用的密钥和 的配置
ssh
,上述方法可能是好主意,也可能不是。在某些情况下,您可能希望在运行之前对代理执行某些操作ssh -A
(例如添加密钥,见下文)。
为代理添加密钥
当代理启动时,它没有任何私钥。如果您发现由操作系统启动的代理,理论上操作系统可能不仅启动了代理,还添加了一些密钥。使用ssh-add
或按在 中设置ssh
时添加密钥。AddKeysToAgent
ssh_config
在可以访问代理的 shell 中(SSH_AUTH_SOCK
在环境中,代理正在运行)调用:
ssh-add -l
查看代理所代表的密钥(身份)。可能没有。要添加密钥,请运行:
ssh-add path/to/key
注意ssh-add
,不带参数会探测一些标准路径名并添加找到的文件。请参阅man 1 ssh-add
了解详情。
如果AddKeysToAgent
已设置ssh_config
(默认情况下未设置)或者您在命令行中请求它,ssh
它本身将添加它使用的密钥。这意味着如果您想使用相同的密钥向服务器进行身份验证,然后稍后在服务器上进行身份验证,则不需要ssh-add
。您可以执行以下操作:
# with agent already running
ssh -A -o AddKeysToAgent=yes …
这也适用于指定的键-i
。这些情况允许您ssh
在一个命令中运行代理和(上一节末尾提到的方法):
# already running agent (if any) is irrelevant
# we are starting a new agent
ssh-agent ssh -A -o AddKeysToAgent=yes …
调用ssh
相关选项是-A
。从man 1 ssh
:
-A
允许转发来自身份验证代理(例如)的连接ssh-agent(1)
。 也可以在配置文件中按主机指定此功能。
(配置文件中的关键字是ForwardAgent
。
服务器可能允许或不允许转发。AllowAgentForwarding
请DisableForwarding
参阅man 5 sshd_config
。
被警告:
应谨慎启用代理转发。能够绕过远程主机上的文件权限(对于代理的 UNIX 域套接字)的用户可以通过转发的连接访问本地代理。攻击者无法从代理获取密钥材料,但他们可以对密钥执行操作,使他们能够使用加载到代理中的身份进行身份验证。[…]
如果服务器允许转发,并且已将正确的密钥添加到本地代理,那么-A
您只需将其添加到ssh
用于连接服务器的命令中即可。它可能很简单:
ssh -A user@server
并且使用ForwardAgent yes
in ssh_config
(或在您的~/.ssh/config
) 您甚至不需要-A
在命令行中,纯ssh user@server
就可以了。
服务器情况
如果您的本地ssh -A …
为您提供了一个交互式远程 shell,那么您可以使用与我们之前(本地)使用的相同的命令,现在在服务器上:
# on the server
env | grep '^SSH_AUTH_SOCK='
如果转发成功,您将发现变量已设置。它就像ssh-agent
正在运行一样,但实际上是 SSH 服务器监听套接字并中继到您的本地ssh-agent
。使用套接字的程序并不关心。您甚至可以进一步转发代理(从ssh -A
服务器转发到另一台计算机)。
只需使用ssh
或另一个能够与代理通信的命令即可。它应该找到套接字并与本地通信ssh-agent
。
ssh-add
没有什么不同。这并不明显,但如果您ssh-add
在服务器上使用来添加一些密钥,那么该工具实际上会从服务器添加密钥(而不是告诉您的本地ssh-agent
打开具有相同路径的本地文件)。您可以断开与服务器的连接,而您的本地代理将继续持有添加的密钥。因此,本地ssh-agent
不仅允许您在服务器上使用本地密钥;它还允许您使用来自服务器的密钥从本地连接到任何地方。但这有很大的不同。ssh-agent
需要存储一些添加密钥的表示,即使只是在内存中。本地ssh-add
与本地对话ssh-agent
不会使本地密钥离开本地计算机。远程ssh-add
与本地对话ssh-agent
会将远程密钥复制到本地内存中。
如果您的本地ssh -A …
指定了要在服务器上运行的命令(而不是交互式 shell),则代理转发机制不会发生任何变化。远程命令将SSH_AUTH_SOCK
在环境中找到,并且能够与您的本地进行通信ssh-agent
。