避免单独将 ssh 密钥(带密码)添加到 shell 会话

避免单独将 ssh 密钥(带密码)添加到 shell 会话

注意:在 中添加几行.<name of shell>rc并不能解决这里的问题,因为这个特定的 ssh 密钥有一个密码,并且这并不能消除继续输入密码的需要。

所以我真的不明白ssh-agent幕后是如何工作的。我只是使用ssh-agentssh-add ~/.ssh/id_rsa每次我需要添加密钥来访问某些远程资源时。我已经添加了一次密钥,我不需要为同一个“shell 会话”再次添加它(“shell 会话”可能不是合适的术语)。

不幸的是,我一直在创建新的 shell 会话。我在 OS X 上的 tmux 下运行 zsh,并有一个创造性地命名为 的 ssh 密钥id_rsa。该 ssh 密钥有一个与之关联的密码。

每次启动新的 shell 时,我都必须执行以下操作

$ eval `ssh-agent`
$ ssh-add ~/.ssh/id_rsa
<type password>

这真的很令人恼火。

ssh-agent我注意到环境变量的输出SSH_AGENT_PID每次都不同。我的预感是这个环境变量和 是SSH_AUTH_SOCK不需要在单个 shell 会话中重新添加密钥的原因。当我调用该ssh程序时,它将使用这些环境变量与 进行通信,ssh-agent并且身份验证将成功。

我想知道是否有一种ssh-agent在会话之间共享 s 的方法。也许正确的方法是在启动之前添加 SSH 密钥tmux并配置tmux以保留SSH_AUTH_SOCKSSH_AGENT_PID环境变量。我真的不确定。解决这个问题的标准方法是什么?

答案1

ssh-agent 的工作方式是每个会话有一个代理。代理随会话开始和结束。

会话在您登录时启动,而不是在您打开终端或启动 shell 时启动。ssh-agent作为 shell 启动脚本的一部分系统地运行肯定是错误的。

我不是 OSX 用户,所以我可能会遗漏一些东西,但据我了解,在非古老的 ​​OSX 版本(自 10.5 起)上,SSH 与 OSX 钥匙串集成。所以你ssh-agent根本不应该跑。该SSH_AUTH_SOCK变量应指向 launchd 套接字(launchd 提供 ssh 代理服务)。看如何将 Mac OS X 钥匙串与 SSH 密钥一起使用?如何防止 ssh 将我的密钥添加到 Snow Leopard 上的 ssh-agent 中?

如果出于某种原因您想坚持使用ssh-agent,并且希望为所有会话使用一个代理(这也是有道理的),您可以为 SSH 套接字使用固定路径。 (我已经在 Windows 上完成了该操作。)在您的 中.profile,设置SSH_AUTH_SOCK为固定路径,ssh-agent如果尚未运行则启动。

export SSH_AUTH_SOCK=~/.ssh/auth_sock
if ! fuser "$SSH_AUTH_SOCK" >/dev/null 2>/dev/null; then
  # Nothing has the socket open, it means the agent isn't running
  ssh-agent -a "$SSH_AUTH_SOCK" -s >~/.ssh/agent-info
fi

请注意,我的代码不会尝试终止代理。如果您想在注销时终止代理,请在注销脚本中添加终止指令。当然,如果您终止以您的用户身份运行的所有进程,其中包括代理。

答案2

这是我的登录脚本中的一个小片段,用于处理您想要的内容:

SSHAF=$HOME/.ssh_agent_env
[ -f $SSHAF ] && . $SSHAF

# if ssh-agent not really running?
if [ -n "$SSH_AGENT_PID" ] && ! kill -0 $SSH_AGENT_PID >/dev/null
then ssh-agent >$SSHAF 
     . $SSHAF
     ssh-add # add list of more keys here if needed
fi

解释:我将 ssh-agent 的环境设置变量保存在 $HOME (.ssh_agent_env) 的点文件中,如果该文件存在(第 2 行),我将获取该文件以获取(可能)正在运行的 ssh-agent 的进程 ID。 (SSH_AGENT_PID 变量)如果设置了 SSH_AGENT_PID 变量,我会检查代理是否在其 PID 上使用kill -0 运行(如果进程正在运行,kill -0 将返回代码设置为0(真),1(假))否则,如果代理未运行,我将启动它并将输出保存在 .ssh_agent_env 文件中,获取该文件以将值添加到我的 shell 会话中,然后运行 ​​ssh-add 来缓存我的密钥。

第一次进入系统时,不存在文件,因此启动代理。该文件存在后的任何时间,我们都会验证代理是否正在运行。如果没有,我们就启动。

注意:这是我对上面第一个答案的解决方案 2 的运行实现。

答案3

基本上,它的作用ssh-agent是在后台启动自身,并打印一堆环境变量,ssh客户端实用程序使用这些变量来了解如何到达代理(主要是 中的套接字路径SSH_AUTH_SOCK)。如果您再次启动代理,您会运行多个副本,但您通常只能从一个 shell 访问一个副本...(检查类似的内容ps uax | grep agent以查看您正在运行多少个副本。)ssh-add运行时,它会联系代理,并要求它读取内存的密钥。之后,ssh连接到同一ssh-agent实例的任何客户端都可以利用保存的密钥。


有几种选择只运行一个ssh-agent

1)ssh-agent在开始tmux会话之前(或screen就此而言)开始。此时设置的环境变量应该继承到您在tmux或下运行的所有 shell screen。 (我不知道是否tmux需要特殊配置来不清理环境变量。)

我一直(错误的)懒惰,所以我只是在每次启动会话之前手动完成此操作,但是创建一个脚本来启动代理然后启动/会话screen会很容易。screentmux

如果您考虑图形桌面环境之类的环境,则应在 DE 启动时启动代理(如果可能),以便环境变量可用于您启动的任何终端。

2) 当您登录时,您的系统可能已经启动ssh-agent。在这种情况下,您应该能够只ssh-add键入它的密钥,而无需启动代理的新副本。特别是 OS X 在登录时启动代理,并修改了 SSH 工具,通过 GUI 请求密钥密码,并自动将命令中使用的密钥保存ssh到代理。您也可以ssh-add照常使用。

3) 如果您想在完全独立的 shell 中使用单个代理(因此无法继承环境变量),请检查代理是否正在从 shell 的启动脚本运行,如果没有则启动它。将代理的套接字地址保存到文件中,或使用套接字的固定路径。


无论如何,问题在于将环境变量指向相同的ssh-agent.您添加到代理的一个实例中的任何密钥都应该对同一代理的所有用户可见,无论您使用ssh-add的是什么 shell。

顺便说一句,ssh-add可以使用一个参数来定义密钥应保存多长时间:运行ssh-add -t 3600 my-key-file将告诉代理在一小时后忘记密钥。这可能有助于减少密钥在内存中未加密的时间。

答案4

理想情况下,您ssh-agent只启动一次,只运行ssh-add一次,后续 shell 将继承该代理。

如果您通过 GUI 登录并且窗口管理器使用.xsession.xinitrc,则可以将以下内容添加到该文件中:

if [ -z "$SSH_AUTH_SOCK" ]; then
  eval $(ssh-agent)
  ssh-add
fi

xterm这意味着窗口管理器生成的任何进程(或其他终端仿真器)都将继承该代理。

如果您在没有 X11 的情况下工作,那么会感到高兴一点,因为您很棒,然后将这些行添加到您的.bash_profile.profileshell 初始化脚本中。

将从当前 shell 中eval获取输出并对其进行评估,将和设置为任何值。然后将运行,与您手动执行的操作几乎一样。然后,该代理将被您登录后可能很快启动的会话继承(除非您已设置为实际的登录 shell,这是可能的)。ssh-agentSSH_AUTH_SOCKSSH_AGENT_PIDssh-addtmuxtmux

在完美的世界中,您只有一个正在运行的 SSH 代理,并且无需再次提供任何密码...直到您注销并再次登录,或在另一个控制台上登录。

相关内容