原文:多ssh key部署同一台server以及ssh-agent的最佳实践 - Noosphere
有些时候,我们需要在一台服务器里拉取github的项目,由于安全考虑,github的规定一个deploy key
只能用在一个项目里面。 所以多个项目就需要我们用多个ssh key
而我们如果只在一台服务器,除了默认生成的id_rsa
,则需要为每个项目加入生成一个独立的ssh key
,这样就存在多个秘钥和公钥对,那么我们执行git pull
或者git push
这样的命令的时候,ssh如何找到正确的key呢?
这个时候需要用到ssh的config以及ssh-agent来解决这个问题,下面我们一步步来说明这个过程。
生成新的密钥对
ssh-keygen -f ~/.ssh/project1_rsa
ssh-keygen -f ~/.ssh/project2_rsa
上面这个命令,一路回车的话,当然也可以输入密码,如果使用密码,那么在使用的时候则需要输入这个密码(通过ssh-agent这个代理程序可以帮你记住密码,则可以不用每次都输入),这个会在用户的目录下生成2个密码对,生成的内容如下:
ls ~/.ssh
project1_rsa # project1 的私钥
project1_rsa.pub # project2 的公钥
project2_rsa
project2_rsa.pub
然后,接下来,为了让ssh知道我们生成的密钥对里面的私钥,需要用ssh-add
命令加入
ssh-add ~/.ssh/project1_rsa
如果报下面这个错误:
Could not open a connection to your authentication agent.
则说明ssh-agent
代理程序没有启动,那么再返回来启动这个代理程序,然后再加入
eval `ssh-agent -s` # 启动代理
ssh-add ~/.ssh/project1_rsa
ssh-add ~/.ssh/project2_rsa
这里有个问题,ssh-agent
不一定是默认启动的,这个agent在下一个终端会话进来后可能用不了,这个问题我们后面在说。
接下来,为了完成让git pull的时候,自动认得目录,接下来,我们要做两个配置
1. 创建~/.ssh/config
touch ~/.ssh/config
把下面内容贴进去
Host project1
HostName github.com
User git
IdentityFile /home/ubuntu/.ssh/project1_rsa
Host project2
HostName github.com
User git
IdentityFile /home/ubuntu/.ssh/project2_rsa
这个配置的意思是,当ssh碰到要去连接的Host为project1的时候,会把HostName 设置为 github.com,并且使用git用户,私钥使用的是IdentityFile /home/ubuntu/.ssh/project1_rsa
2. 修改git remote
进入你的github项目
git remote set-url origin git@project1:/project1.git
- your github name: 是你在github注册的名字
由于这里使用的git ssh协议,那么在你执行git pull
这些命令的时候,它会去寻找命令~/.ssh/config
里面的配置,然后找到根据git@project1
来找到Host project1
的配置,然后机会ssh会使用这些配置来执行命令。
ssh-agent自动启动
ssh-agent进程一般来说会自动启动,并会自动加载~/.ssh/id_rsa
,它启动的时候,创建一个继承SSH_AUTH_SOCK
和SSH_AGENT_PID
环境变量的进程,那么如果你开的会话并没有这些环境变量,那么你的会话无法正确的链接到ssh-agent,即使你用ps -aux | grep ssh-agent
可以看到有这个进程,甚至可能有多个ssh-agent(因为你在多个会话里面执行过多次”eval ssh-agent -s
“)也无济于事。
如果没有这些环境变量,你执行ssh-add
命令的时候,它连不到已经启动的ssh-agent
,所以会报Could not open a connection to your authentication agent.
这样的错误。
所以我们确保我们启动会话的时候启动ssh-agent
。为了实现这个你可以在~/.bashrc
或者~/.bash_profile
或者~/.profile
这些会话启动的时候会加载shell里面加入启动命令,实现的方法有多种,比如你可以直接加入eval
ssh-agent -s``. 那么而每次启动,然后同时加入trap 'kill $SSH_AGENT_PID' EXIT
,让会话退出的时候kill掉这个启动的经常。 然而这样做,每当你其他一个shell就会创建一个ssh-agent的进程。
为了解决这个问题,可以用封装成下面的命令,加入到~/.bashrc
(~/.bash_profile
或者~/.profile
)
SSH_ENV="$HOME/.ssh/agent-environment"
function addAdditionSSHKey {
/usr/bin/ssh-add $HOME/.ssh/project1_rsa;
/usr/bin/ssh-add $HOME/.ssh/project2_rsa;
}
function start_agent {
echo "Initialising new SSH agent..."
/usr/bin/ssh-agent | sed 's/^echo/#echo/' > "${SSH_ENV}"
echo succeeded
chmod 600 "${SSH_ENV}"
. "${SSH_ENV}" > /dev/null
/usr/bin/ssh-add; # add default id
addAdditionSSHKey; # add addition ids
}
# Source SSH settings, if applicable
if [ -f "${SSH_ENV}" ]; then
. "${SSH_ENV}" > /dev/null
#ps ${SSH_AGENT_PID} doesn't work under cywgin
ps -ef | grep ${SSH_AGENT_PID} | grep ssh-agent$ > /dev/null || {
start_agent;
}
else
start_agent;
fi
其中addAdditionSSHKey
可以配置你要加入的私钥,每次你加入新的私钥的后,都可以直接在新的会话窗口直接执行addAdditionSSHKey
帮助你加入新的key
这个段shell会先判断~/.ssh
目录下面存储的agent-environment
环境变量信息是否存在,如果存在,说明之前已经启动了一个ssh-agent进程,只需要把它的变量export到当前的会话即可,如果没有,则启动一个新的ssh-agent,并把相关环境变量保存下来
这个agent-environment
环境变量存储的信息大约如下,
SSH_AUTH_SOCK=/tmp/ssh-qyakUB3GkFmc/agent.9914; export SSH_AUTH_SOCK;
SSH_AGENT_PID=9916; export SSH_AGENT_PID;
#echo Agent pid 9916;
. "${SSH_ENV}" > /dev/null
则个语句就是执行命令,把已经保存的环境变量export到当前的会话。