跳到主要内容
AnyStorage
免费下载

SFTP 与 SSH 密钥

SFTP Permission denied (publickey) 排查清单

括号里列的是服务器还允许的认证方式,不是失败的那一个。怎么读 ssh -v,以及这句报错背后的七个原因。

OpenSSH 说 Permission denied (publickey) 到底指什么、服务端坚持的文件权限与密钥格式,以及让老 RSA 密钥失效的那次算法变更。

sftp permission denied publickey,SFTP 公钥认证失败,authorized_keys 权限

这一行,以及所有人都读错的地方

sh

$ sftp alice@files.example.com
alice@files.example.com: Permission denied (publickey).

这句话在 OpenSSH 客户端里只有一个生成点,看它的格式字符串最省事:

text

fatal("%s@%s: Permission denied (%s).",
    authctxt->server_user, authctxt->host, authlist);

最后那个字段是 authlist——服务器仍然愿意接受的认证方式列表,不是失败的那个方式。所以 Permission denied (publickey) 的意思是:我把手上有的都试了,服务器只提供公钥认证,而我的密钥没被接受。如果它写的是 (publickey,password),你还有密码可退;既然没有,就别再找密码入口了。

症状、原因与处理
你看到什么原因处理
立刻失败,-v 里没有 "Offering public key"客户端根本没找到/没发出密钥-iIdentitiesOnly yes
-v 发了密钥,服务端仍然拒绝authorized_keys 里没有,或用户名不对检查目标账号下的那份文件
一个用户能用,另一个不行~~/.sshauthorized_keys 的权限目录 700,文件 600
-v 出现 "no mutual signature algorithm"OpenSSH 8.8 起 ssh-rsa 默认被禁换密钥类型,或按主机重新启用
服务端日志写 "invalid format"密钥文件不对:.ppk,或把公钥当私钥转成 OpenSSH 格式
Windows 上只有管理员账号失败没用 administrators_authorized_keys写那个文件,修好它的 ACL
只在脚本或跳板机里失败没有 agent,或 agent 没转发ssh-addForwardAgent 要有意识地用

1. 先读 verbose 日志

在看到客户端自己对这次握手的记录之前,下面所有内容都只是猜测。

sh

ssh -v alice@files.example.com
sftp -v alice@files.example.com

三行字带着答案,而且都是 OpenSSH 源码里的字面字符串。Authentications that can continue: publickey 是服务端的方式列表;Offering public key: /Users/alice/.ssh/id_ed25519 表示客户端真的发出了这把密钥——如果这行不存在,问题完全在客户端;no mutual signature algorithm 则是第 4 步的算法不匹配。

服务端把 sshd_config 的日志级别抬起来:LogLevel 接受 QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG, DEBUG1, DEBUG2, DEBUG3,默认 INFO。要记录密钥指纹,VERBOSE 就够了;手册明确警告以 DEBUG 级别记录日志「violates the privacy of users and is not recommended」。

2. 两端的权限都要修

这是服务端最常见也最不显眼的原因:密钥是对的,但放在一个别人可写的目录里,就会被静默忽略。sshd 手册写得很清楚,~/.ssh「the recommended permissions are read/write/execute for the user, and not accessible by others」,~/.ssh/authorized_keys「the recommended permissions are read/write for the user, and not accessible by others」。原因紧接在后面:「If this file, the ~/.ssh directory, or the user's home directory are writable by other users, then the file could be modified or replaced by unauthorized users」,这种情况下「sshd will not allow it to be used unless the StrictModes option has been set to 'no'」。而 StrictModes 默认就是 yes

sh

chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod go-w ~
ls -ld ~ ~/.ssh ~/.ssh/authorized_keys

客户端同理:能被别人读到的私钥会被 ssh 自己拒绝,chmod 600 ~/.ssh/id_ed25519

3. 检查文件、格式和用户名

authorized_keys 一行一把密钥,手册把字段描述为「options, keytype, base64-encoded key, comment」,其中 options 可选。复制粘贴或浏览器下载塞进来的换行会把 base64 切断,那一行就静默失效。

sh

ssh-keygen -lf ~/.ssh/id_ed25519.pub
tail -c 100 ~/.ssh/authorized_keys | cat -A | tail -2

同一族还有两件事。密钥必须在你登录的那个账号的 authorized_keys 里,所以拿 alice 的密钥去 sftp root@host 一定失败。另外 sshd_configAuthorizedKeysFile 可以指向别处——手册说它「may include wildcards」并支持 token,所以加固过的主机可能读的是 /etc/ssh/keys/%u 而不是家目录。

4. 让老 RSA 密钥失效的那次算法变更

如果一把用了好几年的密钥突然不行了,先看这条。OpenSSH 8.8 的发布说明写着:「This release disables RSA signatures using the SHA-1 hash algorithm by default. This change has been made as the SHA-1 hash algorithm is cryptographically broken.」被禁的是 ssh-rsa 这个签名算法,不是 RSA 密钥本身。

ssh_configPubkeyAcceptedAlgorithms 的当前默认清单包含 rsa-sha2-512rsa-sha2-256,没有 ssh-rsa。自己机器上的情况可以直接问:

sh

ssh -Q PubkeyAcceptedAlgorithms

发布说明给的临时办法是按目标主机重新启用,它同时把这件事定位为「only as a stopgap measure until legacy implementations can be upgraded or reconfigured with another key type (such as ECDSA or Ed25519)」:

text

Host old-host
    HostkeyAlgorithms +ssh-rsa
    PubkeyAcceptedAlgorithms +ssh-rsa

+ 表示追加到默认集合,- 表示移除,^ 表示放到最前。更好的办法是换新密钥:ssh-keygen -t ed25519

5. agent、口令,以及密钥太多的问题

私钥带口令而环境里没人会弹窗(cron、CI、GUI 应用)时,客户端没办法解开它。装进 agent 一次就好:

sh

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
ssh-add -l

反向的失败也存在。MaxAuthTries 默认是 6,如果 agent 一口气递上十几把密钥,客户端还没轮到对的那把就被切断了。解法是 IdentitiesOnly:它让 ssh「only use the configured authentication identity and certificate files … even if ssh-agent or a PKCS11Provider or SecurityKeyProvider offers more identities」。

sh

ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 alice@files.example.com

跳板机优先用 ProxyJump,而不是转发 agent。真要转发就按主机开,不要做成全局配置。

6. Windows 服务端有第二份密钥文件

这个坑很费时间,因为通用教程在你最可能用来测试的那类账号上恰好是错的。微软文档说得很直接:管理员用户的公钥要放进 C:\ProgramData\ssh\ 下的 administrators_authorized_keys,并且「This file only applies to administrator accounts. You must use it instead of the user-specific file within the user's profile location.」ACL 必须只允许管理员和 SYSTEM:

powershell

icacls.exe "$env:ProgramData\ssh\administrators_authorized_keys" /inheritance:r /grant "Administrators:F" /grant "SYSTEM:F"

同一页还有两个注记:Windows OpenSSH 不支持 AuthorizedKeysCommandAuthorizedKeysCommandUser;密钥认证对本地账号和 Active Directory 账号有效,但 Microsoft Entra ID 账号不支持。

密钥通了之后

认证修好之后,剩下的问题是这条连接拿来做什么。AnyStorage(v0.2.24;macOS 11+、Windows 10+、Ubuntu 20.04+)支持以密钥认证连接 SFTP 主机,和 S3 兼容端点、WebDAV 放在同一个窗口里,免费版可用两个连接。想把主机当成驱动器而不是文件列表时,它通过内置的本地 WebDAV 服务(http://127.0.0.1:3211)挂载——不用 FUSE、WinFsp、macFUSE,也就不用在刚解决的密钥问题上再叠一层 sshfs 的调试。

(publickey) 是不是说我的密钥错了?

它说的是服务器只接受公钥认证,而你提供的东西没有满足它——这里面也包括"你什么都没提供"。所以 ssh -v 和 "Offering public key" 那一行才是第一步。

为什么 ssh 能进,sftp 不行?

认证相同,服务不同。如果密钥能过 sshsftp 在后面失败,去看 sshd_config 里的 Subsystem 行(sftp-server 还是 internal-sftp),以及 ChrootDirectory——它的权限和所有者是被 sshd 无条件检查的。

我的老 RSA 密钥还能用吗?

只要它是长度足够的真 RSA 密钥就能用:现代的 rsa-sha2-256rsa-sha2-512 签名算法用的是同一把密钥。默认被禁的只是 SHA-1 的 ssh-rsa 签名。

.ppk 文件可以直接用吗?

不能。PuTTY 的格式是自己的,用 PuTTYgen 的 Conversions 菜单导出成 OpenSSH 私钥,或者用 ssh-keygen 重新生成一对。

下一步