场景复现
在写这篇文章时,不仅感叹自己遇到的坑真是又麻烦、又坑人。好端端的服务器就连接不上了,问题神奇的就发生了。
问题发生过程为:通过SecureCRT连接服务器,提示:
Public Key Authentication Failed:
Public-key authentication with the server for user root failed.Please verify username and public/private key pair.
(翻译为:公钥认证失败:用户 root 与服务器的公钥身份验证失败。请验证用户名和公钥/私钥对。)
这时使用终端连接服务器,则提示:
fangjunyu@fangjunyudeMacBook-Pro ~ % ssh root@111.231.22.116
root@111.231.22.116: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).
(翻译为:权限被拒绝(publickey、gssapi-keyex、gssapi-with-mic))
现在就开始我们的问题排查之旅。
环境配置
1、服务器版本:CentOS Linux release 7.9.2009 (Core)
SSH版本:OpenSSH_7.4p1, OpenSSL 1.0.2k-fips
2、客户端版本:macOS Monterey 12.7.3
SSH版本:OpenSSH_8.6p1, LibreSSL 3.3.6
3、客户端版本:macOS Sonoma 14.3.1
SSH版本:OpenSSH_9.4p1, LibreSSL 3.3.6
排查过程
大家可以看到,我有两台电脑,我一直使用这两台电脑连接远程机,在我发现老电脑(这里代指本次无法连接的问题机器)无法连接后,尝试使用新电脑进行连接。
是的,新电脑是可以连接到远程机的。
好了,我想可能是我老电脑的公钥和密钥出问题了,我可以把新电脑的公钥和密钥复制过来。
复制密钥
然后,我将新电脑的公钥、密钥打包,隔空投送给我的老电脑,并将老电脑的密钥打包备份。
注意:任何修改配置文件的操作都要备份,也可以通过下面的代码进行快速备份。
cp ~/.ssh/id_rsa{,backup}
cp ~/.ssh/id_rsa.pub{,backup}
接着,完成SSH的替换,这时重新访问SecureCRT,提示我:
Enter Secure Shell Passphrase:
Enter a passphrase to decrypt your private key for root@111.231.22.116.
Comment: root@VM-16-16-centos
Passphrase
(翻译:输入密码以解密 root@111.231.22.116 的私钥)
如果输错密钥会提示:
Public Key Authentication Failed:
The passphrase is incorrect.Please reenter your passphrase.Letters in passphrase must be entered using the correct case.Make sure the Caps Lock key is not on.
(翻译:密码不正确。请重新输入密码。密码中的字母必须使用正确的大小写输入。请确保 Caps Lock 键未打开。)
密码输入成功,会提示:
Public Key Authentication Failed:
The server recognized your public key,/Users/fangjunyu/.ssh/id_rsa,but none of the known signature mechanisms were accepted. This normally means that the server you are connecting to does not comply with any of the supported standards.
(服务器识别了您的公钥/Users/fangjunyu/.ssh/id_rsa,但没有接受任何已知的签名机制。这通常意味着您正在连接的服务器不符合任何支持的标准。)
复制密钥后,问题仍然没有任何解决。
另外,在输入私钥密码的过程中,SecureCRT有提示我选择对应的公钥,但是在复现过程中,没有再次弹出选择公钥的窗口,在这里做一个备注。
也弹出过:
Public Key Authentication Failed:
Public-key authentication with the server for user root failed.Please verify username and public/private key pair.
(翻译:用户 root 与服务器的公钥身份验证失败, 请验证用户名和公钥/私钥对)
这个问题复现中也没有出现,可能是连接的用户名输入错了导致的。
匹配公钥和私钥
接着,我把老电脑的公钥和私钥还原回去,并进行下一步的排查。
还原老电脑的密钥后,我在想,是不是我的公钥和密钥不匹配导致的。
虽然我尝试使用新电脑连接服务器,并在服务器中查看id_rsa.pub文件的指纹。
[root@fangjunyu]~# ssh-keygen -l -f ~/.ssh/id_rsa.pub
2048 SHA256:UpaDYjtc5pcjAm/Ojym5m/LuabmGpkn+qL4k3N6to7g root@fangjunyu.com (RSA)
这时我再查看老电脑的密钥指纹,发现老电脑的密钥指纹完全一样:
ssh-keygen -l -f /Users/fangjunyu/.ssh/id_rsa
2048 SHA256:UpaDYjtc5pcjAm/Ojym5m/LuabmGpkn+qL4k3N6to7g root@fangjunyu.com (RSA)
ssh-keygen -l -f /Users/fangjunyu/.ssh/id_rsa.pub
2048 SHA256:UpaDYjtc5pcjAm/Ojym5m/LuabmGpkn+qL4k3N6to7g root@fangjunyu.com (RSA)
然后我又用新电脑查看密钥指纹,发现新电脑的密钥指纹反而是与服务器、老电脑的密钥指纹对不上:
ssh-keygen -l -f ~/.ssh/id_rsa
2048 SHA256:UpaDYjtc5pcjAm/Ojym5m/LuabmGpkn+qL4k3N6to7g /Users/fangjunyu/.ssh/id_rsa.pub (RSA)
ssh-keygen -l -f ~/.ssh/id_rsa.pub
2048 SHA256:UpaDYjtc5pcjAm/Ojym5m/LuabmGpkn+qL4k3N6to7g no comment (RSA)
这是一件很神奇的事情,密钥不一致可以登录,密钥一致反而登录不上。
然后我又通过排查发现服务器端的~/.ssh/authorized_keys,配置了新电脑的公钥,因此才解释了为什么新电脑的公钥可以连接服务器,但是老电脑的公钥就没有连接服务器。
[root@fangjunyu]~# cat ~/.ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCuEgwLPXmoAEki73WjTBOGfEl6gyMoAXW/fCB40gq/5U54U1e9GRX6TgusBmKyP5q6kFrqqNTE5z4n37hwKzKHbgUmMz2dipEzahCJDFxoDmr1C1XRAQNEWX+ECKYD7eGMRy5e7P9qwLb6q376CEN/FTamy4KO6JAcCe17POD2j+oUCAp2ymuGJsh2BdbgBZ6P4kpEHHY3QTP2um0txVswiTk2G/wejWyMuYtQ+zI/Az26BJZ2Ilv6YBObZrP7XcdwhK86IypBn0LwyP8RKSodLdmjCIFAROexX9fblAK1tcUvUUk4CW15ON8uI/cdUzwekUca45jKyKPSV4kBiUzz root@VM-16-16-centos
随后,我把老电脑的公钥也添加到服务器的~/.ssh/authorized_keys,或者说,是把服务器的~/.ssh/id_rsa.pub内容追加到~/.ssh/authorized_keys文件中,问题才得以解决,这是旧电脑也能连接到服务器了。
内容追加代码:
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
这时,再使用老电脑连接服务器,就发现可以连接了。
问题解决了,这是本次教程的一个里程碑,标志是问题找到了解决方案。
———————— 下面是后续的排查工作——————-
但是排查工作没有结束,为什么id_rsa公钥会连接不上,反而需要通过配置authorized_key文件才可以连接。
接着,我开始检查密钥私钥文件是不是损坏了,然后使用SSH工具检查:
openssl rsa -check -in /path/to/private_key
执行后,输出如下:
openssl rsa -check -in ~/.ssh/id_rsa
Enter pass phrase for /Users/fangjunyu/.ssh/id_rsa:
RSA key ok
writing RSA key
这表示显示 RSA 密钥是有效的,并且写入了 RSA 密钥。同时表明私钥文件 ~/.ssh/id_rsa 在格式上是有效的,并且没有检测到明显的问题。
升级SSH版本
经过一番深思熟虑的对比,发现老电脑的ssh版本比较低:
1、客户端版本:macOS Monterey 12.7.3
SSH版本:OpenSSH_8.6p1, LibreSSL 3.3.6
2、客户端版本:macOS Sonoma 14.3.1
SSH版本:OpenSSH_9.4p1, LibreSSL 3.3.6
这里可以看到开头场景配置中,关于SSH版本的配置。老电脑的版本为:
ssh -V
OpenSSH_8.6p1, LibreSSL 3.3.6
因此,怀疑是SSH版本的问题,我们开始升级SSH来排查是否能够解决。
首先,我们使用Homebrew升级OpenSSH:
brew upgrade openssh
我在执行brew upgrade openssh过程中,发现openssh没有安装,报了如下问题:
ssh -V
OpenSSH_8.6p1, LibreSSL 3.3.6
fangjunyu@fangjunyudeMacBook-Pro .ssh % brew upgrade openssh
==> Downloading https://formulae.brew.sh/api/formula.jws.json
######################################################################### 100.0%
==> Downloading https://formulae.brew.sh/api/cask.jws.json
######################################################################### 100.0%
Error: openssh not installed
然后我们执行下面的代码进行openssh的安装和升级:
brew install openssh
brew upgrade openssh
安装并升级完成后,运行 ssh -V 命令查看OpenSSH有无升级完成。
ssh -V
OpenSSH_8.6p1, LibreSSL 3.3.6
brew upgrade openssh
Warning: openssh 9.7p1 already installed
ssh -V
OpenSSH_8.6p1, LibreSSL 3.3.6
我们可以看到,安装完成后,版本号还是旧的,但是执行升级命令,则提示已经是最新的版本。
这个问题是路径造成的,我们先确认路径:
which ssh
获得ssh路径为:
/usr/local/bin/ssh
然后,我们在shell配置文件中配置系统路径:配置文件有:~/.bash_profile、~/.bashrc
因为我是用的是zsh,因此我在 ~/.zshrc 文件中配置了这一路径,然后执行下述命令配置系统路径:
SSH_PATH=$(which ssh) \
&& echo "export PATH=\"$SSH_PATH:\$PATH\"" >> .zshrc \
&& source .zshrc
执行完成后,再次执行ssh -V命令,就显示最新的ssh版本了。
ssh -V
OpenSSH_9.7p1, OpenSSL 3.2.1 30 Jan 2024
然后我重新尝试连接服务器,仍然是前面的报错,这表示升级SSH版本这条路走不通。
修改文件权限
检查本地密钥文件(例如 id_rsa)的权限是否正确,它们应该只对所有者有读写权限(600)。错误的权限设置可能导致密钥被拒绝。
根据这一问题,我开始检查本地的密钥权限是否有变动导致的:
ls -al ~/.ssh/id_rsa*
-rw-------@ 1 fangjunyu staff 1766 3 25 15:37 /Users/fangjunyu/.ssh/id_rsa
-rw-------@ 1 fangjunyu staff 400 3 25 15:39 /Users/fangjunyu/.ssh/id_rsa.pub
发现老电脑的配置文件权限没有改动,因此也不是密钥权限的问题。
虚拟机测试
现在又开始怀疑老电脑的配置环境有问题,接着我把id_rsa和id_rsa.pub复制到我VMware Fusion虚拟机内,然后执行:
ssh % ssh root@111.231.22.116
root@111.231.22.116: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).
但是在服务器端执行:
cat id_rsa.pub >> authorized_keys
虚拟机现在也能够连接上服务器了。
这个测试表示并不是老电脑和虚拟机环境的配置,大概率问题还是出在密钥或服务器的公钥上。
虽然,我前面有使用 sha256sum和来校验服务器和老电脑的文件,都是一样的,但还不能排除这个问题,因此我先更换服务器的公钥来判断这个问题。
更换服务器公钥
这里,我是用新电脑连接服务器并执行:
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
前面已经提到了,执行后,我的老电脑也可以使用ssh连接服务器。
接着,我在老电脑上执行:
scp ~/.ssh/id_rsa.pub [用户名]@主机名+地址
具体输出如下:
scp ~/.ssh/id_rsa.pub root@111.231.22.116:/root/.ssh/
id_rsa.pub 100% 400 15.2KB/s 00:00
这样id_rsa.pub文件,就从服务器端传输成功了。然后我再将服务器上新追加的公钥删掉掉。
然后,重新登录服务器,现在老电脑又登不上了。
现在得出的结论是,跟公钥文件没有关系,不是服务器的公钥文件有损坏。另外注意修改id_rsa.pub文件时,也要做一下备份。
未完结的结论
最后,查询了很多教程,最后得出的结论是,客户端的密钥生成id_rsa.pub文件后,不需要传输到服务器上。而是将id_rsa.pub文件内容放到前面提到的~/.ssh/authorized_keys,就可以,所以前面一直有这样的一个误区。
至于,为什么突然之间,老电脑无法连接到服务器,可能是authorized_keys被修改/调整了。但我实际排查的时候,并没有发现authorized_keys有修改的痕迹,或许是我的一个误操作导致的。
该问题暂定定性为:authorized_keys被修改导致无法连接服务器。
完
其他知识
多个密钥认证
在使用SSH连接服务器时,我们可以执行:
ssh -vvv user@host
这个命令表示SSH连接时,会尝试使用多个密钥进行认证。
工作流程为:
- 客户端列出了它的可用身份验证密钥(identity files),
- 客户端尝试通过这些密钥进行身份验证。
- 最后,客户端尝试了所有可用密钥后,连接成功,或者因为没有更多的身份验证方法可尝试,因此连接被拒绝。