「Host key verification failed」の解決 - known_hostsの扱い

「Host key verification failed」の解決 - known_hostsの扱い

「Host key verification failed」とは何を意味するのか?

結論: サーバの提示したホスト鍵が、クライアントが記憶している鍵と食い違ったため接続を打ち切った状態。鍵やパスワードの問題ではなく「サーバの身元確認」で止まっている。

SSH はパスワードや公開鍵で 自分を認証する 前に、まず 接続先サーバが本物か を確認する。この確認に使うのがサーバの「ホスト鍵」で、一度接続したサーバの鍵は ~/.ssh/known_hosts に記録される。次回以降、提示された鍵が記録と一致しなければ SSH は接続を中断する。これが Host key verification failed だ。

Host key verification failed.

重要なのは、このエラーには 2つの異なる原因 があることだ。

  • 記録済みの鍵と違う鍵が提示された(サーバ再構築・IP 再利用、まれに中間者攻撃)
  • 初めて接続するサーバで、厳格チェックにより未知の鍵を拒否したStrictHostKeyChecking yes 等)

この2つは対処がまったく違う。まずどちらかを見分ける。

前提(対象環境)

  • クライアント: Ubuntu / macOS(考え方は共通)
  • サーバ: OpenSSH server
  • 確認対象は基本的に クライアント側~/.ssh/known_hosts

まず原因を切り分けるには?

結論: エラーの直前に出るメッセージを読む。REMOTE HOST IDENTIFICATION HAS CHANGED なら鍵の不一致、No ... host key is known なら初回接続の拒否。

Host key verification failed.直前の行 に原因が書いてある。スクロールして必ずそこを読む。

パターンA: 鍵が変わった(記録と不一致)

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
...
Offending ECDSA key in /home/user/.ssh/known_hosts:12
...
Host key verification failed.

パターンB: 初回接続で拒否された

No ED25519 host key is known for server.example.com and you have requested strict checking.
Host key verification failed.

パターンA は 鍵が変わった場合の直し方、パターンB は 初回接続で弾かれる場合へ進む。

なぜ鍵が変わるのか?原因の全体像

結論: 大半はサーバ側の正当な変更(再構築・IP 再利用)。ごく一部に中間者攻撃の可能性があるため、消す前に変更が正当か必ず裏取りする。

原因 起きやすい状況 危険度
サーバ再構築・OS 再インストール ホスト鍵が再生成された
IP / ホスト名の再割り当て クラウド・DHCP で別サーバが同じ宛先になった
ホスト鍵のローテーション 運用方針で鍵を更新した
接続先の取り違え 踏み台越し・ポートフォワードで別ホストに繋いだ
中間者攻撃(MITM) 経路上で第三者が偽サーバに誘導している

ほとんどは低危険度だが、「心当たりがない」のに鍵が変わったときは 削除する前の確認を飛ばさない。

known_hosts はどこにあり、何を記録しているか?

結論: ユーザーごとの記録は ~/.ssh/known_hosts、システム全体は /etc/ssh/ssh_known_hosts。各行が「ホスト名/IP + 鍵種別 + 公開鍵」で、こことの不一致が今回のエラーを生む。

$ cat ~/.ssh/known_hosts

1行が1ホスト1鍵に対応する。

server.example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA...
[server.example.com]:2222 ecdsa-sha2-nistp256 AAAAE2VjZHNh...

標準ポート以外は [ホスト名]:ポート の形式で記録される点に注意する。該当エントリを探すには ssh-keygen -F を使う。

$ ssh-keygen -F server.example.com

HashKnownHosts yes(Ubuntu のデフォルト)ではホスト名がハッシュ化され、cat してもどの行か目視できない。だが後述の ssh-keygen -R / -F はハッシュ化されたエントリも正しく扱えるので、手で編集する必要はない。

鍵が変わった場合の直し方(ssh-keygen -R)

結論: 該当エントリを ssh-keygen -R ホスト名 で削除し、再接続して新しい鍵を登録し直す。known_hosts を手で開いて消す必要はない。

エラー文に Offending ... key in /home/user/.ssh/known_hosts:12ファイルと行番号 が出ている。ここを消すのが正解だが、行番号で手編集するより ssh-keygen -R が安全だ。

$ ssh-keygen -R server.example.com
# Host server.example.com found: line 12
/home/user/.ssh/known_hosts updated.
Original contents retained as /home/user/.ssh/known_hosts.old

標準ポート以外を使っている場合は、記録形式に合わせて指定する。

$ ssh-keygen -R '[server.example.com]:2222'

IP でも接続している場合は、ホスト名と IP の両方のエントリを消す必要がある。

$ ssh-keygen -R 192.0.2.10

削除後に再接続すると、新しい鍵について確認を求められる。フィンガープリントを確認して yes で登録する。

$ ssh user@server.example.com
The authenticity of host 'server.example.com (192.0.2.10)' can't be established.
ED25519 key fingerprint is SHA256:abcd1234...
Are you sure you want to continue connecting (yes/no/[fingerprint])?

古い OpenSSH では行番号で手編集する記事も多いが、HashKnownHosts 環境や複数エントリで事故りやすい。ssh-keygen -R を優先する。

削除する前に:本当に正規の変更か確認する

結論: 鍵が変わる心当たりがないなら、削除前にサーバ側の正規フィンガープリントと突き合わせる。一致しなければ中間者攻撃を疑い、その経路では接続しない。

Host key verification failed の本来の役目は なりすましの検知 だ。警告を機械的に消す癖は、その防御を自分で外すことになる。

サーバに別経路(コンソール等)で入れるなら、サーバ自身が持つホスト鍵のフィンガープリントを表示する。

$ ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
256 SHA256:abcd1234... root@server (ED25519)

この SHA256:... が、再接続時に SSH が表示するフィンガープリントと 一致 すれば正規の変更だ。安心して登録してよい。一致しなければ、その接続経路を疑う。

初回接続で弾かれる場合(StrictHostKeyChecking)

結論: No ... host key is known ... strict checking は、未知ホストを StrictHostKeyChecking yes が拒否した状態。鍵を安全に登録すれば通る。むやみに no へ緩めない。

初めて接続するサーバで、かつ厳格チェックが有効だと、対話確認なしに即拒否される。

No ED25519 host key is known for server.example.com and you have requested strict checking.
Host key verification failed.

対処は「正しい鍵を known_hosts に登録する」こと。最も安全なのは、サーバ側の正規フィンガープリントを 事前に確認したうえで登録する方法だ。一時的に通すだけなら accept-new が使える。

$ ssh -o StrictHostKeyChecking=accept-new user@server.example.com

accept-new(OpenSSH 7.6 以降)は 未知のホストは自動登録するが、既知ホストの鍵変更は従来どおり拒否するno と違い、なりすまし検知を残したまま初回登録だけ自動化できる。

StrictHostKeyChecking no は鍵変更すら無視するため、本番運用では使わない。自動化で未知ホストを許容したい場合でも accept-new を選ぶ。

known_hosts を事前に登録する(ssh-keyscan)

結論: 自動化や複数台への配布では ssh-keyscan で鍵を取得して known_hosts に投入できる。ただし取得経路自体が信頼できる前提で使う。

対話確認を挟めない CI / Ansible などでは、接続前に鍵を登録しておく。

$ ssh-keyscan -t ed25519 server.example.com >> ~/.ssh/known_hosts

複数ホストをまとめて取得することもできる。

$ ssh-keyscan server1 server2 server3 >> ~/.ssh/known_hosts

ssh-keyscan は「いまネットワーク越しに見える鍵」をそのまま取り込む。取得時点で経路が汚染されていれば偽の鍵を登録してしまう。可能なら取得した鍵のフィンガープリントを正規値と突き合わせる。

それでも直らないときのチェックリスト

結論: エラー直前の行で A/B を見分け、A は ssh-keygen -R、B は安全な登録で対処する。消す前の確認と、緩めすぎない設定を徹底する。

  • [ ] Host key verification failed.直前の行 を読んだか(A: 変更 / B: 初回)
  • [ ] パターン A なら Offending ... known_hosts:NN のファイル・行を確認したか
  • [ ] 鍵変更に 心当たりがあるか(なければフィンガープリント突き合わせ)
  • [ ] ssh-keygen -R ホスト名 で削除したか(ポート付き・IP も忘れず)
  • [ ] 再接続時のフィンガープリントは正規値と一致したか
  • [ ] パターン B で安易に StrictHostKeyChecking no にしていないか(accept-new を検討)
  • [ ] システム全体の /etc/ssh/ssh_known_hosts に古いエントリが残っていないか

次に読む