Сообщение об ошибке
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. `knownhosts.Normalize` и `knownhosts.Line` формируют из Go записи в правильном формате.
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...