公钥没放对位置、目录多了一个可写位、算法被新版 OpenSSH 关掉,是免密登录失败的三个主因,均在 WSL2 Ubuntu 24.04 实测。
先给结论:Ubuntu 24.04 与 Debian 12 上,ssh-keygen 不加 -t 就直接生成 ed25519 密钥,服务器端要动的通常只有 ~/.ssh/authorized_keys 这一处;PubkeyAuthentication 与 StrictModes 默认都是开着的,真正容易把登录卡死的是目录或文件多出来的可写位,以及带口令的私钥在脚本里无法输入口令。下面所有命令与报错原文都来自一台 WSL2 Ubuntu 24.04.4 测试机(OpenSSH 9.6p1),文末列出未实测的范围。
一、生成密钥:默认已是 ed25519,口令要算进自动化计划
ssh-keygen -t ed25519 -C "build@office" -f ~/.ssh/id_build # 交互询问口令,直接回车即无口令
ssh-keygen -t ed25519 -f ~/.ssh/id_ci -N "" -q # 无口令加安静模式,CI 与脚本用这种
ls -l ~/.ssh/id_build ~/.ssh/id_build.pub # 实测 600 私钥、644 公钥、目录 700
ssh-keygen -l -f ~/.ssh/id_build.pub # 实测输出 256 SHA256:... (ED25519)
ssh-keygen -y -f ~/.ssh/id_build # 从私钥反出公钥,实测可直接粘贴
实测细节:
-t 时,Ubuntu 24.04 的 ssh-keygen 生成 ed25519,用 ssh-keygen -l 复核打印 (ED25519)。手册把 -t 的候选写成 dsa、ecdsa、ecdsa-sk、ed25519、ed25519-sk、rsa,并注明默认是 ed25519 [1]。-a 控制私钥加密时的密钥派生轮数,手册说明轮数越高口令校验越慢、抗暴力破解越强 [1],给密钥设口令时值得加上。-p,加 -o 会顺带把私钥存成新格式,实测输出 Your identification has been saved with the new passphrase.;旧口令写错时实测报 Failed to load key ...: incorrect passphrase supplied to decrypt private key。改注释用 -c,实测先打印 Old comment: ... 再打印 Comment ... applied。ssh -o BatchMode=yes 实测直接 Permission denied (publickey,password),去掉 BatchMode 则卡在口令提示上。要么把私钥交给 ssh-agent,要么用 -N "" 生成无口令私钥。ssh -G 目标主机 | grep pubkeyacceptedalgorithms 的默认列表里有 ssh-ed25519、ecdsa-sha2 系列、rsa-sha2-512、rsa-sha2-256,没有 ssh-dss 与 ssh-rsa;同一台机器上 ssh-keygen -t dsa 仍能生成密钥文件,但用它登录实测被拒。二、公钥上服务器:ssh-copy-id 的真实行为,与没有它的时候
ssh-copy-id -n -i ~/.ssh/id_build.pub user@10.0.0.5 # 实测 dry run,只试不写
ssh-copy-id -i ~/.ssh/id_build.pub user@10.0.0.5 # 只追加登录失败的那几把
cat ~/.ssh/id_build.pub | ssh user@10.0.0.5 \
'umask 077; mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys'
手册写得很直白:ssh-copy-id 先用这些密钥逐个试登录,能登进去的说明已安装,只有失败的才被追加到远端 ~/.ssh/authorized_keys,目录和文件不存在时一并创建 [2]。实测 dry run 对已存在的公钥输出 WARNING: All keys were skipped because they already exist on the remote system.,所以重复执行不会写重复行,要强行再追加就用 -f。同一页还提示它依赖能登进去,通常意味着密码认证要先开着 [2],这与实测一致:PasswordAuthentication no 之后,未安装的公钥用 ssh-copy-id 推送失败,报 Permission denied (publickey)。
本机 ssh-copy-id --help 实测报 Illegal option --,看用法要用 -h 或 -?,用法行里有 -f -n -s -x -i -p -F -t -o,比多数教程列的多,其中 -t 能指定远端目标文件 [2]。
还有一条 Windows 侧实测事实:C:\Windows\System32\OpenSSH 里只有 ssh.exe、ssh-keygen.exe、ssh-add.exe、scp.exe 等,没有 ssh-copy-id.exe,该目录的 ssh.exe 自报 OpenSSH_for_Windows_9.5p2, LibreSSL 3.8.2。在 Windows 上照抄一行式 ssh-copy-id 会直接失败,得走上面那条手动追加,或换用自带 ssh-copy-id 的 Git Bash(其 ssh 为 10.2p1)。
三、authorized_keys 权限:致命的是可写,不是可读
chmod 700 ~/.ssh; chmod 600 ~/.ssh/authorized_keys # 推荐的稳妥值
sshd -T | grep strictmodes # 实测 strictmodes yes
stat -c '%a %U:%G %n' ~/.ssh ~/.ssh/authorized_keys # 排错先看清现值与属组
journalctl -u ssh -n 50 | grep -i "bad ownership" # 实测可见 refused 行
StrictModes 默认是 yes,含义是登录前检查用户文件与主目录的权限和属主,手册给出的理由是新手常把目录或文件留成其他人可写 [4]。实测权限矩阵,目标用户为测试账号:
authorized_keys 取 600、644、604、640、660、664、620 时登录全部成功;取 606、602、200、000 时被拒。也就是说 644 不会让登录失败,公钥清单本来也不是秘密,真正致命的是其他用户可写,以及文件读不到。Authentication refused: bad ownership or modes for file ~/.ssh/authorized_keys。Authentication refused: bad ownership or modes for directory ~/.ssh;700、750、770、775、755 都放行。主目录 775 未触发拒绝。sshd 手册把默认公钥文件写作 ~/.ssh/authorized_keys 与 ~/.ssh/authorized_keys2,实测 sshd -T 的 authorizedkeysfile 正是这两项 [3]。同一页描述公钥行可以带选项,例如 command=、from=、no-pty,restrict 一次关掉全部转发与伪终端 [3]。实测三行带选项的公钥,行为与手册一致:command="echo FORCED_CMD" 让客户端命令被忽略、只跑指定命令;from="10.20.30.40" 让本机登录被拒;no-pty 让 ssh -tt 报 PTY allocation request failed on channel 0,去掉后同一会话能拿到伪终端。
四、sshd 开关与算法:Ubuntu 24.04 的真实默认值
grep -nE "^(Include|KbdInteractiveAuthentication)" /etc/ssh/sshd_config # 实测只有这两行是活的
printf 'PasswordAuthentication no\n' | sudo tee /etc/ssh/sshd_config.d/99-hardening.conf
sudo systemctl reload ssh && sudo sshd -T | grep -E "passwordauthentication|pubkeyauthentication"
ssh -o BatchMode=yes -o PreferredAuthentications=password user@10.0.0.5 # 实测 Permission denied
sudo rm /etc/ssh/sshd_config.d/99-hardening.conf && sudo systemctl reload ssh # 回滚这一步
Ubuntu 24.04 的 /etc/ssh/sshd_config 实测只有 Include /etc/ssh/sshd_config.d/*.conf 和 KbdInteractiveAuthentication no 两行未注释,其余靠上游默认,用 sshd -T 才看得到真正生效的值,本机实测为 pubkeyauthentication yes、passwordauthentication yes、strictmodes yes、kbdinteractiveauthentication no、permitrootlogin without-password。手册侧对应 PubkeyAuthentication 默认 yes、PermitRootLogin 默认 prohibit-password、StrictModes 默认 yes [4]。改动建议写进 sshd_config.d 下的独立文件,实测删除该文件再 systemctl reload ssh 就能完整恢复原状态。同一份手册还说明同一关键字取先出现的那个值 [4],所以 drop-in 与主文件冲突时先加载的赢。
算法兼容方面,官方把 SHA-1 系、DSA 与 ssh-rsa 签名算法归为遗留算法并默认不启用,同时给出在命令行临时指定 PubkeyAcceptedKeyTypes 与 KexAlgorithms 的过渡写法,长期方案是升级过旧的实现 [5]。实测吻合:强制 PubkeyAcceptedAlgorithms=ssh-rsa 时登录被拒,改成 rsa-sha2-512 时成功。
| 组件 | 本机版本 | 实测到的行为 | 仅文档口径 | | — | — | — | — | | WSL2 Ubuntu 24.04.4 | OpenSSH 9.6p1-3ubuntu13.20 | 密钥生成、权限矩阵、开关与算法 | Debian 12 的 8.9p1 表现 | | Windows 11 自带客户端 | OpenSSH_for_Windows_9.5p2 | 目录内无 ssh-copy-id.exe,公钥登录成功 | 域账号与第三方客户端 | | MSYS 与 Git Bash 客户端 | OpenSSH 10.2p1 | 自带 ssh-copy-id | 各版本发布日期 |
五、多密钥、agent 与 Windows 客户端
ssh -G user@10.0.0.5 | grep -E "^(identitiesonly|addkeystoagent)" # 实测 no 与 false
eval "$(ssh-agent -s)"; ssh-add ~/.ssh/id_build; ssh-add -l; ssh-add -D; ssh-agent -k
ssh -o BatchMode=yes -o IdentitiesOnly=yes -i ~/.ssh/id_build user@10.0.0.5 # 实测成功
ssh -o BatchMode=yes -o IdentitiesOnly=yes user@10.0.0.5 # 实测被拒
客户端实测默认值是 identitiesonly no 与 addkeystoagent false:私钥不会被自动塞进 agent,而 agent 里的密钥会在默认身份之前被尝试。判别实验是这样做的:agent 里只放 id_build 时,不加 IdentitiesOnly 能登录,加上 IdentitiesOnly=yes 且不给 -i 就报 Permission denied (publickey,password),补上 -i 又成功。所以一台机器管多台时,用 -i 加 IdentitiesOnly=yes 才能定死用哪把密钥,配合 ~/.ssh/config 里按 Host 指定 IdentityFile 更省心。
Windows 侧实测链路是:先在 Ubuntu 主机上把 Windows 生成的公钥追加进 authorized_keys,再用 C:\Windows\System32\OpenSSH\ssh.exe -o BatchMode=yes -i 密钥文件 user@内网IP 登录,成功返回远端的 id -un 与 uname -sr 输出,全程没用 ssh-copy-id。注意 Windows 版 ssh-keygen 的 -N 参数写不好会把引号当成口令本身,实测那样生成的私钥带口令,BatchMode 登录随即失败。
六、排错速查表与撤销路径
| 现象 | 常见原因 | 处理 | | — | — | — | | 服务器上有公钥却仍要密码 | 私钥带口令,BatchMode 或脚本无法输入 | 先 ssh-add 载入私钥,或改用无口令私钥(实测) | | 日志出现 bad ownership or modes | 目录或文件对其他用户可写,或属组不是本人主组 | chmod 700 与 chmod 600,再核对属主属组(实测) | | 公钥已追加但登录被拒 | 公钥文件读不到,或 authorized_keys 被其他用户可写 | 权限改回 600,属组改回该用户主组(实测) | | ssh-copy-id 报 Permission denied | 密码认证已关,或首次推送没有可用身份 | 临时开回 PasswordAuthentication,或走手动追加(实测) | | Windows 上 ssh-copy-id 不是命令 | 自带 OpenSSH 不含这个脚本 | 用手动追加,或换带 ssh-copy-id 的 Git Bash(实测) | | 老服务器协商失败 | 只剩遗留算法或遗留密钥交换算法 | 按官方兼容页临时指定算法,长期是升级版本(文档口径) |
撤销路径分三层。密钥层:删本地私钥与公钥,服务器上先 cp ~/.ssh/authorized_keys ~/.ssh/authorized_keys.bak,再用 grep -v '注释名' ~/.ssh/authorized_keys > /tmp/ak && mv /tmp/ak ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys,实测按注释删掉单行后其余密钥仍可登录。配置层:删掉 drop-in 文件再 systemctl reload ssh,实测登录行为立刻恢复原状;只改一行也可以用 sudo sed -i.bak 先留备份。工具层:测试机上 systemctl stop ssh ssh.socket、sudo apt-get purge -y openssh-server openssh-sftp-server 加 sudo apt-get autoremove --purge -y,再删测试用户与主机密钥,实测 /etc/ssh 回到只剩 ssh_config 与 ssh_config.d 的状态。
**常见提问**
-f。permitrootlogin without-password,即允许公钥、拒绝口令;把它改成 no 之后公钥也会被拒,这一条属于文档口径。~/.ssh/config 里按 Host 指定 IdentityFile 并配合 IdentitiesOnly,实测这一组合能锁定用哪把密钥。局限性:全部实测在一台 WSL2 的 Ubuntu 24.04.4 LTS 与同一台 Windows 11 上完成,OpenSSH 版本 9.6p1,时间为 2026-10-28。未在本机复现的部分包括真实重启后的自启行为、RPM 系的 sshd 配置路径与服务名、SELinux 对 .ssh 安全上下文的拦截、Debian 12 与 Fedora 的默认值差异、authorized_keys 其余选项如 restrict 与 permitopen、以及 authorized_keys2 的弃用时间表。这些只按文档口径表述,不作为实测结论。
**实测记录**
-t 生成 ed25519 已用 ssh-keygen -l 复核,私钥 600、公钥 644、目录 700;-p -o、-c、-y、-l、-e 行为与手册一致;带口令的私钥在 BatchMode 下认证失败,去掉 BatchMode 则停在口令提示。sshd -T 实测 pubkeyauthentication yes、passwordauthentication yes、strictmodes yes、kbdinteractiveauthentication no、permitrootlogin without-password、authorizedkeysfile 含 authorized_keys2;权限矩阵与属组实验如正文所列,两条 refused 日志原文已记录;from=、command=、no-pty 三个选项行为已复现。Permission denied (publickey),再关 pubkeyauthentication 时报 Permission denied (),删除 drop-in 并 reload 后恢复登录;强制 ssh-rsa 失败、rsa-sha2-512 成功;ssh -G 默认 addkeystoagent false、identitiesonly no。ss -tlnp 已无 22 端口监听。一处副作用:安装过程里 apt 把 openssh-client 从 1:9.6p1-3ubuntu13.16 升到 1:9.6p1-3ubuntu13.20,未回退。参考资料
- [1] ssh-keygen(1) – Ubuntu 24.04 noble manual page(ssh-keygen手册)
- [2] ssh-copy-id(1) – Ubuntu 24.04 noble manual page(ssh-copy-id手册)
- [3] sshd(8) – OpenBSD manual page(sshd手册)
- [4] sshd_config(5) – OpenBSD manual page(sshd_config手册)
- [5] OpenSSH: Legacy Options(OpenSSH兼容说明)
文中主要命令已在 WSL Ubuntu(24.04)实测并核对其在 Debian 系与通用发行版的文档口径。