ssh-agent后台运行
介绍 ssh-agent 原理以及使用方法。
描述
因为要在本机执行一些git操作,配置了多ssh-key,但每次打开终端都要执行eval $(ssh-agent -s)
然后再执行ssh-add
操作,查看ssh-agent手册发现ssh-add 这个命令不是用来永久性的记住你所使用的私钥的。
实际上,它的作用只是把你指定的私钥添加到 ssh-agent
所管理的一个session 当中。而 ssh-agent 是一个用于存储私钥的临时性的 session 服务,也就是说当你重启之后,ssh-agent服务也就重置了。
最快速的解决办法就是:
vim ~/.bashrc
添加
eval
ssh-agent -s# ssh-agent 依赖于特殊环境变量,使用 eval 以正确产生环境变量
ssh-add $HOME/.ssh/id_rsa
但这样会有个问题,当退出运行 ssh-agent 的会话后,ssh-agent 会被关闭,这样一来会影响后续密钥认证过程,导致自动 ssh 失败、ssh 脚本运行出错…
而且如果打开多终端后,后台会开启多个ssh-agent进程.
让我们先来看一下ssh-agent是如何工作的:
$ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-sp4EAi4iNWF5/agent.26520; export SSH_AUTH_SOCK;
SSH_AGENT_PID=26521; export SSH_AGENT_PID;
echo Agent pid 26521;
ps x | grep ssh-agent
21983 ? Ss 0:00 ssh-agent
26521 ? Ss 0:00 ssh-agent
26540 pts/5 S+ 0:00 grep --color=auto ssh-agent
我们可以从第一个命令中得到$SSH_AUTH_SOCK
以及 $SSH_AGENT_PID
.
其中,$SSH_AGENT_PID
这个就是ssh-agent的id,我们可以通过ssh-agent -k $SSH_AGENT_PID
来干掉它
非常重要的环境变量是$SSH_AUTH_SOCK
, 这个环境变量非常重要,如果这个变量有问题,你无法使用ssh-add命令来添加私钥
在~/.bashrc中使用脚本使ssh-agent后台运行
对于 Gnome
,GNOME SSH Keyring Agent
较好地处理了 ssh-key
的使用问题。
对于非 gnome 的 bash 环境,可以将如下命令添加到 ~/.bashrc
或者~/.bash_profile
中来加载无密码的 ssh-key:
下面的脚本可让ssh-agent在后台运行并使多终端使用同一个ssh-agent服务且自动添加$HOME/id_rsa
私钥文件。
findAgent=`find /tmp/ -type s -name agent.\* 2> /dev/null | grep '/tmp/ssh-.*/agent.*'`
if [ $? -ne 0 ];then
eval `ssh-agent`
#ln -sf "$SSH_AUTH_SOCK" $findAgent
ssh_keys=`find $HOME/.ssh/ -name "id_rsa*" |grep -v pub`
ssh_agent_keys=$(ssh-add -l | awk '{key=NF-1; print $key}')
ssh_keys_count=`find $HOME/.ssh/ -name "id_rsa*" |grep -v pub |wc -l`
ssh_agent_keys_count=$(ssh-add -l | awk '{key=NF-1; print $key}' |wc -l)
for k in "${ssh_keys}"; do
for l in "${ssh_agent_keys}"; do
if [ $ssh_keys_count != $ssh_agent_keys_count ];then
if [ "$k" != "$l" ]; then
ssh-add $k > /dev/null 2>&1
fi
fi
done
done
else
export SSH_AUTH_SOCK=$findAgent
ssh_keys=`find $HOME/.ssh/ -name "id_rsa*" |grep -v pub`
ssh_agent_keys=$(ssh-add -l | awk '{key=NF-1; print $key}')
ssh_keys_count=`find $HOME/.ssh/ -name "id_rsa*" |grep -v pub |wc -l`
ssh_agent_keys_count=$(ssh-add -l | awk '{key=NF-1; print $key}' |wc -l)
for k in "${ssh_keys}"; do
for l in "${ssh_agent_keys}"; do
if [ $ssh_keys_count != $ssh_agent_keys_count ];then
if [ "$k" != "$l" ]; then
ssh-add $k > /dev/null 2>&1
fi
fi
done
done
fi
关闭终端时退出ssh-agent
vim ~/.bash_logout
if [ -n "$SSH_AUTH_SOCK" ] ; then
eval `/usr/bin/ssh-agent -k`
fi
如果 ssh-key
有密码,可以考虑在脚本中使用 expect
自动交互加载 key files,此方法适用于bash终端,对于zsh可能有点问题.
使用keychain控制ssh-agent后台运行
keychain is a small utility which manages ssh-agent on your behalf and allows the ssh-agent to remain running when the login session ends. On subsequent logins, keychain will connect to the existing ssh-agent instance. In practice, this means that the passphrase must be be entered only during the first login after a reboot. On subsequent logins, the unencrypted key from the existing ssh-agent instance is used. This can also be useful for allowing passwordless RSA/DSA authentication in cron jobs without passwordless ssh-keys.
To enable keychain, install it and add something like the following to ~/.bash_profile:
sudo apt-get install keychain
eval `keychain --agents ssh --eval id_rsa`
From a security point of view, ssh-ident and keychain are worse than ssh-agent instances limited to the lifetime of a particular session, but they offer a high level of convenience. To improve the security of keychain, some people add the –clear option to their ~/.bash_profile keychain invocation. By doing this passphrases must be re-entered on login as above, but cron jobs will still have access to the unencrypted keys after the user logs out. The keychain wiki page has more information and examples.
TIP
类似的工具还有GNOME Keyring
和 KWallet
,有兴趣的可自行了解。
使用ssh-agent.service控制ssh-agent后台运行
On Arch Linux, the following works really great (should work on all systemd-based distros):
Create a systemd user service, by putting the following to ~/.config/systemd/user/ssh-agent.service
:
[Unit]
Description=SSH key agent
[Service]
Type=forking
Environment=SSH_AUTH_SOCK=%t/ssh-agent.socket
ExecStart=/usr/bin/ssh-agent -a $SSH_AUTH_SOCK
[Install]
WantedBy=default.target
Setup shell to have an environment variable for the socket (.bash_profile, .zshrc, …):
export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-agent.socket"
Enable the service, so it’ll be started automatically on login, and start it:
systemctl --user enable ssh-agent
systemctl --user start ssh-agent
Add the following configuration setting to your ssh config file ~/.ssh/config
(this works since SSH 7.2):
AddKeysToAgent yes
This will instruct the ssh client to always add the key to a running agent, so there’s no need to ssh-add it beforehand.
参考:
How can I run ssh-add automatically, without password prompt
How to make ssh-agent automatically add the key on demand