缘起
敝公司的线上环境与业界大拿相仿,躲在防火墙后面,需要通过跳板机登录。在本文描述的问题出现之前,
我们的 capistrano 部署脚本一直采用的方式是,配置 :gateway
,让 capistrano 处理中转。
capistrano 的原理 是利用跳板机开一个 SSH 隧道,然后本地连接这个隧道,执行操作,等同与以下命令:
# Term 1
ssh -N 9999:prod.server:22 -L jake@login1
# Term 2
ssh jake@127.0.0.1:9999
元旦之后,这种方式宣告失败,ssh jake@127.0.0.1:9999
连不上,终端 1 里开起来的隧道返回:
Channel 2: open failed: administratively prohibited: open failed
当时很苦恼,还去 capisrano 群组求助, 幸亏阅读相关文档之后,终于搞定。
ProxyCommand
解决的办法其实简单,就是 ProxyCommand。在本机的 ~/.ssh/config
中,如下配置:
Host prod.server
User jake
ProxyCommand ssh -A login1 nc %h %p
然后就可以直接 ssh prod.server
了,也就是说,可以去掉 config/deploy.rb
中的
:gateway
,直接连接生产环境。
ssh-agent
但这有个不足处,需要输两次密码,解决办法也很简单,就是 SSH 秘钥与 ssh-agent
。
首先我们要生成一个秘钥:
ssh-keygen -N myprecious -f ~/.ssh/corp
以上命令,即生成一个名叫 corp,并有 myprecious 作为密码保护的秘钥。也可以使用无密码保护的秘钥,
但假如秘钥文件丢失,风险很大,而使用 ssh-agent
,在使用体验上等同于无密码,所以,
推荐使用密码保护。
将 corp.pub 的内容分别加入 login1 与 prod.server 的相应用户的
~/.ssh/authorized_keys
中,并配置本机与 login1 机器上的转发,即修改两台机器的
~/.ssh/config
:
本机:
Host login1
ForwardAgent true
login1 机器:
Host prod.server
ForwardAgent true
配置完之后,把这个秘钥交给 ssh-agent
:
ssh-add ~/.ssh/corp
可能会报 Could not open a connection to your authentication agent. 这个错误的意思是,ssh-agent 还没有跑起来,执行一下:
ssh-agent $SHELL
即可。公钥交付完毕之后,我们测试一把:
# 通过 login1 连接 prod.server
# -t 参数表示,请一定分配 Terminal
ssh -t login1 ssh prod.server
# 看看是否连到线上
hostname # ==> prod.server
# 看看你的 SSH 公钥有没有被转发
ssh-add -l # ==> 类似 /Users/johndoe/.ssh/corp.pub
注意这里被转发到相应服务器的只是 SSH 公钥部分,如此,配合前文所述之 ProxyCommand:
Host prod.server
ProxyCommand ssh -A login1 nc %h %p
就可以免密码,直接 ssh prod.server
啦。
Githop
利用 ProxyCommand,我们还可以通过跳板机获取原本不能直接访问的 Git 代码库。例如,敝人实践的方式是, 沿用工作机器,一台 MacBook Pro,上面已经生成的公钥,交给 ssh-agent 打理:
ssh-add ~/.ssh/corp.pub
配置好跳板机、生产机器,以及专门用来中转 Git 仓库的 Githop 机器,使他们可以一路 ForwardAgent
,
并且在需要中转 Git 的机器上配置 ProxyCommand:
Host gitlab
User git
ProxyCommand ssh -A githop nc %h %p
配置好之后测试一下,只要在生产机器上可以做到 git clone ssh://gitlab//repo.git
成功,
那么 capistrano 实际部署时就能顺利完成 deploy:update_code
这一步了。
自动 ssh-add
每次打开终端还得重新添加公钥有些麻烦,我们可以让 Shell 或者 SSH 自动来做。
-
让你所使用的 Shell 来帮忙,例如 zsh,打开
~/.zshrc
,在末尾加上ssh-add ~/.ssh/corp
即可。这么有个缺点,假如你的秘钥受密码保护,每次新开终端,都会提醒你输入该秘钥的密码,比较讨厌。 -
放在
~/.ssh/config
里:IdentityFile ~/.ssh/corp
2013-06-19 更新:
初次生成的密钥文件,可能会因为权限问题不能添加到 ssh-agent ,转发也不成功。将私钥的 filemode 改成 0600 即可。
即执行:
chmod 0600 ~/.ssh/corp