Выберите продукт

Debian/Ubuntu: как исправить Host key verification failed в Ansible при смене IP

Ошибка Host key verification failed в Ansible на Debian и Ubuntu обычно возникает после переустановки сервера, смены IP или повторного использования адреса. Покажу, как найти конфликт в known_hosts и безопасно принять новый ключ.
Debian/Ubuntu: как исправить Host key verification failed в Ansible при смене IP

Ошибка Host key verification failed в Ansible почти всегда связана не с самим Ansible, а с SSH-проверкой подлинности удалённого узла. На Debian и Ubuntu это особенно часто всплывает после пересоздания сервера, смены IP, перевыпуска инстанса из шаблона или повторного использования адреса, который раньше принадлежал другой машине.

В этот момент Ansible пытается подключиться по SSH, сверяет host key с локальным файлом known_hosts и останавливает выполнение. Для администратора это выглядит как внезапная поломка автоматизации, хотя на деле срабатывает штатная защита OpenSSH.

Отдельно пугает сообщение REMOTE HOST IDENTIFICATION HAS CHANGED. И пугать оно должно: SSH специально блокирует соединение, если ключ узла не совпадает с тем, который уже был сохранён раньше. Это защита от подмены сервера и атак посредника. Но в реальной эксплуатации причина часто вполне штатная — сервер переустановили, а запись в ~/.ssh/known_hosts осталась старой.

Особенно неудобно, когда Ansible работает по IP из inventory, а не по имени хоста. Тогда замена содержимого узла по тому же адресу мгновенно ломает деплой, bootstrap, обновления и любые playbook, которые полагаются на SSH.

Ниже разберём, как быстро найти конфликт, безопасно очистить старую запись, заново принять корректный ключ и в каких случаях можно временно смягчить host key checking, а в каких это плохая идея.

Почему Ansible показывает Host key verification failed

Когда Ansible подключается к удалённому узлу, он обычно использует системный клиент OpenSSH. Тот проверяет host key сервера — публичный ключ SSH-демона. Локально этот ключ хранится в ~/.ssh/known_hosts у пользователя, под которым запускается Ansible.

Если для конкретного хоста в known_hosts уже есть запись, SSH ожидает увидеть тот же самый ключ. Если сервер присылает другой ключ, клиент считает это потенциальной угрозой и завершает подключение.

Host key verification failed.

Или так:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Обычно причина одна из следующих:

  • сервер переустановили, и у него появились новые SSH host keys;
  • IP-адрес переиспользован для другой машины;
  • вы раньше подключались по имени, а теперь по IP, или наоборот;
  • в known_hosts накопились конфликтующие записи;
  • в inventory указан один адрес, а фактически трафик идёт на другой узел через NAT, floating IP или bastion;
  • ключ действительно изменился нештатно, и это надо отдельно проверить.

Если ключ на боевом сервере сменился неожиданно, не удаляйте запись автоматически, пока не убедитесь, что это действительно ваш узел после пересоздания, миграции или reinstall.

Как понять, где именно конфликт: inventory, IP или known_hosts

Первый шаг — выяснить, к какому адресу Ansible реально подключается. Это не всегда очевидно: имя хоста в inventory и фактический адрес соединения могут отличаться. Например, узел называется web-01, а реальный адрес задан через ansible_host.

Проверьте inventory:

ansible-inventory --graph
ansible-inventory --host web-01

В первую очередь смотрите на ansible_host, ansible_user и, если используется нестандартный SSH-порт, на ansible_port. Если в inventory хранится IP, конфликт чаще всего привязан именно к нему.

Следом полезно повторить вход вручную от того же пользователя, под которым запускается Ansible:

ssh admin@203.0.113.10

Обычный SSH часто показывает более понятную ошибку, чем Ansible, включая строку в known_hosts, где лежит конфликтующая запись.

Для подробной диагностики используйте отладку:

ssh -vvv admin@203.0.113.10

Так вы увидите, какой именно файл known_hosts читается, какие типы ключей предлагает сервер и какая запись считается конфликтной.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Если вы часто пересоздаёте тестовые и боевые машины, удобнее держать их на отдельных VDS, где проще контролировать IP, DNS и жизненный цикл узлов. Для динамичной инфраструктуры это заметно снижает число сюрпризов с SSH-ключами.

Где Ansible берёт known_hosts на Debian и Ubuntu

В типичном случае используется файл ~/.ssh/known_hosts текущего пользователя. Если вы запускаете playbook вручную, проблема, скорее всего, будет именно в вашей домашней директории. Если же запуск идёт из CI, systemd unit, cron или через другой аккаунт, конфликтующий файл может лежать уже в другом $HOME.

Проверить это можно так:

whoami
echo $HOME
ls -la ~/.ssh
ls -la ~/.ssh/known_hosts

На Debian и Ubuntu этого обычно достаточно, чтобы быстро понять, тот ли файл вы вообще чините. Очень частая ошибка — удалить запись у своего пользователя, а затем снова получить ту же проблему из CI под сервисным аккаунтом.

Ещё один нюанс: современные версии OpenSSH часто хэшируют имена хостов в known_hosts. Поэтому запись может выглядеть не как IP или имя, а как непонятная строка. Это нормально. В таких случаях лучше пользоваться ssh-keygen, а не редактировать файл вручную.

Диагностика конфликта SSH-ключа в known_hosts на Linux

Как безопасно удалить старую запись из known_hosts

Если вы уверены, что узел действительно был пересоздан или IP теперь принадлежит вашему новому серверу, удалите старую запись штатной утилитой ssh-keygen. Это самый надёжный способ, особенно если хосты в файле захэшированы.

ssh-keygen -R 203.0.113.10
ssh-keygen -R web-01.example.internal

Если SSH работает на нестандартном порту, указывайте адрес в квадратных скобках:

ssh-keygen -R [203.0.113.10]:2222

После удаления полезно убедиться, что старая запись действительно исчезла:

ssh-keygen -F 203.0.113.10

Если команда ничего не вернула, запись удалена. После этого можно либо принять новый ключ вручную при первом входе, либо заранее добавить его в known_hosts.

Как заново добавить корректный host key

Вариант 1. Подтвердить ключ вручную через SSH

Самый простой способ — один раз подключиться вручную:

ssh admin@203.0.113.10

SSH покажет fingerprint нового ключа и попросит подтвердить доверие. Но подтверждать его лучше не вслепую: сначала сверяйте fingerprint с тем, что видите на самом сервере через консоль провайдера, out-of-band доступ или другой доверенный канал.

На сервере отпечатки обычно смотрят так:

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

После подтверждения запись появится в known_hosts, и Ansible снова сможет подключаться.

Вариант 2. Предзаполнить known_hosts через ssh-keyscan

Для массовой подготовки инфраструктуры удобен ssh-keyscan. Он считывает публичный host key без интерактивного входа:

ssh-keyscan -H 203.0.113.10 >> ~/.ssh/known_hosts

Если используется нестандартный порт:

ssh-keyscan -p 2222 -H 203.0.113.10 >> ~/.ssh/known_hosts

Но тут есть важный нюанс: ssh-keyscan сам по себе не доказывает, что перед вами именно нужный сервер. Поэтому в чувствительных средах сначала подтверждайте fingerprint доверенным способом и только потом добавляйте ключ автоматически.

ssh-keyscan отлично подходит для bootstrap и автоматизации, но безопасен только тогда, когда источник ключа дополнительно подтверждён.

Что делать в Ansible: inventory, ansible.cfg и host key checking

По умолчанию Ansible уважает SSH host key checking, и это правильное поведение. Параметр можно отключить, но делать это постоянно для всех окружений обычно не стоит.

Для разовой проверки временно отключить контроль можно так:

ANSIBLE_HOST_KEY_CHECKING=False ansible all -m ping

Либо через ansible.cfg:

[defaults]
host_key_checking = False

Такой подход иногда выручает при первичном bootstrap тестовой среды, но для production его лучше не оставлять. Вы перестаёте замечать подмену узла, а это уже не удобство, а потеря важной защиты.

Гораздо полезнее поддерживать inventory в аккуратном состоянии. Пример:

[web]
web-01 ansible_host=203.0.113.10 ansible_user=admin
web-02 ansible_host=203.0.113.11 ansible_user=admin

Если вы используете IP как ansible_host, то и записи в known_hosts будут завязаны на IP. При частой смене адресов или пересоздании серверов иногда удобнее использовать стабильные DNS-имена. Если вы как раз приводите в порядок адресацию, может пригодиться и регистрация доменов для предсказуемых имён хостов и сервисов.

Компромиссный вариант для контролируемой среды — автоматически принимать только новые хосты:

[all:vars]
ansible_ssh_common_args='-o StrictHostKeyChecking=accept-new'

Режим accept-new лучше полного отключения проверок. Он автоматически принимает ключ только для ранее неизвестных хостов, но по-прежнему блокирует подключение, если уже известный ключ внезапно изменился.

Однако этот режим не решает проблему переиспользованного IP, если в known_hosts уже лежит старая запись. В таком случае её всё равно придётся удалить или обновить.

FastFox VDS
Регистрация доменов от 99 руб.
Каждый проект заслуживает идеального доменного имени, выберите один из сотни, чтобы начать работу!

Автоматизация known_hosts в playbook и вне его

Если вы часто поднимаете новые узлы, лучше управлять известными ключами централизованно. В Ansible для этого есть модуль работы с known_hosts, но тут важно помнить ограничение: чтобы задача выполнилась на удалённой машине, к ней ещё надо сначала подключиться.

Именно поэтому проблему первого входа чаще решают не в основном playbook, а на этапе bootstrap: отдельным скриптом, CI-job, подготовкой control node или облачной инициализацией.

Практически рабочая схема выглядит так:

  • получаете актуальный список адресов из inventory;
  • собираете host keys для новых машин через доверенный канал или через ssh-keyscan с валидацией;
  • обновляете ~/.ssh/known_hosts у пользователя, который запускает Ansible;
  • только после этого запускаете playbook.

Если у вас много меняющихся узлов, дополнительно полезно стандартизировать bootstrap и хранение секретов. На практике это хорошо сочетается с подходами, описанными в материале про безопасное хранение секретов для деплоя.

Если среда полностью динамическая, а IP часто переиспользуются, стоит подумать уже не только о файле known_hosts, а о более формализованной схеме доверия: SSH-сертификатах, стабильных DNS-именах, инвентаре из единого источника истины и чётком процессе пересоздания узлов.

Автоматизация inventory и known_hosts для Ansible

Частые ошибки и ловушки

Ansible запускается не от того пользователя

Это одна из самых частых ситуаций: вручную ssh работает, а Ansible из CI — нет. Причина обычно в том, что CI-процесс использует другой $HOME и другой known_hosts. Всегда проверяйте, кто именно запускает playbook.

Конфликтуют имя и IP

Вы могли раньше подключаться к узлу по DNS-имени, а теперь Ansible ходит по IP. Или наоборот. Тогда в known_hosts могут существовать разные записи для одного и того же сервера.

ssh-keygen -F 203.0.113.10
ssh-keygen -F web-01.example.internal

Используется нестандартный порт

Для SSH на порту, отличном от 22, формат записи в known_hosts отличается. Искать и удалять её тоже надо с указанием порта:

ssh-keygen -F [203.0.113.10]:2222
ssh-keygen -R [203.0.113.10]:2222

DNS указывает не туда

Если в inventory указано имя, а DNS-кэш или запись ещё не обновились, вы можете получать ключ совсем другого сервера. Сначала проверьте, куда реально резолвится имя, и только потом чистите known_hosts.

Практический runbook для Debian и Ubuntu

Если нужен короткий рабочий сценарий без лишней теории, используйте такой порядок:

  1. Проверьте, какой адрес использует Ansible: ansible-inventory --host ИМЯ_ХОСТА.
  2. Попробуйте ручной вход: ssh user@IP.
  3. Убедитесь, что сервер действительно пересоздан или заменён.
  4. Сверьте fingerprint нового host key через консоль сервера или другой доверенный канал.
  5. Удалите старую запись: ssh-keygen -R IP.
  6. Добавьте новый ключ вручную через ssh или заранее через ssh-keyscan.
  7. Повторите проверку: ansible all -m ping.

Минимальный набор команд может выглядеть так:

ansible-inventory --host web-01
ssh-keygen -F 203.0.113.10
ssh-keygen -R 203.0.113.10
ssh admin@203.0.113.10
ansible web-01 -m ping

Когда можно отключить host key checking, а когда нельзя

Для одноразового тестового стенда временное отключение проверок можно считать инженерным компромиссом. Но даже в таком случае обычно лучше использовать StrictHostKeyChecking=accept-new, а не полное отключение.

Если речь идёт о production, административных серверах, bastion-хостах, доступе к базам и CI/CD с секретами, постоянное отключение проверок — плохая идея. Эта ошибка раздражает, но именно она помогает заметить подмену хоста до того, как проблема станет серьёзной.

Полезно относиться к known_hosts как к элементу инфраструктуры наравне с inventory, SSH-ключами доступа и правилами bootstrap. Тогда ошибка перестаёт быть случайной неприятностью и превращается в управляемый процесс.

Если вы параллельно пересобираете инфраструктуру или переносите сервисы между узлами, полезно заранее продумать и миграцию без простоя. В этом контексте может пригодиться материал про перенос сайта без даунтайма.

Итог

Ошибка Host key verification failed в Ansible на Debian и Ubuntu чаще всего появляется после смены IP, пересоздания сервера или конфликта записей в known_hosts. Самый безопасный путь — не отключать защиту, а корректно обновить информацию о host key: понять, к какому адресу подключается Ansible, проверить fingerprint, удалить старую запись через ssh-keygen -R и заново принять или добавить новый ключ.

Если проблема повторяется регулярно, решайте её не вручную, а через нормальную автоматизацию: аккуратный inventory, предзаполнение known_hosts, режим accept-new там, где он уместен, и понятный bootstrap для новых узлов. В такой схеме и SSH остаётся безопасным, и Ansible не ломается при каждом пересоздании хоста.

Поделиться статьей

Вам будет интересно

Debian/Ubuntu: как исправить Device is busy у Docker network, volume и namespace OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как исправить Device is busy у Docker network, volume и namespace

Если Docker на Debian или Ubuntu отвечает Device is busy при удалении сети, тома или namespace, причина обычно в живом процессе, о ...
Debian/Ubuntu: duplicate address detected, DAD failed IPv6 — причины и исправление OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: duplicate address detected, DAD failed IPv6 — причины и исправление

Сообщения duplicate address detected и DAD failed в Debian/Ubuntu означают, что IPv6-адрес не прошёл проверку уникальности в локал ...
Debian/Ubuntu: как исправить swapoff: Device or resource busy при отключении swap OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как исправить swapoff: Device or resource busy при отключении swap

Ошибка swapoff: Device or resource busy в Debian и Ubuntu обычно связана не с «битым» swap, а с нехваткой RAM, zram, автоподключен ...