できない.dev

SSH で「Host key verification failed」が出て接続できない

接続先が提示したホスト鍵が known_hosts の記録と一致しないか、記録自体が無いときに出る。
サーバーを作り直したのか中間者攻撃なのかを鍵指紋で確かめてから、古い記録を消して入れ直す。

公開:

要約

Host key verification failed. は、接続先が示したホスト鍵が ~/.ssh/known_hosts の記録と食い違ったときに出る。ssh(1)(新しいタブで開く) が説明するとおり、SSH は初回接続で相手の公開鍵を記録し、2 回目以降は毎回それと照合する。
食い違いは「相手が入れ替わった」という警告なので、鍵を消す前に理由を確かめる。

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Offending ECDSA key in /home/me/.ssh/known_hosts:12
Host key verification failed.

多くの場合はサーバーの作り直しが理由である。
ただし「多くの場合」で片付けると中間者攻撃を見逃すため、指紋の照合を挟む。

よくある原因

  1. サーバーを作り直した: OS の再インストールや、クラウドのインスタンス再作成でホスト鍵が生成し直されている。
    移行時に /etc/ssh/ssh_host_* を引き継がなければ必ず変わる。
  2. IP が再利用された: known_hosts はホスト名だけでなく IP でも記録される。
    クラウドでは同じ IP が別の利用者に回るため、名前は違っても IP の行が衝突する。
  3. 接続先が実は別のホスト: 踏み台やポートフォワードの設定を変えると、localhost:2222 のような同じ宛先で違うサーバーに繋がる。
  4. 記録が無いまま非対話で実行: CI では確認プロンプトに答えられない。StrictHostKeyCheckingyes 相当なら、未知のホストというだけで失敗する。
  5. known_hosts の破損: 手で編集して行が折り返された、あるいはファイルが読み取り専用になっている場合も一致に失敗する。

解決策

1. 相手の指紋を先に確認する

ssh-keyscan -t ed25519 example.com | ssh-keygen -lf -

サーバー側にログインできるなら、そこで同じ値を出して突き合わせる。

ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub

一致すれば正当な変更である。
一致しない、あるいは確認手段が無いなら、その接続は行わない。

2. 古い記録を削除する

ssh-keygen -R example.com
ssh-keygen -R 203.0.113.10

ssh-keygen(1)(新しいタブで開く)-R はホスト名がハッシュ化されていても該当行を消せる。
ホスト名と IP の両方を消しておくと再発しにくい。
削除後にもう一度接続し、表示された指紋が手順 1 の値と同じことを確認してから受け入れる。

3. CI では事前に登録する

mkdir -p ~/.ssh && chmod 700 ~/.ssh
ssh-keyscan -t ed25519 github.com >> ~/.ssh/known_hosts

ssh-keyscan の結果をそのまま信用するのは初回だけなので、GitHub のように指紋が公開されているサービスでは、取得した値を提供元のドキュメントと照合してから固定する。
以後は取得ではなくリポジトリに保存した値を使う。

4. 一時回避は範囲を限定する

ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null user@example.com

このオプションは照合そのものを捨てるため、恒久的な設定ファイルには書かない。
使い捨ての検証環境に限る。

この記事は役立ちましたか?