从OpenSSH 8.2版本开始,引入了通过FIDO2进行验证的方法。和PGP智能卡方式相比,使用FIDO2免去了更改SSH代理的麻烦,开箱即用。而对于更常见的使用私钥文件来说,由于FIDO2是独立的硬件设备,即使电脑本身不安全也不会泄露私钥。但由于标准的FIDO2设备无法复制备份私钥,一旦硬件设备损毁或丢失,在没有备用方案的情况下,就会无法通过SSH连接到服务器,所以强烈建议增加一个备用方案,例如:至少使用两个设备生成密钥、使用其他方式创建备用密钥并保留好,或是添加其他连接方式。
准备工作
首先准备FIDO2设备,不同的设备可能支持不同的加密方式,首选支持ed25519-sk方式的设备,如果没有的话可以退而求次选择支持ecdsa-sk方式的,至于更古老的RSA方式,现在已经不推荐使用了。
如果打算购买新设备的话可以选择Yubico的设备,如果有更高要求的话,也可选择其他设备或是通过开源项目自行打造。这里使用的是Yubikey 5C NFC。
其次要准备的是SSH客户端,输入ssh -V
来检查版本,如果版本高于8.2,则支持FIDO2认证。若版本低于8.2,则需要升级SSH客户端版本。
在Windows系统上,可以在PowerShell的OpenSSH项目中下载新版本,下载并解压后执行install-sshd.ps1
脚本安装服务。
在macOS系统上,即使客户端版本大于8.2似乎也无法使用FIDO2,原因可能是苹果的keychain也提供了保存SSH密钥的功能,所以引起了冲突。如果要使用的话,需要额外安装SSH客户端,例如用Homebrew安装。
最后,服务器端的版本也有要求,在Ubuntu 18.04 LTS中的OpenSSH 7.6p1中无法识别添加的ed25519公钥,而在Ubuntu 20.04 LTS中的OpenSSH 8.2p1中则可以正常使用。
生成密钥
FIDO2有两种密钥生成方式,分别是可发现凭证(Discoverable Credential)模式和不可发现凭证(non-Discoverable Credential)模式,这两种模式曾经被称为常驻密钥模式(Resident Key)和非常驻密钥(non-Resident Key)模式。两者的区别是可发现凭证模式会在FIDO2的存储空间内放置用户标识,另一种则不会。
体现在SSH验证中,可发现凭证模式可以在插上电脑后直接连接到SSH代理,而另一种需要配合私钥文件才会被识别,下文将会提到,这个私钥文件中并没有真正的私钥。两者之间的取舍主要是安全和便利的取舍,如果计划使用可发现凭证,最好修改PIN码来避免被盗用。
虽然由于存储空间有限,FIDO2设备中可以放置的可发现凭证是有限的,但实际上使用可发现凭证的地方并不多,除了用于ssh中,目前只见到过微软账号的无账号功能会用到,对于Yubikey 5C的25个数量限制来说,其实空间很足够。
使用如下命令来生成密钥:
ssh-keygen -t 加密方式 -f 文件输出路径
或
ssh-keygen -t 加密方式 -O resident -f 文件输出路径
例如:
ssh-keygen -t ed25519-sk -O resident -f ~/.ssh/id_ ed25519-sk
其中-O resident
参数的意思是生成可发现凭证,-f
参数为指定输出文件的路径,可以省略不写,这时通常会输出到~/.ssh/
中。此外,可以在命令中加入no-touch-required取消认证时需要按下设备上的按钮,但会降低安全性,并不推荐。
执行之后按照提示,插入设备,输入PIN码和按下按钮,此时密钥就生成完成了。接下来还会要求输入私钥的文件的密码和文件名,当然这两项可以不填。这时生成的私钥和通常情况下不同,根据OpenSSH的说法,这个私钥文件中并没有真正的私钥,而是“密钥句柄”,这个文件的作用是替代私钥被SSH客户端所识别;另一个后缀为.pub的则是公钥。如果生成的不是可发现凭证,记得保留好两个文件。
生成完成后,将输出文件中的公钥放入服务器的authorized_keys
中即可。
使用
将之前生成的私钥放入~/.ssh/
中并插入设备即可使用,如果有多个的话,使用ssh -i 文件路径
来指定使用的私钥。
如果使用可发现凭证,即使没有私钥,在插入设备后,也可以通过执行ssh-add -K
命令的方式让SSH代理识别到,使用ssh-add -L
来检查SSH代理存储的内容,不过这种方式重启后就会失效。如果执行ssh-keygen -K
则可以读取设备来重新生成私钥和公钥。
安全提醒
虽然将私钥放置在加密设备中可以避免被远程盗取,但如果电脑本身不安全也可能会趁着连接的时候偷偷执行命令。另外,如果原本使用密码登录的话,记得关闭密码登录,不然即使设置了私钥登录也无法阻止密码登录。
题外话
在测试时使用VMware安装Ubuntu来测试Linux上的用法,然而发现VMware的智能卡直通并不能完全将Yubikey直通进虚拟机导致无法读取,参考了一下Yubico的说明和VMware的论坛在虚拟机的vmx文件中添加如下配置就可以将Yubikey给虚拟机独占来解决问题:
usb.generic.allowHID = "TRUE"
usb.generic.allowLastHID = "TRUE"
usb.generic.allowCCID = "TRUE"
usb.ccid.disable = "TRUE"
另外在Windows中测试时即使下载了新版本的SSH,也总是无法通过ssh-add -K
来加载,或许等到以后正式搭载到Windows中就能解决问题了。
参考文章
https://blog.getevo.top/archives/ssh配置fido2usb验证器无密码登录
Comments 4 条评论
博主 RivenNero
可发现凭证:物理密钥中存放用户标识
不可发现凭证:密钥中不存放用户标识
这是两种方法的唯一区别吗?也就是说,不可发现凭证是更安全的吗?
博主 bloade
@RivenNero 是的,不可发现凭证只会把标识放在生成的文件里,即使其他人拿到了密钥和PIN,没有这个文件也无法通过验证;而可发现凭证只要有密钥和PIN就可以。
博主 Fred
ssh-keygen -t ed25519-sk -O resident
Generating public/private ed25519-sk key pair.
You may need to touch your authenticator to authorize key generation.
A resident key scoped to ‘ssh:’ with user id ‘null’ already exists.
Overwrite key in token (y/n)?
为啥执行resident时报已有 key,默认带了一个?那怎么办?怎么去拿到这个自带的对应公钥?
博主 bloade
@Fred 先试试用ssh-keygen -K,如果是可发现密钥的话,这个命令可以从fido设备中取出公钥和密钥句柄(或者称“私钥”)。
但若是不可发现的话就无法提取了,如果确定里面已有的私钥不是以前生成过忘记了的话,我觉得没法使用的私钥即使覆盖掉也没问题。
另外我不太确定错误是不是和用户名null有关,我记得我生成密钥之后用设备制造商提供的查看器看了下,用户名是一个和ssh有关的名字。