命令行神器之 ssh 篇

tldr ssh

Secure Shell is a protocol used to securely log onto remote systems.It can be used for logging or executing commands on a remote server.- Connect to a remote server:      ssh username@remote_host- Connect to a remote server with a specific identity (private key):      ssh -i path/to/key_file username@remote_host- Connect to a remote server using a specific port:      ssh username@remote_host -p 2222- Run a command on a remote server:      ssh remote_host command -with -flags- SSH tunneling: Dynamic port forwarding (SOCKS proxy on localhost:9999):      ssh -D 9999 -C username@remote_host- SSH tunneling: Forward a specific port (localhost:9999 to slashdot.org:80):      ssh -L 9999:slashdot.org:80 username@remote_host- Enable the option to forward the authentication information to the remote machine (see `man ssh_config` for available options):      ssh -o "ForwardAgent=yes" username@remote_host

using ssh agent

ssh-agent命令是一种用来保存公钥身份验证所使用的私钥的程序,本质上ssh-agent就是一个密钥管理器,运行ssh-agent以后,使用ssh-add将私钥交给ssh-agent保管,其他程序需要身份验证的时候可以将验证申请交给ssh-agent来完成整个认证过程。

关于ssh-agent的工作原理可以查看An Illustrated Guide to SSH Agent Forwarding这篇文章,这里简单举例子说明其作用:

假设当前机器为A,另有远程服务器BCD,将A的公钥发布到3台远程服务器上,在机器A开启ssh-agent,然后ssh-add当前A机器的私钥,并且在~/.ssh/config中开启转发ForwardAgent yes,这样BCD三台服务器之间 ssh 登录都可以通过A的这个公钥进行验证登录,而不用配置A的私钥,比如先 ssh 到B,可以从B直接 ssh 到CD

A 机器执行的命令

BCD服务器上只要开启sshd服务,并且将用户目录下面的~/.ssh目录备份删除掉。A机器上备份删除原来的~/.ssh目录后,执行以下命令:

# 创建密钥 ssh-keygen -t rsa -C "username@A"# 一般 Mac OSX 和 Linux 都已经开启`ssh-agent`服务,可以使用以下命令确认 echo "$SSH_AUTH_SOCK"# 如果没有开启 ssh-agent,则手动输入下面这个命令 eval "$(ssh-agent -s)"# 显示ssh-agent中的公钥 ssh-add -L# 如果没有显示任何公钥信息,则手动加入个人的密钥 ssh-add ~/.ssh/id_rsa# 开启转发,一定要有这个配置,不然开启了 ssh-agent 也不会转发 echo "Host *\n    ForwardAgent yes" > ~/.ssh/config# 用 ssh-copy-id 命令发布 A 机器的公钥到 B,C,D 服务器上,不要手动去创建目录和文件 ssh-copy-id username@B ssh-copy-id username@C ssh-copy-id username@D

检查本地被代理的密钥

  • -L:显示ssh-agent中的公钥
  • -l:显示ssh-agent中的密钥
 ssh-add -LThe agent has no identities.

如果提示如上,则目前没有代理任何密钥,Linux 上可以通过ssh-add ~/.ssh/id_rsa命令添加指定的密钥。Mac OSX 上启动和添加密钥的操作说明,可以参考github文档的说明:

# Note: The -K option is Apple standard version of ssh-add, which stores the passphrase in your keychain for you when you add an ssh key to the ssh-agent. ssh-add -K ~/.ssh/id_rsaPassphrase stored in keychain: /Users/username/.ssh/id_rsaIdentity added: /Users/username/.ssh/id_rsa (/Users/username/.ssh/id_rsa) ssh-add -L2048 2f:31:ba:0c:3e:b2:70:52:00:bc:85:37:a2:a7:77:ad /Users/username/.ssh/id_rsa (RSA)

ssh -t jumpbox.server ssh remote.server

 ssh -t -i ~/.ssh/jumpbox_rsa.pub username@jumpbox.server ssh username@remote.server ssh -t username@jumpbox.server ssh username@remote.server

~/.ssh/config 文件配置

上面的命令参数有点多,通过配置~/.ssh/config文件,可以简化ssh命令连接常用服务器的参数:

Host *    ForwardAgent yesHost jumpbox.server    HostName 192.168.1.11    User username    IdentityFile ~/.ssh/jumpbox_rsa.pub    ControlMaster auto    ControlPath ~/.ssh/socket/master-%l-%r@%h:%pHost remote.server1    HostName 192.168.1.2    User username    Port 22    ForwardAgent yes    ProxyCommand ssh -i ~/.ssh/jumpbox_rsa.pub username@remote.server 'nc %h %p'Host remote.server2    HostName 192.168.1.3    User username    Port 22    ForwardAgent yes    ProxyCommand ssh jumpbox.server nc %h %p

如上配置之后,就不用在命令行里每次显示的指定jumpbox.server,可以直接连接远程服务器,这里服务器的别名不需要 DNS 解析,ssh会从~/.ssh/config中获取服务器地址:

 ssh remote.server1 ssh remote.server2

set up socks5 ssh tunnel

 ssh -D 1337 -N -C -f -q username@jump.server.com# 如果有密钥,则指定 -i 参数 ssh -D 1337 -N -C -f -q -i ~/.ssh/jumpbox_rsa.pub username@jump.server.com

use socks5 tunnel with proxychains-ng

proxychains-ng安装请参考官方文档,在/etc/proxychains.conf文件[ProxyList]下面加入代理配置:

socks5 127.0.0.1 1337

如果需要jumpbox.server转发到目标服务器,像正常scp命令一样使用,只是在前面加上proxychains4, 如下:

 proxychains4 scp pom.xml username@remote.server:/home/username

ssh local forwarding

不用proxychains-ng的话,则使用ssh本地端口转发命令,示例如下,访问本地8022端口的数据会被转发到192.168.1.3:22端口:

  • -L [bind_address:]port:host:hostport
  • -N Do not execute a remote command. This is useful for just forwarding ports (protocol version 2 only)
 ssh -N -L 8022:192.168.1.3:22 -i ~/.ssh/jumpbox_rsa.pub username@jumpbox.server scp -P 8022 README.md username@localhost:/home/username

mysql客户端连接本地3307端口,即可经过jumpbox.serverssh转发到远程remote.mysql.server

 ssh -N -L 3307:remote.mysql.server:3306 -i ~/.ssh/jumpbox_rsa.pub username@jumpbox.server mysql -u root -P 3307 -p -h localhost test

ssh remote forwarding

可以通过ssh将本地或者内网的服务暴露给外网,如访问远程服务器jumpbox.server:8080的请求会经过ssh转发到本地的localhost:443端口:

  • -R [bind_address:]port:host:hostport
  • -N Do not execute a remote command. This is useful for just forwarding ports (protocol version 2 only)

本地监听443端口:

 nc -l 443

从本地使用ssh连接远程服务器jumpbox.server,并会在远程服务器开启监听端口8090,加入-N参数是指不需要真实远程登陆到jumpbox.server上:

 ssh -N -R 8090:localhost:443 username@jumpbox.server

这时再访问远程服务器,可以用netstat命令查看到,通过ssh在远程服务器上打开了一个监听端口8090

 netstat -an | grep 8090tcp        0      0 127.0.0.1:8090          0.0.0.0:*               LISTEN

jumpbox.server上执行以下命令:

 echo test | nc localhost 8090

本地监听443的端口会收到远程服务器转发过来的字符串test,如果本地没有监听443端口,则提示:

connect_to localhost port 443: failed.

ssh-agent 登录碰到的一个问题

从当前机器A可以经过jumpbox.server服务器登录到BC,却在登录D时需要密码输入之后才能进入。DBC服务器一样,在~/.ssh/authorized_keys文件中有A的公钥信息,sshd服务器版本和配置都是一样的,同时检查了一下~/.ssh/authorized_keys文件的权限都是600,这个文件没有问题。

当前机器A上的环境如下:

 ~/.ssh/configHost *    ForwardAgent yesHost jumpbox.server    HostName 192.168.1.11    User username    IdentityFile ~/.ssh/jumpbox_rsa.pub    ControlMaster auto    ControlPath ~/.ssh/socket/master-%l-%r@%h:%p ssh-add -Lssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQnnbiFwLHAQemEg4kHBvqpPe4k8X07tZoakf6Ky5hSn222qTCrS1WJVIgXs5nuxKVTGFe6mkywQh64e6Lluu4bWCL/gE7IbEDPEZd6viQSYnaEiCDLvIfENrAC7LynnHRXBMimp2pPGU+j/I/+uOjnUkvHNPy9v7GxRU7Dak3mewMHM4DdsPJJrG8eSMu4PBbK3mGbKI96gsg2uQ3GXJeZmG5tLVFUTnywJHX++s3q1FBeDrWsqcQsD9uRxpDAv7CUbtjBxRzmsXwGTQZjcupX33bhGWHfOp4ELTqfMv2PwaeE+PatU45bsciQeZDmG8myBpiuZujNV4OoBH1F2yr username@localhost

通过ssh -vvv server.D.ip也没有得到明显的提示信息,在网上 GOOGLE 了一些文章之后,在这个帖子里,看到有个人提到了~/.ssh目录的权限需要是700,一般这个目录是用ssh-keygen生成的就是700权限,可是在服务器D上,这个目录却是755的权限,也就是这个目录是手工创建的,所以密钥登录验证没有通过,只能使用密码方式验证登录的用户了,另外authorized_keys最好是通过客户端的ssh-copy-id命令创建,如果手工创建也要确保文件权限是600的。

 ls -la ~drwxrwxr-x 2 username username 4096 Apr 7 11:28 .ssh ls -la ~/.ssh/authorized_keys-rw------- 1 username username 398 Apr 7 11:28 authorized_keys

上面的.ssh目录权限不正确,正确应该如下:

 chmod 700 ~/.ssh ls -la ~drwx------ 2 username username 4096 Apr 7 11:29 .ssh

用户主目录的权限对 SSH 的影响

在 Mac OSX 和 Ubuntu 里,用户主目录的权限为755,用户是可以使用公钥登录的,但是 CentOS 系统中,用户目录的权限必须是700的,不然也会因为宿主目录权限不正确,而被服务器拒绝公钥登录。

/etc/security/access.conf

这个文件的配置也可以控制用户的登录权限。

References

  1. Generating a new SSH key and adding it to the ssh-agent
  2. Using SSH agent forwarding
  3. An Illustrated Guide to SSH Agent Forwarding
  4. SSH CONFIG FILE
  5. SSH PORT FORWARDING EXAMPLE
  6. ProxyChains-NG ver 4.12 README
  7. Create a SOCKS proxy on a Linux server with SSH
  8. SSH from A through B to C, using private key on B
  9. Using Jump Servers and Port Forwarding
  10. Mac OSX系统下通过ProxyChains-NG实现终端下的代理
  11. ssh-agent not working properly