ssh-agent & capistrano

缘起

敝公司的线上环境与业界大拿相仿,躲在防火墙后面,需要通过跳板机登录。在本文描述的问题出现之前, 我们的 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 这一步了。

via

自动 ssh-add

每次打开终端还得重新添加公钥有些麻烦,我们可以让 Shell 或者 SSH 自动来做。

  1. 让你所使用的 Shell 来帮忙,例如 zsh,打开 ~/.zshrc,在末尾加上 ssh-add ~/.ssh/corp 即可。这么有个缺点,假如你的秘钥受密码保护,每次新开终端,都会提醒你输入该秘钥的密码,比较讨厌。

  2. 放在 ~/.ssh/config 里:

    IdentityFile ~/.ssh/corp

via

2013-06-19 更新:

初次生成的密钥文件,可能会因为权限问题不能添加到 ssh-agent ,转发也不成功。将私钥的 filemode 改成 0600 即可。

即执行:

chmod 0600 ~/.ssh/corp

参考资料