Agent转发的实现
ssh-agent除了用于免密登录之外,还可以实现跨主机的key认证.
假设有如下一个场景,我们需要从公网连接到公司一个服务器ssh_server,再通过这个服务器跳转到公司的其他内网机器ssh_server2.但是处于安全因素考虑,IT要求所有的ssh连接都需要通过公钥认证,不允许通过密码登录到ssh服务器.
在这种前提下,我们连接到ssh_server是没有问题的,可以直接用本机(ssh_client)的密钥对进行认证,但是从ssh_server跳到ssh_server2就比较麻烦,我们不能在ssh_server2上配置ssh_server的私钥,如果配置了,意味着任何人登录到ssh_server都能登录ssh_server2,万一ssh_server被攻陷了,ssh_server2也同样遭殃.我们希望的是ssh_server2只接受客户端本机(ssh_client)的公钥登录.有一种解决方案,是将ssh_client的私钥临时拷贝到ssh_server上,用完删除.但是这样会导致私钥在网络上传输,容易被截取,同样是不安全的.
ssh-agent的转发功能提供了另外一种解决方案,用户从ssh_client连接到ssh_server后,如果试图连接到ssh_server2,ssh_server可以将公钥认证请求转发到ssh_client上,ssh_client上的ssh-agent可以代理ssh_server公钥认证.
前提条件,ssh_server和 ssh_server2上都对ssh_client的私钥做了授权,通过ssh-client的ssh-agent可以免密登录.
[root@ssh_client ~]# ssh 172.17.0.2
Last login: Thu Apr 26 13:15:24 2018 from test
[root@ssh_server ~]# logout
Connection to 172.17.0.2 closed.
[root@ssh_client ~]# ssh 172.17.0.4
Last login: Wed Apr 25 13:08:01 2018 from 172.17.0.3
[root@ssh_server2 ~]# logout
Connection to 172.17.0.4 closed.
[root@ssh_client ~]# ssh-add -l
2048 SHA256:XVtu4pjbOq39iJeG13+Ml6IFjoy/7pfv7YwSByyvV4U /root/.ssh/id_rsa (RSA)
2048 SHA256:qvSCPe3JJjX7o4JbEaR+QCcVthHKvKGqOraLW4+Z4UQ keys/k2 (RSA)
[root@ssh_client ~]#
从ssh_server直接连ssh_server2还是需要输入密码.
[root@ssh_server ssh]# ssh root@172.17.0.4
The authenticity of host '172.17.0.4 (172.17.0.4)' can't be established.
ECDSA key fingerprint is SHA256:Z24pWQCUSlqJF7Nyx0iA4AE/Z5z5WJWbSKA6AFspDbA.
ECDSA key fingerprint is MD5:a7:a5:b2:42:ba:be:dd:f1:5f:fe:5c:89:9c:b9:eb:c3.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '172.17.0.4' (ECDSA) to the list of known hosts.
root@172.17.0.4's password:
[root@ssh_server ssh]#
我们要实现的功能是,通过ssh_client连接到ssh_server之后,在当前会话(ssh_server上)继续连接ssh_server2能实现免密.
测试如下:
[root@ssh_client ~]# ssh 172.17.0.2
Last login: Thu Apr 26 23:22:19 2018 from test
[root@ssh_server ~]# ssh root@172.17.0.4
root@172.17.0.4's password:
[root@ssh_server ~]# logout
Connection to 172.17.0.2 closed.
验证失败,从ssh_server试图连接ssh_server2(172.17.0.4)还是提示输入密码.
Agent转发需要在ssh的客户端和服务端都做些配置.
在ssh_server机器上,sshd_config需要支持配置AllowAgentForwarding选项:
[root@ssh_server /]# cd /etc/ssh/
[root@ssh_server ssh]# grep Forward sshd_config
#AllowAgentForwarding yes
#AllowTcpForwarding yes
X11Forwarding yes
# X11Forwarding no
# AllowTcpForwarding no
AllowAgentForwarding默认是yes,因此,服务端无需变更.
在ssh_client机器上,也就是私钥实际存放的机器上,ssh_config需要配置ForwardAgent为yes
[root@ssh_client ssh]# grep Forward ssh_config
# ForwardAgent no
# ForwardX11 no
ForwardX11Trusted yes
默认是no,因此需要修改:
Host *
ForwardAgent yes
去除Host *
和ForwardAgent no
的注释,并将ForwardAgent设置成yes.
再次尝试agent转发功能
[root@ssh_client ssh]# ssh root@172.17.0.2
Last login: Thu May 3 13:10:58 2018 from 172.17.0.3
[root@ssh_server ~]# ssh root@172.17.0.4
Last login: Thu May 3 13:11:05 2018 from 172.17.0.2
[root@ssh_server2 ~]#
从ssh_client登录到ssh_server之后,再从ssh_server登录到ssh_server2也实现了免密登录.
从ssh_server2 logout到ssh_server,可以查看下当前环境变量中和SSH相关的内容:
[root@ssh_server2 ~]# logout
Connection to 172.17.0.4 closed.
[root@ssh_server ~]# env|grep SSH
SSH_CLIENT=172.17.0.3 39854 22
SSH_TTY=/dev/pts/2
SSH_AUTH_SOCK=/tmp/ssh-HZ0OghvUE4/agent.69
SSH_CONNECTION=172.17.0.3 39854 172.17.0.2 22
[root@ssh_server ~]#
从上面的结果,可以看到环境变量中有SSH_AUTH_SOCK,这个变量和ssh_client上启动ssh-agent后导入的环境变量名称是一致的,从ssh_server上发起ssh连接时,会经过这个SSH_AUTH_SOCK做认证,/tmp/ssh-HZ0OghvUE4/agent.69这个socket再通过已经建立的加密的SSH隧道(172.17.0.3 39854 172.17.0.2 22) 将认证请求转发到ssh_client上的ssh-agent进程.
主机之间的文件拷贝
SSH的Agent转发功能除了用于在主机间跳转之外,还能实现通过scp指令在远程主机之间进行文件拷贝.
scp进程是ssh客户端程序中用于文件传输的指令,通常的用途是将SSH客户端上的文件拷贝到SSH服务端(scp ./localfile remotename@remoteserver:/remotefile),或者从SSH服务端将文件拷贝到SSH客户端(scp remotename@remoteserver:/remotefile ./localfile).如果我们需要从客户端机器C上直接将远程服务器A上的文件F转移到远程服务器B上,可以用scp中的 -3参数是实现 Copies between two remote hosts are transferred through the local host. Without this option the data is copied directly between the two remote hosts. Note that this option disables the progress meter.
.但是这种方式有个缺点,它的实际实现方式是将文件F从服务器A拷贝到客户端C,再从客户端C拷贝到服务器B.如果我们是在低速的VPN中连接远程机器,这样传输文件的效率就太低了.
ClinetC:~$ time scp -3 xxx@ServerA:~/google-chrome-stable_current_amd64.deb yyy@ServerB:/tmp
real 3m53.849s
user 0m2.144s
sys 0m1.820s
ClinetC:~$ssh yyy@ServerB
ServerB:/tmp$ ls -tlr
total 50936
-rw-rw-r-- 1 ubuntu ubuntu 52149676 5月 7 21:31 google-chrome-stable_current_amd64.deb
drwx------ 2 ubuntu ubuntu 4096 5月 7 21:35 ssh-GoQ1x6HnWZ
ServerB:/tmp$ rm google-chrome-stable_current_amd64.deb
拷贝50M文件花费了大概4分钟.
如果通过ssh-agent,可以不用通过客户端直接远程scp:
ClinetC:~$ eval `ssh-agent`
Agent pid 16565
ClinetC:~$ ssh-add
Identity added: /home/xxx/.ssh/id_rsa (/home/xxx/.ssh/id_rsa)
ClinetC:~$ time scp xxx@ServerA:~/google-chrome-stable_current_amd64.deb yyy@ServerB:/tmp
real 0m5.254s
user 0m0.024s
sys 0m0.004s
ClinetC:~$ssh yyy@ServerB
ServerB:/tmp$ ls -tlr
total 50932
-rw-rw-r-- 1 ubuntu ubuntu 52149676 5月 7 21:39 google-chrome-stable_current_amd64.deb
drwx------ 2 ubuntu ubuntu 4096 5月 7 21:39 ssh-zRWyUfhFIa
这次拷贝只需要5秒.注意,这里scp指令没有带-3参数,也就是说文件不需要通过第三方(SSH客户端)中转.
如果是ssh-agent转发的功能没有打开,执行远程主机间的拷贝会类似如下结果:
[root@ssh_client ssh]# scp root@172.17.0.2:/root/test root@172.17.0.4:/root/test
root@172.17.0.4's password:
test 100% 152KB 27.1MB/s 00:00
Connection to 172.17.0.2 closed.
登录172.17.0.2和172.17.0.4都是免密的,但是这里我们依然需要输入172.17.0.4的密码,因为这个登录指令实际上是在172.17.0.2主机上触发的.