从 OpenSSH 5.4 版本 (2010年) 开始支持 SSH 证书,相比 SSL 中使用的证书来说,SSH 的更为简单,没有证书链只有一个 CA 证书,这样就免去了商业签名授权。
简介
使用证书实际上就是将对公钥的信任转换为对 CA 证书的信任,所以 CA 的私钥必须要很好保存,如果丢失就需要重建所有的证书,可以通过 ssh-keygen
生成证书,支持 user 和 host 两种方式,最好将 CA 也分成 user 和 host 两类,以减少泄漏时的影响。
其中 user 和 host 证书的区别在于,生成的证书是保存在用户侧还是主机侧,前者用于确保客户端确认服务端是合法的,而后者则用于判断用户是否可信。
主机证书
在安装 sshd
服务的时候,会自动生成主机侧的证书,一般是 /etc/ssh/ssh_host_xxx_key
文件,除非采用相同的 OS 镜像,正常的系统安装后每个主机的私钥对不同,每次链接到服务器时就需要验证是否为服务器的公钥。
如果主机数比较多,那么验证过程会很繁琐,可能不再严格检查是否匹配,所以,也就不太安全。
如果链接的是一台被 Hacked 主机,而且还接受了主机侧的证书,那么 Hacker 就可以看到所有与主机的通讯内容。尤其是对于云计算来说,主机可能会频繁重建,而且 IP 地址可能随时修改,这就导致需要频繁验证主机公钥,大部分用户可能就会不加思索直接信任。
原理介绍
首先生成 SSH Root CA (实际就是常用的公私钥对) 用来对主机的公钥进行签名;然后客户端配置为信任所有 SSH Root CA 签发的公钥,这就意味着,虽然扔需要通过交换校验服务端的公钥,但 SSH Root CA 公钥几乎不怎么修改,这样风险就大大降低。
操作实践
----- STEP1 生成CA的公私钥对,会生成私钥host_ca、公钥host_ca.pub两个文件
$ ssh-keygen -t rsa -b 4096 -N "" -f host_ca -C "Host SSH CA"
----- STEP2 生成host的公私钥对,一般在sshd服务端已经存在/etc/ssh/ssh_host_xxx文件
$ ssh-keygen -t rsa -b 4096 -N "" -f ssh_host_rsa_key -C "Host SSH Key"
----- STEP3 对证书进行签名,其中ssh_host_rsa_key-cert.pub就是基于主机的证书(这里只需要上述生成的公钥)
$ ssh-keygen -s host_ca -I host.example.com -h -n host.example.com -V +52w /etc/ssh/ssh_host_rsa_key.pub
-s 指定用于签名的CA私钥文件
-I 证书的标识,推荐使用主机名,可以用于后续证书的撤销
-h 主机而非用户证书
-n 通过逗号分隔的证书校验,服务端会进行校验,可以使用DNS或者~/.ssh/config中的配置
-W 过期时间,上述的 +52w 表示 52 周
----- 将含有整的公钥ssh_host_rsa_key-cert.pub复制到服务器
$ vim /etc/ssh/sshd_config
HostCertificate /etc/ssh/ssh_host_rsa_key-cert.pub
----- 复制 host_ca.pub 信息,添加到客户端的如下文件,或者全局/etc/ssh/ssh_known_hosts文件
$ vim ~/.ssh/known_hosts
@cert-authority * ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDFmxwUIQJ6KDQ+0wB+T6yeYMJw== host-ca
其中的 *
表示匹配所有的主机,或者使用类似 *.example.com
的域名匹配,如果要匹配多个模式则可以使用逗号分割,同样可以使用 IP 地址。
功能验证
执行上述的 STEP2
操作重新生成主机密钥对,此时再登录会提示用户验证,如果再执行 STEP3
操作,就无需再验证。
用户证书
通常来说,用户需要通过密码或者公私钥对进行登录,前者没有特殊的,这里仅介绍后者。
用户生成公私钥对,私钥部分在本地安全保存,公钥则上传到需要登录服务器的 ~/.ssh/authorized_keys
文件中,用户通过私钥生成一段信息,然后服务端利用公钥进行验证,通过则登录成功。
如果用户出于安全考虑,要对公私钥对进行周期轮换,这就需要将保存在服务器上老的公钥删除,同时添加新的公钥,当主机数太多的时候,就会非常的麻烦。而且,当攻击者通过各种手段获取了该主机公私钥对,那么就可以直接添加新的登录用户。
原理介绍
首先生成 SSH User CA 用来对用户证书进行签名,并将需要的主机配置为信任该证书签发的公钥,也就是将 CA 的公钥信息配置到服务端;然后对需要登录的用户通过 SSH User CA 签发证书,同时可以指定过期时间、绑定用户名等,这样就省去了对 authorized_keys
文件的维护。
操作实践
----- STEP1 生成用户证书签名用的CA私钥对
$ ssh-keygen -t rsa -b 4096 -N "" -f user_ca -C "User SSH CA"
----- STEP2 生成登录用的公私钥对
$ ssh-keygen -t rsa -b 4096 -N "" -f id_cert_rsa -C "Host SSH Key"
----- STEP3 通过CA证书对公钥进行签名,会生成id_cert_rsa-cert.pub文件
$ ssh-keygen -s user_ca -I cert-dev -n root,vagrant,andy -V -5:+52w -z 1 id_cert_rsa.pub
-n 指定用户名,表示证书仅对该用户名有效,可以逗号分割指定多个
-V 证书有效期,默认是永久有效
----- 将 user_ca.pub 复制到服务器,添加如下配置
$ vim /etc/ssh/sshd_config
TrustedUserCAKeys /etc/ssh/user_ca.pub
上述这种方式会导致服务器的所有账户都会信任 user_ca 签发的所有用户证书,所以,也可以将 user_ca.pub 的内容添加到 sshd 服务器的某个用户的 ~/.ssh/authorized_keys
文件中,这样只有该账户信任 user_ca 签发的用户证书。
$ cat ~/.ssh/authorized_keys
@cert-authority principals="user" ssh-rsa AAAAB3Nz...XNRM1EX2gQ==
其中的 user
就是指定的服务器帐号名,一般就是对应的用户名,登录的时候通过 -i
参数指定私钥即可,例如 ssh -i id_cert_rsa andy@127.0.0.1
即可。
功能验证
假设用户证书已经过期,那么只需要执行 STEP3
重新用 CA 签名即可;如果是新的用户,那么执行 STEP2+STEP3
即可,此时添加的是不同的用户而已。
常用命令
----- 查看证书信息
$ ssh-keygen -L -f ssh_host_rsa_key-cert.pub
登录时通过 -i
参数指定私钥,同时 CA 签名的 xxx-cert.pub
保存在与私钥相同的目录下即可,连接服务器时会自动使用该证书,例如。
$ ssh -i ~/.ssh/user_key user@host.example.com