エラーメッセージ
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...