問題の概要
10台の新しいサーバーをプロビジョニングし、コードをデプロイする準備が整いました。Ansible Playbookを実行しますが、成功を示す緑色のバーが表示される代わりに、画面が赤いテキストで埋め尽くされます。Ansibleが処理を開始する前に、接続が拒否されてしまいました。
これはネットワークの故障やサーバーのダウンではありません。SSHの基本的なセキュリティ機能によるものです。初めてマシンに接続するとき、SSHはマシンの固有のフィンガープリントをローカルの ~/.ssh/known_hosts ファイルと照合します。ホストが全く新しい場合や、OSを再インストールしてフィンガープリントが変更された場合、SSHは停止し、「Are you sure you want to continue connecting?(接続を続行しますか?)」と問いかけます。
Ansibleは自動化のために設計されており、対話を前提としていません。非対話形式で実行されるため、ユーザーの代わりに「yes」と入力することはできません。そのため、単に処理を断念して致命的なエラー(fatal error)をスローします。
実際のエラーメッセージ
fatal: [192.168.1.100]: UNREACHABLE! => {
"changed": false,
"msg": "Host key verification failed.",
"unreachable": true
}
発生理由
通常、このエラーは以下の3つのシナリオのいずれかで発生します。
- **新規セットアップ:** 新しいVPSやローカルのVMに初めて接続する場合。
- **再構築:** サーバー(AWS EC2インスタンスなど)を初期化し、OSを再インストールした場合。IPアドレスは同じでも、SSHキーが変更されています。
- **IPの再利用:** 動的なクラウド環境では、以前 `known_hosts` に登録されていた別のサーバーが使用していたIPアドレスが割り当てられることがあります。
ステップバイステップの解決策
方法 1: ホストキーチェックの無効化(迅速な方法)
セキュアなラボ環境やプライベートな内部ネットワークで作業している場合は、フィンガープリントのチェックを完全にスキップしたい場合があります。これは、ネットワークレベルでセキュリティが確保されている一時的なCI/CDランナーなどでよく使われる解決策です。
これを行うには、プロジェクトフォルダ内の ansible.cfg ファイルを作成または編集します。
[defaults]
host_key_checking = False
ファイルを編集せずに一度だけ解決したい場合は、コマンドを実行する前に環境変数を設定します。
export ANSIBLE_HOST_KEY_CHECKING=False
ansible-playbook site.yml
警告: この設定は中間者攻撃(MITM)に対して脆弱になります。ネットワークを完全に信頼できる場合にのみ使用してください。
方法 2: ssh-keyscan の使用(セキュアな方法)
本番環境では、検証を有効にしたまま、Ansibleに必要なキーを提供します。サーバーを「事前スキャン」して、フィンガープリントをローカルの信頼済みストアに保存できます。
# 単一のサーバーをスキャン
ssh-keyscan -H 192.168.1.100 >> ~/.ssh/known_hosts
# ファイル内のIPリスト全体をスキャン
ssh-keyscan -H -f inventory_ips.txt >> ~/.ssh/known_hosts
ここで -H フラグが役立ちます。これはホスト名をハッシュ化するため、万が一 known_hosts ファイルが閲覧されても、インフラ全体の構成を簡単には特定できなくなります。
方法 3: 古いキーの削除
「Host key mismatch」エラーが表示される場合、コンピュータがそのIPアドレスに対して古いキーを記憶していることを意味します。新しいキーを保存する前に、古いエントリを削除する必要があります。ssh-keygen を使用して特定のIPアドレスを対象にします。
ssh-keygen -f "~/.ssh/known_hosts" -R "192.168.1.100"
古いキーが削除されたら、方法2の ssh-keyscan コマンドを使用して新しいキーを取得します。
方法 4: インベントリでの個別オーバーライド
特定のサーバーグループに対してのみチェックを無効にしたい場合もあります。その場合は、インベントリファイル(例: hosts.ini)内で直接SSH引数を渡すことができます。
[dev_servers]
192.168.1.100 ansible_ssh_extra_args='-o StrictHostKeyChecking=no'
確認
正しく動作するか確認しましょう。ホストに対して Ansible の ping モジュールを実行します。pong が返ってくれば、ハンドシェイクは成功しており、自動化の準備は完了です。
ansible all -m ping -i inventory.ini
期待される出力:
192.168.1.100 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
本番環境向けのプロのヒント
- **設定のスコープを限定する:** グローバルの `/etc/ansible/ansible.cfg` で `host_key_checking = False` を設定するのは避けましょう。セキュリティリスクを抑えるため、プロジェクトごとにローカルで設定するようにしてください。
- **パイプラインの自動化:** GitLab CI や GitHub Actions では、`before_script` に `ssh-keyscan` を追加します。これにより、手動介入なしでパイプラインが新しいインフラに接続できるようになります。
- **踏み台サーバー(Bastion Hosts):** ジャンプホストを使用している場合、キーのチェックはローカルのコントロールノードで行われることに注意してください。`ProxyCommand` を使用する場合は、ゲートウェイと最終目的地の両方のキーを管理する必要があるかもしれません。

