认证失败先分客户端与服务端
SSH 认证失败的症状高度相似——多数情况只返回一行权限拒绝,但原因可能出在客户端提供什么、服务端接受什么、以及两者之间的策略限制。有效的排查路径是:先在客户端用详细输出看它尝试了哪些认证方式、每个方式为什么被拒,再去服务端日志找对应的拒绝原因。两端都看,才不会在「以为是密钥问题、实际是账号被策略限制」这类情况上绕路。
基本信息
| 适用对象 | OpenSSH 客户端与服务端(Linux、macOS、BSD 等) |
|---|---|
| 客户端证据 | 详细输出里的认证方式尝试顺序与拒绝原因 |
| 服务端证据 | 系统授权日志与 sshd 自身日志 |
| 生效配置 | sshd 最终生效值可与配置文件写法不同,需查生效结果 |
| 权限要求 | 读取服务端日志与查看生效配置需要 root |
典型失败原因
- 客户端没提供对的密钥:代理里存在多把密钥,先试错了若干把,触及认证尝试次数上限后被拒
- 服务端没有这把公钥:公钥拼接或追加时换行丢失、写进了错误的用户目录
- 文件权限过宽:家目录或密钥目录可被他人写,服务端按严格模式直接忽略该密钥
- 服务端禁用该方式:口令登录被关闭,或只允许证书签发的密钥
- 账号本身受限:账号被锁定、已过期,或被允许登录名单排除
- 强制约束不满足:公钥条目里限定了来源地址或强制命令,通过也会被立即断开
客户端定位认证方式
客户端定位认证方式
ssh -vvv user@host 2>&1 | grep -i 'offering\|permission denied\|authentications that can continue' # 看尝试顺序与拒绝原因
ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 user@host # 只提供指定密钥,排除代理干扰
ssh-add -l # 检查代理里都装了哪些密钥
eval "$(ssh-agent -s)" && ssh-add -D # 清空代理后重新只加一把密钥
echo $SSH_AUTH_SOCK # 代理套接字不对时,客户端用的不是你以为的密钥服务端确认真实原因
服务端确认真实原因
sshd -T | grep -Ei 'pubkeyauth|passwordauth|permitrootlogin|maxauthtries|allowusers' # 看生效值
journalctl -u sshd -n 50 --no-pager # systemd 系统上的 sshd 日志
journalctl -u ssh -n 50 --no-pager # 单元名随发行版不同
tail -n 50 /var/log/secure # RHEL 系授权日志
tail -n 50 /var/log/auth.log # Debian 系授权日志
sudo sshd -d -p 2222 # 前台调试模式,单次连接的所有决策都会打印
ss -lntp | grep :22 # 确认是不是这台主机、这个进程在处理连接客户端提示与真实原因
| 客户端表现 | 服务端日志线索 | 常见根因 |
|---|---|---|
| 只列出少数认证方式 | 无对应记录 | 服务端未启用该方式或账号被名单排除 |
| 拒绝且日志提示密钥被忽略 | 权限或属主告警 | 目录或文件权限过宽、属主不对 |
| 拒绝但服务端无异常 | 认证尝试耗尽 | 代理内多把密钥把尝试次数用光 |
| 通过后立刻断开 | 强制命令或来源限制触发 | 公钥条目带了附加约束 |
| 提示账号不可用 | 账号锁定或过期 | 口令策略与账号生命周期管理 |
排查顺序建议固定为:客户端详细输出 → 服务端授权日志 → 生效配置。先改配置再找证据是本末倒置,尤其在生产环境上试错可能直接把自己锁在门外。
修改认证相关配置前,务必保留一个已经登录成功的会话,并在改完后先做语法检查再重载;关闭口令认证之前,必须用新窗口确认密钥登录真的可用。