Где fail2ban перестаёт справляться

fail2ban - хороший инструмент и правильный первый ответ. Вот где именно он упирается, как выжать из него больше и чего он не может ни при какой конфигурации.

10 мин чтения

Сначала отдадим должное

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

Это руководство - о разрыве между «сегодня вечером блокирует реальных атакующих» и «через год всё ещё корректно работает на парке серверов», потому что именно в этом разрыве живут сюрпризы, и он редко где записан.

Ни одно из ограничений ниже не является багом. Это следствия того, чем fail2ban является: демон разбора логов, спроектированный в эпоху одиночных серверов и одиночных атакующих.

Ограничение 1: он банит адреса, а не диапазоны

Это главное. Атакующий трафик идёт от хостинг-провайдеров, где один оператор держит целый блок. Забаните 203.0.113.47 - ботнет в течение часа переедет на .48, и вы поглотите ещё один полный круг попыток, прежде чем забаните и его. На /24 это 256 кругов настроенного вами порога.

Можно приблизить решение своим action, расширяющим каждый бан до /24, но вы теперь сопровождаете арифметику CIDR на shell, а ошибка в ней означает бан того, что было нужно. У инструмента попросту нет понятия диапазона как первоклассной сущности.

Измеримый эффект: на сервере под непрерывной атакой защита с банами по диапазонам видит обрыв графика попыток, а защита по отдельным адресам - плато на уровне скорости ротации.

Ограничение 2: баны истекают, состояние не переживает пересборку

Значение bantime по умолчанию измеряется минутами. Это разумно для shared-хоста, где под бан может попасть реальный пользователь, и неверно для сервера, смотрящего в интернет: тот же ботнет возвращается вечером и начинает заново.

Можно поставить bantime = -1 для постоянных банов, и так и надо - но тут появляется вторая проблема. Список банов живёт в собственной базе fail2ban и в работающем фаерволе; пересоберите машину, восстановите из образа или переедьте на новый хост - и всё, чему сервер научился, исчезло.

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

Ограничение 3: каждый сервер учится в одиночку

Это структурное ограничение, и никакая конфигурация его не чинит. Каждый ваш сервер обнаруживает каждого атакующего самостоятельно, и цена этого обнаружения - выставленный вами порог: пять попыток, десять, сколько бы ни было.

Десять серверов, десять раз тот же атакующий, десять раз поглощённый порог. И каждая из этих попыток - реальный форк sshd, реальная строка в логе и реальный шанс, что именно в этом заходе переиспользованный пароль пройдёт.

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

Ограничение 4: он отказывает молча

Именно это ограничение реально стоит людям серверов, и именно ему уделяют меньше всего внимания.

fail2ban зависит от совпадения строк лога с регулярными выражениями. Обновление дистрибутива меняет формат сообщения sshd; фильтр перестаёт совпадать; jail по-прежнему «работает» и показывает ноль банов, что выглядит ровно как спокойная неделя. Обновления пакетов, бывало, сбрасывали jail.local. Смена бэкенда systemd оставляет журнал непрочитанным. Служба не поднимается после перезагрузки.

В каждом из этих случаев мониторинг, который у вас, скорее всего, есть, - работает ли служба - отвечает «да». Вопрос, который это поймал бы, звучит так: «банил ли он кого-нибудь в последнее время, и похоже ли это число на объём атак, который я вижу в логе?» - и его почти никто не задаёт.

Как выжать из fail2ban больше

Если хотите остаться с ним - законный выбор для небольшого парка, - вот изменения, которые значат больше всего, примерно по порядку:

  • Поставьте bantime = -1 и увеличьте findtime, чтобы медленный атакующий тоже попадался. Сверху - jail recidive, чтобы рецидивисты эскалировались.
  • Добавьте свой action, расширяющий бан до /24, и сначала тщательно проверьте арифметику на собственных диапазонах.
  • Сохраняйте баны между перезагрузками через множество nftables с флагом persistent или восстанавливайте их из базы при старте.
  • Мониторьте число банов, а не состояние службы. Оповещайте, когда оно нулевое, а лог аутентификации - нет.
  • Внесите свои управляющие адреса в ignoreip раньше всего остального и проверьте со второго подключения, что сделали это верно.

Рядом: fail2ban, CrowdSec, SSHGuard и управляемый агент

fail2ban — не единственный инструмент, который читает лог аутентификации и банит найденное, и различия между ними структурные, а не вопрос настройки. Ниже — что каждый делает без единой правки сверх значений по умолчанию.

Читайте это как форму, а не как табло. На одном VPS с единственным администратором колонки fail2ban достаточно, остальное — накладные расходы. Внимания заслуживают две строки: общие знания и «работает ли оно ещё» — именно этого никакая настройка на одном изолированном хосте не даёт.

Что каждый инструмент делает из коробки.
fail2banCrowdSecSSHGuardSSH Protector
Что читаетauth.log или journaldлоги по конфигурации сбораauth.log или journaldauth.log или journald
Что банит по умолчаниюодин адресодин адресодин адресодин адрес на Free, всю подсеть /24 атакующего на платных тарифах
Срок бана из коробкивременный (bantime)временный (duration)временныйпостоянный
Чем применяется блокировкадействие firewall на каждый jailотдельно устанавливаемый bouncerсобственный бэкенд firewallодин сводный набор правил nftables
Общие знания между хостаминетда, общий блок-лист сообществанетда, между защищёнными аккаунтами
Где принимается решениена хостена хостена хостена хосте
Без интернетапродолжает работатьпродолжает работать с уже полученными решениямипродолжает работатьпродолжает работать; главная — локальная политика
«Оно ещё работает?»делаете самиметрики и консольделаете самиконсоль и оповещение, когда сервер замолчал
Лицензия и ценабесплатно, open sourceopen source, платные тарифыбесплатно, open source1 сервер бесплатно навсегда, дальше от $9/мес

Что добавляет управляемый агент

Две вещи, и вторая не строится в одиночку ни при какой конфигурации.

Первая - эксплуатационная база: баны подсетей как первоклассное понятие, баны постоянные и восстанавливаемые при загрузке, реальный порт SSH, определённый по конфигурации sshd, а не предположенный, ваш адрес в белом списке с момента установки и консоль, отвечающая на вопрос «оно вообще работает» - тот самый отказ, который реально кусается.

Вторая - общая репутация. Каждый защищённый сервер пополняет общую базу, поэтому адрес, атаковавший кого-то вчера, уже заблокирован, когда доходит до вас, и вы никогда не поглощаете его первые N попыток. Парсер логов на одном хосте может учиться только на атаках по этому хосту.

SSH Protector принимает решения локально на агенте, так что защита не зависит от доступности облака: если связь пропала, продолжает работать локальная политика. Один сервер бесплатен навсегда - этого достаточно, чтобы неделю погонять его рядом с fail2ban и сравнить, кто что поймал.

FAQ

Стоит ли ещё использовать fail2ban?
Да, как базовый уровень. Он бесплатен, есть в любом репозитории, и на сервере, за которым больше никто не следит, он заблокирует реальных атакующих в день установки. Честные оговорки: бан отдельных адресов против ботнетов, перебирающих диапазоны; баны, истекающие по умолчанию; отсутствие общих знаний между хостами; молчаливый отказ.
Как сделать баны fail2ban постоянными?
Поставьте bantime = -1 в нужном jail. Учтите, что список банов тогда живёт только в базе fail2ban и в работающем фаерволе, поэтому пересборка или восстановление из образа теряет всё, чему сервер научился, а множество растёт без чьей-либо ревизии. Сохраняйте множество фаервола между перезагрузками, иначе баны теряются при каждом рестарте.
Может ли fail2ban забанить целую подсеть?
Штатно - нет. Он банит адрес, который встретился в строке лога. Можно написать свой action, расширяющий каждый бан до содержащей его /24, но тогда вы сами сопровождаете арифметику CIDR, а ошибка в ней блокирует нужный вам диапазон. Понятия диапазона как сущности в инструменте нет.
Как проверить, что fail2ban действительно работает?
Запустите fail2ban-client status sshd и смотрите на число забаненных, а не только на то, активна ли служба. Работающий jail, который никого не забанил, при том что в логе аутентификации есть отказы, означает, что фильтр перестал совпадать - обычно после обновления дистрибутива, изменившего формат сообщения sshd. Мониторьте число банов, а не процесс.

Погоняйте неделю рядом

Баны подсетей, постоянные по умолчанию, общая репутация и наглядный ответ, живо ли оно. Один сервер бесплатно навсегда, без карты.