错误信息
ssh: handshake failed: knownhosts: key is unknown
也可能输出为
- ssh: handshake failed: knownhosts: key mismatch
- ssh: must specify HostKeyCallback
`*knownhosts.KeyError` 有一个 `Want` 字段:对于“key is unknown”它为空,对于“key mismatch”则不为空。“ssh: must specify HostKeyCallback”表示 `ClientConfig` 根本没有设置主机密钥检查。
golang.org/x/crypto/ssh/knownhosts (Go) — *knownhosts.KeyError from the HostKeyCallback
含义
`knownhosts` 回调在你的 known_hosts 文件中没有找到这个主机(及端口)的条目,因此拒绝信任服务器出示的密钥。这正是主机身份验证在起作用:没有已知密钥,客户端就无法区分真正的服务器和冒充者。“key mismatch”是更严重的同类错误——主机已经列出,但对应的是另一个密钥。
原因
从未添加过该主机
常见交互式的 OpenSSH 会询问“Are you sure you want to continue connecting?”并记录密钥。Go 程序不会提示,因此从未添加过的主机——或者 known_hosts 为空的新容器——会在这里失败。
主机名或端口格式错误
常见对于 22 以外的端口,条目写作 `[host]:port`。普通的 `host` 条目不匹配到 2222 端口的连接,IP 地址也不匹配以 DNS 名称记录的条目。
服务器的密钥变了(key mismatch)
偶见重装过的服务器、被回收再分配的云 IP,以及位于多台主机前面的负载均衡器,都会出示新的密钥。不匹配也可能意味着连接被拦截,因此必须通过核对新指纹来解决,而不是删除这项检查。
修复方法
- 1.
验证主机密钥后再添加
`ssh-keyscan` 只是获取网络给你的内容。添加之前,先把指纹与可信来源进行比对;把验证过的条目固化到镜像或预配流程中。
bash # Fetch the host key, then compare its fingerprint with one obtained out of band # (cloud console, provisioning output, the server's /etc/ssh/*.pub). ssh-keyscan -t ed25519 -p 22 server.example.com > /tmp/hostkey ssh-keygen -lf /tmp/hostkey cat /tmp/hostkey >> ~/.ssh/known_hosts # only after the fingerprints match - 2.
自定义端口使用带方括号的写法
knownhosts 与 OpenSSH 一样,严格匹配主机和端口。在 Go 中,`knownhosts.Normalize` 和 `knownhosts.Line` 可以生成格式正确的条目。
text # known_hosts entry for a non-default port: brackets and the port are part of the name [server.example.com]:2222 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...