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