通常在一个 ssh 链接中,需要指定用户名、主机名、主机端口号、配置参数等信息,如果每次登陆一台主机都要输入,那么就会变的非常麻烦,而且一些 IP 地址通常又非常难记。
为此,我们可以通过 OpenSSH 的客户端配置文件简化我们的登陆方式,下面简单介绍下。
公私钥免密认证
通过公私钥可以做到免密码,原理也很简单,用户将公钥保存在服务器上,登录时,服务端发送一段随机字符串,用户用私钥加密后再发回来,服务端用公钥解密,成功就证明用户是可信的,直接登录 shell,不再要求密码。
简单来说,生成一个密钥对,将公钥传送到服务器端,保存在 AuthorizedKeysFile 配置项指定的文件。
实践
可以通过如下步骤执行。
1. 服务端设置
在服务器端,首先确认 /etc/ssh/sshd_config 这个文件,检查下面几行是否有效。
RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
2. 生成公私钥
直接通过 ssh-keygen 生成公私钥密码对即可。
$ ssh-keygen [-t rsa/dsa]
$ ssh-keygen -t rsa -f ~/.ssh/id_rsa -N "" -C "foobar@kidding.com"
参数:
-t: 加密类型
-f: 指定输出文件
-N: 通过该密码加密私钥,为空则会自动登陆
-C: 注释,通常为邮箱名称,会保存在公钥中
密钥对默认保存在 .ssh/ 目录下,包括了 id_rsa(私钥) id_rsa.pub(公钥),其它常用的加密方式还包括了 RSA DSA ECDSA ED25519 。
3. 将公钥上传到服务器
将公钥上传到服务器,此时会保存到需要免密码登陆用户 (在此为 foobar) 的 $HOME 目录下,方法很多,可以手动复制,也可以通过 scp 或者专有的 ssh-copy-id 命令。
$ cat ~/.ssh/id_rsa.pub | ssh foobar@remote-server-ip "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
$ scp ~/.ssh/id_rsa.pub foobar@remote-server-ip:~
$ ssh-copy-id -i ~/.ssh/id_dsa.pub foobar@remote-server-ip
配置文件中通过 AuthorizedKeysFile 指定公钥保存的文件名,一般是 .ssh/authorized_keys 文件,然后直接添加到该文件中即可,需要注意如下权限。
$ chmod 700 ~/.ssh/
$ chmod 644 ~/.ssh/authorized_keys
$ chmod 600 ~/.ssh/id_rsa
4. 登陆
如果使用私钥登录多台主机,可以通过 -i 选项指定私钥文件。
$ ssh -i id_rsa user-name@remote-server-ip
$ ssh -o PreferredAuthentications=publickey remote-server-ip -p 2880 -l user-name
如果是初次登陆时,会提示是否将对应的主机添加到 known_hosts 文件中,可以通过如下命令自动添加,无需交互。
$ ssh -T -o StrictHostKeyChecking=no remote-server-ip 'date'
安全相关
在生成密钥对时,如果密码没有输入,那么可以自动登陆,不过同样会导致当有人获取了该私钥后,可以登陆你配置的所有服务器。为此,为了保证私钥安全,生成密钥对时,最好指定密码。
----- 修改密码,如果设置为空则无密码
$ ssh-keygen -p -f id_rsa
不过这也导致了每次登陆时需要输入 私钥保护密码,会产生与之前相同的问题。
客户端配置
每次通过 ssh 登陆时,通常需要按照如下方式,指定用户名、主机、端口号,如果拥有多个 ssh 账号,那么要记住每个 ssh 账号的参数会非常麻烦。
$ ssh foobar@192.168.9.123 -p 2222
常用参数:
-p: 指定端口
-i: 如果通过公私钥认证,则通过该参数指定私钥
-v: 调试,用于查看认证过程
-o: 指定参数,例如-o ServerAliveInterval=60
实际上,对于 OpenSSH 客户端,可以通过配置文件简化登陆。
OpenSSH 客户端会使用 ~/.ssh/config 用户配置文件,也可使用全局配置 /etc/ssh/ssh_config,如果没有该文件则需要手动创建,该文件中的配置项通过 Key = Value 格式进行设置。
通过如下的方式指定别名,可以支持通配符 *%,注意,配置项大小写不敏感,值大小写敏感,而且注释只支持行首的注释。
Compression yes # 全局配置,与下面方式相同
Host * # 对于所有主机通用配置项
ServerAliveInterval 60 # 防止因为空闲链接断开,每隔60秒发送一次请求,从而保持连接
ServerAliveCountMax 3 # 发送请求后,如果服务端连续超过3次没有响应,则自动断开
StrictHostKeyChecking no # 默认首次添加到known_hosts时会有提示信息,配置为自动添加
Protocol 2 # 使用协议版本V2
Host mysql # 登陆时简化MySQL主机的配置
HostName 192.168.9.123 # 指定服务器的IP,如果与上述的Host参数相同,则可以忽略
User foobar # 登陆用户名
Port 2222 # 登陆使用端口号,默认22
IdentityFile ~/.ssh/mysql # 如果通过公私钥认证方式,指定私钥文件地址
Host dev backup www* mail # 可以指定多个甚至是通配符
HostName %h.example.com # 利用上述的Host作为参数
例如,上述的 mysql 设置,可以直接通过 ssh mysql 命令登陆,而且 scp 等,同样可以如此使用。
另外,对于上述的最后一个示例,需要简单说明下,如果是通过 ssh dev 命令登陆,那么实际登陆时对应的主机名为 dev.example.com,以此类推。
代理设置
为了安全设置,通常防火墙只允许 80/22 端口访问,假设该服务器同时部署了 MySQL 服务,那么我们就无法通过笔记本进行调试。当然可以通过 ssh 的本地代理实现,设置如下:
$ ssh -f -N -L 9906:127.0.0.1:3306 foobar@database.example.com
如上,使得本地访问 9906 端口时,会将请求转发到 database.example.com 的 127.0.0.1:3306,也就是对应的 MySQL 服务器了。同样可以通过如下方式简化。
Host tunnel
HostName database.example.com
IdentityFile ~/.ssh/foobar.example.key
LocalForward 9906 127.0.0.1:3306
User foobar
然后通过 ssh -f -N tunnel 命令登录即可。
共享连接
当登陆一台服务器后,可以通过共享链接实现免登陆,也就是说第一次登陆之后,后面的会自动登陆。需要在添加配置文件 ~/.ssh/config(600) 中添加如下内容。
host *
ControlMaster auto # 复用之前链接
ControlPath /tmp/ssh_mux_%r@%h:%p # 如果不使用该参数只能是最后一个免登
ControlPersist 4h # 默认直接退出,该参数指定4小时后退出
此时会在 /tmp 目录下创建 ssh_mux 前缀的 sock 文件,它记录了你目前登录到的机器,这样的话,你登录同样的机器就会重用同一个链接了。
ssh-agent
为了解决上述的问题,可以使用 ssh-agent,这是一个守护进程,设计它的唯一目的就是对解密用的专用密钥进行高速缓存,包括进行私钥转发。
ssh 支持与 ssh-agent 通信,允许 ssh 建立新连接时自动获取解密的专用密钥;你所需要做的就是,使用 ssh-add 命令把密钥添加到 ssh-agent 的高速缓存中即可。
工作原理
在 CentOS 中,会默认启动 ssh-agent 服务,当然,也可以手动启动;此是会输出一些信息,包括两个重要的环境变量 SSH_AUTH_SOCK (ssh/scp用来连接的套接字) 和 SSH_AGENT_PID 。
可以通过 ssh-add id_rsa 将私钥添加到 agent 中,后续 ssh、ssh-add、scp 等命令就会利用上述的环境变量与 ssh-agent 进行交互,获取对应的私钥信息,如果对私钥进行了加密,那么后续请求就无需再输入密码。
代理转发

简单来说,在 X 机器上运行 ssh-agent 代理来管理私钥,然后通过 X 机器 ssh 登录到 Y 机器,这样就能让 Y 机器上的 ssh 客户端也能使用到所有 X 机器上的 ssh-agent 所管理的所有私钥。
----- 在X节点上配置/etc/ssh/ssh_config,增加允许Agent转发
ForwardAgent yes
----- 在Y的/etc/ssh/sshd_config配置文件添加,需要重启sshd服务端
AllowAgentForwarding yes
修改完成之后,在 Y 机器上,可以通过 ssh-add -l 命令查看到 X 上的密钥信息。
其原理是,Y 机器上的 ssh 客户端会跟 Y 机器上 sshd 服务器请求私钥,因为已经从 X 登录到 Y 上,X 的 ssh 客户端和 Y 上的 sshd 服务器建立了一条连接,通过这条连接,请求被转发给了 X 上的 ssh 客户端,最终传递给 X 上的 ssh-agent,这样请求的结果反向传递回去。
常用命令
可以通过 ssh-add 管理私钥,常用命令参数如下:
-L列出所缓存的私钥信息,包含了详细信息;-l列出所缓存的 SHA256 信息;-D清空缓存中的密码,此时如果登陆则需要使用之前设置的私钥保护密码;-X/x对agent加锁,不知道具体的作用,仍然可以免密码登陆。
----- 启动并设置环境变量
$ eval $(ssh-agent)
----- 添加并查看私钥,添加时需要输入密码
$ ssh-add YourSecretFile
$ ssh-add -l