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

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

8 мин чтения

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

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 раньше всего остального и проверьте со второго подключения, что сделали это верно.

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

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

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

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

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

FAQ

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

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

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