最近我将以下脚本添加到我的自动启动中(在 KDE 中):
eval `ssh-agent`
ssh-add
该脚本应在登录时启动,并询问我的密码并加载我的密钥。效果几乎没问题。脚本正确执行,代理启动,环境变量全部设置完毕,系统要求我输入密码。唯一的问题是此后密钥未加载。但是,如果我随后在终端中输入 ssh-add ,系统会要求我输入密码,并且密钥将存储在我的 X 会话的其余部分中。
我究竟做错了什么?尽管要求我输入密码,但为什么密钥未加载?
PS:我在 Debian jessie 上运行。
答案1
我能想到有两种可能的情况会导致这种情况。
这两者都源于许多桌面管理器推出自己的 ssh 密钥代理这一事实。这样做是因为代理需要在桌面管理器之前启动,以便由桌面管理器(您的终端仿真器)启动的应用程序拾取导出的变量。
在您启动桌面管理器后,您的桌面管理器将启动自己的 ssh 代理,并最终取代它。
我不确定您在什么时候或如何启动 ssh 代理,但如果桌面管理器在您的代理之后启动,其导出的变量将覆盖您创建的变量。
您的桌面管理器会在您之前启动自己的 ssh 代理,而您的桌面管理器不会被保留。
如果您只是启动终端窗口并执行,那么在您关闭终端窗口后,
eval $(ssh-agent); ssh-add
由此导出的变量将不会保留。ssh-agent
启动新的终端窗口后,您将获得由桌面管理器启动的 ssh 代理设置的变量。
工作方式ssh-agent
是在后台启动一个守护进程,然后打印出几个需要设置的变量。
$ ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-JLbBwVBP4754/agent.4754; export SSH_AUTH_SOCK;
SSH_AGENT_PID=4755; export SSH_AGENT_PID;
echo Agent pid 4755;
因此,当您设置时eval $(ssh-agent)
,您只需设置所有这些变量。
现在,变量只能由子级继承,因此为了使它们保留在桌面管理器中,必须在桌面管理器启动之前设置它们。这可能很难做到正确,并且因发行版而异。这就是许多桌面管理器自己这样做的原因。
请注意,有时也会在 pam 堆栈初始化期间完成此操作。
答案2
正如帕特里克指出的那样,您可能会ssh-agent
与桌面环境生成的实例竞争。好吧,“竞争”可能不是正确的词 - 允许其他应用程序与代理对话的变量必须位于其环境中。由于桌面会话中的所有应用程序都是由桌面环境的某些部分(假设它是会话管理器)以某种方式生成的,因此您首先需要将变量放入会话管理器的环境列表中。这可以通过两种方式发生:
会话管理器在内部执行此操作(取决于您在某处设置的某些选项)。这将包括由 PAM 模块生成的代理(从登录/会话管理器调用)。
通过像你这样的用户脚本。然而,这并不像看起来那么简单。当会话管理器运行您的脚本时,它会创建一个新进程 - 脚本解释器。在其环境中设置变量,但不能轻松导出回会话管理器(其父进程)。这相当于在 shell 中执行相同的操作 - 运行脚本不会对当前 shell 的环境产生任何影响。您必须
source
这样做 - 然后命令将由当前 shell 执行,从而使您可以访问更新/创建的变量。在会话管理器中执行此操作会相当复杂(因为它不是 shell 解释器)。因此你ssh-agent
并没有真正竞争。它只是坐在那里,带有ssh-add
从脚本加载的身份,没有人真正知道它。
要了解发生了什么,请检查1的输出
ps fax | grep -E "(ssh|gpg)-[a]gent"
并将你的脚本更改为
echo "SSH_AUTH_SOCK=$SSH_AUTH_SOCK" > ~/ssh-agent.stdout
echo "SSH_AGENT_PID=$SSH_AGENT_PID" >> ~/ssh-agent.stdout
eval `ssh-agent | tee -a ~/ssh-agent.stdout`
这会将变量的内容打印到文件中~/ssh-agent.stdout
,然后在处理之前添加该位置的输出ssh-agent
(从而导出变量)。将文件内容与环境变量进行比较SSH_AUTH_SOCK
,SSH_AGENT_PID
例如在新创建的 shell 终端中。在大多数情况下,您将能够分辨出哪个是先启动的,因为 PID 是(循环)单调增长的。之所以存在该部分,是因为某些 DE也使用提供 SSH 代理服务gpg-agent
的能力。gpg-agent
您还可以ssh-agent
完全删除该行调用 - 如果您的脚本在 SSH 代理生成桌面环境后运行,您将看到密码对话框(顺便说一下,对于正确的代理),因为环境变量将存在。如果没有,则意味着您的脚本在 DE 的代理实例之前运行,因此根本无法访问任何代理。
1括号是巧妙的技巧grep
从进程列表中删除自身。