SSH 密钥登录失败时,先看这几处
公钥认证失败通常不会给出明确原因,客户端只是一句
Permission denied (publickey)。下面这套顺序是从最常见的几类原因排下来的,
大部分情况能在前两步解决。
第一步:把失败点定位到具体环节
在客户端加 -v,看日志里发送了哪把密钥、服务端接受还是拒绝:
ssh -v user@host
关注这几行:
debug1: Offering public key: ~/.ssh/id_ed25519
debug1: Authentications that can continue: publickey
debug1: No more authentication methods to try.
如果出现了 Offering 却被拒绝,说明密钥发出去了但服务端不认;
如果根本没出现 Offering,是本地没有可用密钥,或者
IdentitiesOnly / agent 的问题。
第二步:检查服务端权限
sshd 对权限很严格:家目录、~/.ssh、
authorized_keys 都不能对组和其他用户可写,
否则该文件会被直接忽略。
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod g-w,o-w ~ # 家目录不能对 group/other 可写
用 ls -ld 一眼看出问题:
ls -ld ~ ~/.ssh ~/.ssh/authorized_keys
# 期望类似
# drwx------ user user ~
# drwx------ user user ~/.ssh
# -rw------- user user ~/.ssh/authorized_keys
属主也要对。如果 authorized_keys 属于 root 而登录用户是别人,
同样会被拒绝。
第三步:确认服务端真的启用了密钥登录
配置文件里写了什么不算数,要看解析后的生效值:
sudo sshd -T | grep -Ei 'pubkey|password|authorizedkeysfile|permitrootlogin'
重点看 authorizedkeysfile。默认是
.ssh/authorized_keys .ssh/authorized_keys2,
但有些发行版或加固脚本会改成别的路径(比如集中放到 /etc/ssh/keys/%u),
这时你放在 ~/.ssh/authorized_keys 的内容就不会被读取。
sshd -t 校验再 reload。
改错了直接重启可能导致再也登不上,尤其是只开了密钥认证的机器。
第四步:Windows OpenSSH 的额外要求
在 Windows 上用 OpenSSH Server 时,如果登录账户属于管理员组,
密钥文件不是 ~/.ssh/authorized_keys,而是:
C:\ProgramData\ssh\administrators_authorized_keys
并且它对 ACL 有硬性要求:只能有 Administrators 和 SYSTEM 有权限。 用 icacls 设置:
icacls C:\ProgramData\ssh\administrators_authorized_keys `
/inheritance:r `
/grant "Administrators:F" `
/grant "SYSTEM:F"
这一步非常容易漏。文件内容和格式都对、权限看起来也没问题,
但只要继承了别的 ACE,sshd 就会静默忽略整个文件,表现就是「密钥明明放对了却登不上」。
判断方法:把客户端 -v 打开,服务端同时看 OpenSSH 日志
(事件查看器 → 应用程序和服务日志 → OpenSSH → Operational),
里面会明确写 Authentication refused: bad ownership or modes 之类的信息。
第五步:编码与换行
把公钥拷贝过去时最容易出问题的是换行。Windows 记事本存成 CRLF, 或复制时带上了多余的空格,都会让 sshd 解析失败。
# 检查是否存在 CR
grep -c $'\r' ~/.ssh/authorized_keys
# 清理并确保只有一行
sed -i 's/\r$//' ~/.ssh/authorized_keys
也可以用 ssh-copy-id 让它自己处理,比手工复制可靠:
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host
排查清单
| 现象 | 大概率原因 |
|---|---|
| 完全没有 Offering 行 | 本地无密钥 / agent 未加载 / 指定了错误的 IdentityFile |
| Offering 之后被拒 | 服务端权限、属主、authorizedkeysfile 路径 |
| 只有 root 能登、普通用户不行 | AllowUsers / AllowGroups 限制 |
| Windows 上密钥放对仍失败 | administrators_authorized_keys 的 ACL |
| 同样的密钥昨天能用今天不行 | 家目录被改过权限,或密钥文件被重启脚本覆盖 |