Где fail2ban перестаёт справляться
fail2ban - хороший инструмент и правильный первый ответ. Вот где именно он упирается, как выжать из него больше и чего он не может ни при какой конфигурации.
Сначала отдадим должное
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 достаточно, остальное — накладные расходы. Внимания заслуживают две строки: общие знания и «работает ли оно ещё» — именно этого никакая настройка на одном изолированном хосте не даёт.
| fail2ban | CrowdSec | SSHGuard | SSH Protector | |
|---|---|---|---|---|
| Что читает | auth.log или journald | логи по конфигурации сбора | auth.log или journald | auth.log или journald |
| Что банит по умолчанию | один адрес | один адрес | один адрес | один адрес на Free, всю подсеть /24 атакующего на платных тарифах |
| Срок бана из коробки | временный (bantime) | временный (duration) | временный | постоянный |
| Чем применяется блокировка | действие firewall на каждый jail | отдельно устанавливаемый bouncer | собственный бэкенд firewall | один сводный набор правил nftables |
| Общие знания между хостами | нет | да, общий блок-лист сообщества | нет | да, между защищёнными аккаунтами |
| Где принимается решение | на хосте | на хосте | на хосте | на хосте |
| Без интернета | продолжает работать | продолжает работать с уже полученными решениями | продолжает работать | продолжает работать; главная — локальная политика |
| «Оно ещё работает?» | делаете сами | метрики и консоль | делаете сами | консоль и оповещение, когда сервер замолчал |
| Лицензия и цена | бесплатно, open source | open source, платные тарифы | бесплатно, open source | 1 сервер бесплатно навсегда, дальше от $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. Мониторьте число банов, а не процесс.
