Есть инструменты, которые переживают целые поколения технологий. Они появляются в эпоху физических серверов, доживают до контейнеров, переживают облака и внезапно обнаруживают себя в мире Kubernetes и сервисных сетей. Fail2Ban относится именно к таким инструментам. Если человек хотя бы несколько лет занимался эксплуатацией Linux-систем, вероятность того, что он никогда не устанавливал Fail2Ban, примерно такая же, как вероятность встретить администратора, который ни разу не писал chmod 777 в состоянии лёгкого отчаяния. Этот инструмент был буквально повсюду. Новый VPS? Ставим Fail2Ban. Публичный SSH? Ставим Fail2Ban. Nginx, Postfix, Dovecot, WordPress - для всего существовали готовые фильтры. И самое интересное заключается в том, что всё это действительно работало. Fail2Ban не был временным костылём или очередной модной игрушкой сообщества. Это был честный, надёжный и удивительно практичный инструмент, который спас огромное количество серверов от вполне реальных проблем.

Важно сразу обозначить одну мысль, потому что вокруг подобных тем очень быстро начинаются религиозные войны. Эта статья не про то, что Fail2Ban стал плохим. Он не стал плохим. Более того, в определённых сценариях он остаётся отличным выбором и сегодня. Проблема заключается совсем в другом. Мир вокруг него изменился настолько сильно, что сами предпосылки, на которых строилась его работа, постепенно перестали соответствовать реальности. Это немного похоже на ситуацию с картами автомобильных дорог. Если у вас есть бумажный атлас дорог 2008 года, он не становится бесполезным только потому, что наступил 2026 год. Но если половину трасс перестроили, появились новые развязки, а города выросли в несколько раз, пользоваться им становится всё сложнее. С безопасностью произошло примерно то же самое.

В начале 2010-х годов типичная инфраструктура была удивительно простой. Подавляющее большинство небольших проектов размещалось на одном или нескольких виртуальных серверах. На одном сервере мог работать nginx, PHP и база данных. Максимум - ещё отдельный сервер для резервных копий или почты. Docker только начинал появляться, Kubernetes существовал где-то в презентациях инженеров Google, а словосочетание "сервисная сеть" звучало как название нового маршрута городского транспорта. Логи хранились локально, IP-адреса пользователей были настоящими, а большинство атак выглядело прямолинейно и даже несколько примитивно.

Типичная архитектура тех лет выглядела примерно так:

Internet
    ↓
Ubuntu VPS
    ↓
Nginx
    ↓
PHP-FPM
    ↓
MySQL

Все журналы находились непосредственно на сервере:

ls -lah /var/log

auth.log
nginx/
mysql/
syslog
kern.log

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

Jun 17 10:21:01 server sshd[10452]: Failed password for root from 185.22.11.4 port 44215 ssh2
Jun 17 10:21:04 server sshd[10457]: Failed password for root from 185.22.11.4 port 44217 ssh2
Jun 17 10:21:06 server sshd[10461]: Failed password for root from 185.22.11.4 port 44219 ssh2
Jun 17 10:21:09 server sshd[10464]: Failed password for root from 185.22.11.4 port 44223 ssh2
Jun 17 10:21:12 server sshd[10468]: Failed password for root from 185.22.11.4 port 44227 ssh2

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

Лог
 ↓
Регулярное выражение
 ↓
Подсчёт совпадений
 ↓
Превышение порога
 ↓
Блокировка IP

Например, стандартная конфигурация SSH-защиты могла выглядеть следующим образом:

# /etc/fail2ban/jail.local

[sshd]
enabled = true
port = ssh
backend = systemd
maxretry = 5
findtime = 10m
bantime = 1h

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

iptables -I INPUT -s 185.22.11.4 -j DROP

или в более современных системах:

nft add rule inet filter input ip saddr 185.22.11.4 drop

Для своего времени это было практически идеальное решение. Минимум ресурсов, отсутствие сложных зависимостей, предсказуемое поведение и очень понятная модель принятия решений. Администратор видел логику системы и мог объяснить каждое её действие. Не было магии искусственного интеллекта, загадочных коэффициентов доверия и многотомных руководств по эксплуатации. Всё работало по принципу: "увидел нарушение - наказал нарушителя".

Но затем интернет начал стремительно меняться. Причём изменения происходили не постепенно, а лавинообразно. Сначала появились облачные платформы и массовая виртуализация. Затем пришли контейнеры. Потом появились оркестраторы контейнеров. Затем практически обязательным элементом публичной инфраструктуры стали CDN и обратные прокси. После этого началась эпоха API, микросервисов и Kubernetes. И где-то на фоне всех этих преобразований изменились сами атакующие.

Сегодня достаточно поднять абсолютно новый VPS, открыть наружу SSH и HTTP, чтобы через несколько минут почувствовать всю любовь современного интернета. Особенно забавно наблюдать за логами проектов, которые написаны на Go и никогда в жизни не видели PHP.

Например:

GET /wp-login.php HTTP/1.1
GET /wp-admin HTTP/1.1
GET /.env HTTP/1.1
GET /.git/config HTTP/1.1
GET /phpmyadmin HTTP/1.1
GET /manager/html HTTP/1.1
GET /actuator/health HTTP/1.1
GET /vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1
GET /boaform/admin/formLogin HTTP/1.1

При этом сервер может быть написан на Golang, собран в статический бинарный файл и запускаться внутри контейнера размером меньше пятидесяти мегабайт. Но боты продолжают искать WordPress, Laravel, Tomcat, Apache Struts и десятки других систем. Им совершенно безразлично, что именно вы используете. Их философия предельно проста:

"А вдруг?"

Именно здесь начинается первая серьёзная проблема старой модели защиты. В эпоху Fail2Ban атака выглядела следующим образом:

1 IP
 ↓
1000 попыток входа

Современная распределённая атака чаще выглядит иначе:

10000 IP
 ↓
по 1-2 попытки с каждого адреса

Представим ситуацию, когда ботнет использует десять тысяч узлов:

192.0.2.11      → 1 попытка
198.51.100.14  → 1 попытка
203.0.113.71   → 1 попытка
192.0.2.54     → 1 попытка
198.51.100.81  → 1 попытка
...

Каждый отдельный адрес ведёт себя почти безупречно и никогда не достигает установленного порога:

maxretry = 5

С точки зрения Fail2Ban всё выглядит нормально. Нарушителей нет. Банить некого. Однако если посмотреть на ситуацию целиком, становится очевидно, что инфраструктуру уже активно исследуют. И проблема заключается не в том, что Fail2Ban ошибается. Он честно выполняет именно ту работу, для которой был создан. Просто сама работа изменилась.

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

Internet
    ↓
Cloudflare
    ↓
API Gateway
    ↓
Ingress Controller
    ↓
Kubernetes
    ↓
Service Mesh
    ↓
Microservices
    ↓
Sidecars
    ↓
Observability Stack

И где-то внутри всей этой конструкции по-прежнему находится инструмент, который пытается анализировать локальный журнал событий и принимать решения на основе нескольких регулярных выражений. Именно в этот момент становится понятно, что вопрос уже давно перестал звучать как "хороший ли Fail2Ban инструмент". Настоящий вопрос выглядит иначе: достаточно ли локального анализа логов для защиты современной распределённой инфраструктуры? И именно попыткой ответить на этот вопрос несколько лет назад стал CrowdSec.

CrowdSec появился не как попытка "убить Fail2Ban" или объявить все старые подходы устаревшими. Если посмотреть на философию проекта, становится понятно, что его создатели задавали себе совсем другой вопрос. Что делать, если атакующие давно перестали действовать в одиночку? Что делать, если подбор паролей распределён между тысячами узлов, сканирование выполняется через арендованные облачные ресурсы, а вчерашний ботнет сегодня использует домашние прокси и заражённые устройства "умного дома"? Можно бесконечно улучшать локальные фильтры и усложнять регулярные выражения, но это не решает главной проблемы: каждый отдельный сервер видит лишь маленький фрагмент общей картины. В современном интернете отдельная машина зачастую оказывается слепа, потому что наблюдает только за собственной дверью, тогда как атака происходит сразу на уровне всего квартала.

Именно поэтому CrowdSec построен вокруг идеи коллективной защиты. Если сильно упростить его концепцию, получится примерно следующее. Допустим, некий IP-адрес за последние несколько часов успел подобрать пароли к SSH на серверах в Германии, проверить наличие WordPress во Франции, поискать уязвимый Jenkins в Канаде и попытаться прощупать открытый Kubernetes Ingress в Японии. Каждый отдельный сервер увидел бы лишь один небольшой эпизод этой активности. Однако если объединить информацию от тысяч участников, картина становится совершенно иной. Тогда уже видно, что перед нами не случайный пользователь, а систематическая вредоносная активность.

В этом заключается фундаментальное отличие CrowdSec от классического Fail2Ban. Последний мыслит примерно так:

Я увидел нарушение.
Я заблокировал IP.
На этом моя работа закончена.

CrowdSec рассуждает иначе:

Я увидел подозрительное поведение.
Я сопоставил его со сценариями обнаружения.
Я могу использовать знания сообщества.
Я принимаю решение с учётом более широкого контекста.

При этом важно не впадать в другую крайность и не представлять CrowdSec как очередную "революционную платформу нового поколения на искусственном интеллекте". Стоит произнести словосочетание "коллективная аналитика угроз", как у многих менеджеров загораются глаза и в воображении возникает огромный SIEM-комплекс стоимостью как квартира в центре Амстердама. С десятком кластеров Elasticsearch, армией консультантов и обязательным трёхмесячным проектом внедрения. На практике всё гораздо прозаичнее и, что особенно приятно для инженеров эксплуатации, гораздо ближе к реальной жизни.

По сути CrowdSec всё так же занимается тремя основными задачами:

Сбор событий
↓
Обнаружение подозрительного поведения
↓
Применение мер реагирования

Разница заключается в том, что каждая из этих стадий стала заметно умнее.

Архитектура CrowdSec выглядит следующим образом:

Logs
 ↓
Acquisition
 ↓
Parsers
 ↓
Scenarios
 ↓
Local API
 ↓
Bouncers

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

Первый компонент называется Acquisition. Если говорить человеческим языком, это механизм получения данных. Именно он отвечает за вопрос: откуда вообще брать события для анализа? В эпоху Fail2Ban ответ был очевиден:

/var/log/auth.log
/var/log/nginx/access.log

Современная инфраструктура требует гораздо большей гибкости.

Например, CrowdSec умеет работать с обычными файлами журналов:

# /etc/crowdsec/acquis.yaml

filenames:
  - /var/log/nginx/access.log
  - /var/log/nginx/error.log

labels:
  type: nginx

С системным журналом journald:

source: journalctl
journalctl_filter:
  - "_SYSTEMD_UNIT=sshd.service"

labels:
  type: syslog

С контейнерами Docker:

source: docker
container_name:
  - nginx
  - traefik

labels:
  type: nginx

А также с Loki, Syslog и другими источниками данных. Что особенно важно, это не выглядит как очередной костыль из серии "технически можно заставить работать". Такие сценарии поддерживаются штатно и считаются нормальным способом эксплуатации.

После получения данных в работу вступают парсеры. Их задача заключается в приведении событий к единому виду. Возьмём, например, журналы nginx. Они могут выглядеть совершенно по-разному в зависимости от формата логирования.

Классический формат:

192.0.2.15 - - [17/Jun/2026:13:15:01 +0000] "GET /wp-login.php HTTP/1.1" 404 153

JSON-формат:

{
  "remote_addr":"192.0.2.15",
  "request":"GET /wp-login.php HTTP/1.1",
  "status":404
}

Ingress-nginx в Kubernetes:

10.244.0.17 - - [17/Jun/2026:13:15:01 +0000] "GET /wp-login.php HTTP/1.1" 404 153 "-" "curl/8.7.1"

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

Следующий уровень - Scenarios. Именно здесь начинается настоящая магия инженерии. Сценарии представляют собой набор правил, описывающих вредоносное поведение. Они гораздо богаче классического подхода "совпало регулярное выражение - баним". Например, CrowdSec умеет определять перебор SSH, сканирование веб-приложений, попытки эксплуатации известных уязвимостей и различные виды агрессивного поведения.

Посмотреть установленные сценарии можно так:

sudo cscli scenarios list

Пример вывода:

crowdsecurity/ssh-bf
crowdsecurity/http-probing
crowdsecurity/http-cve
crowdsecurity/nginx-bf
crowdsecurity/apache2-bf

Особенно полезным инструментом оказывается команда cscli explain. Если бы мне пришлось назвать одну функцию CrowdSec, ради которой его стоит попробовать хотя бы в тестовом окружении, это была бы именно она. Любой администратор, который когда-либо отлаживал собственные фильтры Fail2Ban, знает боль от сообщения:

Regex did not match.

И всё. Никаких объяснений. Никакой дополнительной информации. Просто удачи.

CrowdSec подходит к диагностике совершенно иначе:

sudo cscli explain \
    --file /var/log/nginx/access.log \
    --type nginx

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

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

Теория, какой бы красивой она ни была, заканчивается ровно в тот момент, когда инженер открывает терминал и пытается всё это заставить работать в продакшене. И вот здесь начинается самое интересное. Потому что до этого момента CrowdSec выглядит как очень разумная концепция коллективной защиты, но настоящую ценность он начинает показывать только после установки. Именно тогда становится понятно, что это уже не "ещё один Fail2Ban", а полноценная система обнаружения и реагирования, которая при этом остаётся достаточно лёгкой для эксплуатации на обычных серверах.

Начнём с базового сценария - установки на Ubuntu или Debian. Документация CrowdSec предлагает использовать официальный установочный сценарий. И да, сейчас у части администраторов старой школы снова начнёт дёргаться глаз. Потому что выглядит это следующим образом:

curl -s https://install.crowdsec.net | sudo bash

Есть особая категория инженеров, которые готовы терпеть отказоустойчивость на одном дата-центре, но не готовы выполнить curl | bash. И их можно понять. Поэтому давайте посмотрим, что именно делает этот сценарий. Фактически он добавляет официальный репозиторий CrowdSec в систему управления пакетами. При желании этот шаг можно выполнить вручную, проверив все ключи и содержимое сценария перед запуском. После этого установка уже ничем не отличается от привычной работы с пакетным менеджером:

sudo apt update

sudo apt install -y \
    crowdsec \
    crowdsec-firewall-bouncer-nftables

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

sudo systemctl enable crowdsec
sudo systemctl start crowdsec

sudo systemctl status crowdsec

Нормальный результат выглядит примерно так:

● crowdsec.service - Crowdsec agent
     Loaded: loaded
     Active: active (running)
     Main PID: 1832

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

sudo journalctl -u crowdsec -f

Он позволяет в режиме реального времени наблюдать за тем, что происходит внутри агента.

Однако просто установить CrowdSec недостаточно. Ему ещё необходимо объяснить, где искать журналы событий. И именно здесь многие впервые сталкиваются с компонентом Acquisition. Если на сервере работает обычный nginx, настройка выглядит достаточно просто:

# /etc/crowdsec/acquis.yaml

filenames:
  - /var/log/nginx/access.log
  - /var/log/nginx/error.log

labels:
  type: nginx

Если сервер занимается обработкой SSH-подключений через journald:

source: journalctl

journalctl_filter:
  - "_SYSTEMD_UNIT=ssh.service"

labels:
  type: syslog

На первый взгляд это кажется очевидным, но именно на этом этапе возникает одна из самых распространённых ошибок внедрения CrowdSec. Администратор устанавливает пакет, запускает сервис, а затем удивляется, почему ничего не обнаруживается. Ответ обычно очень прост: система не видит событий. Либо указан неправильный путь к журналам, либо логи уже ротированы, либо nginx пишет в stdout контейнера, а CrowdSec продолжает искать старый добрый /var/log/nginx/access.log.

Проверить, получает ли агент события, можно при помощи команды:

sudo cscli metrics

Например:

Acquisition Metrics:

╭──────────────────────────────╮
│ Current Metrics              │
├──────────────────────────────┤
│ Lines read       : 241752    │
│ Lines parsed     : 238109    │
│ Lines unparsed   : 3643      │
│ Lines poured     : 238109    │
╰──────────────────────────────╯

Именно здесь начинается настоящее знакомство с окружающим миром. Потому что если сервер хоть сколько-нибудь публичный, цифры начинают расти с пугающей скоростью. Очень быстро выясняется, что ваш API интересует огромное количество незваных гостей. Кто-то проверяет наличие WordPress. Кто-то ищет открытый Redis. Кто-то надеется обнаружить старую версию Jenkins. А кто-то с удивительным упорством продолжает искать phpMyAdmin на сервисе, который написан на Go и никогда не видел ни одной строчки PHP-кода.

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

sudo cscli collections install crowdsecurity/nginx

Для защиты SSH:

sudo cscli collections install crowdsecurity/sshd

Для обнаружения распространённых попыток эксплуатации веб-приложений:

sudo cscli collections install crowdsecurity/http-cve

Посмотреть установленные коллекции можно так:

sudo cscli collections list

Например:

crowdsecurity/nginx
crowdsecurity/sshd
crowdsecurity/http-cve
crowdsecurity/linux

После этого наступает момент истины. CrowdSec начинает анализировать реальные события и принимать решения. Но пока что эти решения существуют только внутри системы. Они ещё никак не влияют на злоумышленников. Если провести аналогию с физической безопасностью, это выглядит так, словно охрана обнаружила нарушителя, записала его приметы в блокнот и продолжила спокойно пить кофе.

Чтобы решения начали применяться, необходимы Bouncer'ы - компоненты реагирования. Именно они превращают аналитические выводы в конкретные действия. В случае Linux-сервера самым популярным вариантом является Firewall Bouncer.

Современный вариант установки выглядит следующим образом:

sudo apt install -y crowdsec-firewall-bouncer-nftables

И здесь стоит сделать небольшое отступление. Ещё несколько лет назад большинство примеров строилось вокруг iptables. Однако Linux постепенно переходит на nftables, который обеспечивает более современную архитектуру фильтрации пакетов и лучшую производительность. Поэтому если нет объективных причин придерживаться старого стека, разумнее использовать именно его.

После запуска Bouncer можно убедиться, что он зарегистрировался в системе:

sudo cscli bouncers list

Вывод может выглядеть следующим образом:

────────────────────────────────────────────
 Name          IP Address     Valid
────────────────────────────────────────────
 firewall-bouncer             ✔
────────────────────────────────────────────

А список активных решений проверяется командой:

sudo cscli decisions list

Иногда результаты оказываются весьма поучительными:

IP Address      Scenario
203.0.113.54    crowdsecurity/http-probing
198.51.100.77   crowdsecurity/nginx-bf
192.0.2.31      crowdsecurity/ssh-bf

Именно в этот момент многие администраторы испытывают лёгкий культурный шок. Оказывается, пока вы спокойно разворачивали новый сервис и настраивали мониторинг, половина интернета уже успела проверить наличие WordPress, вторая половина поискала Jenkins, а третья пыталась выяснить, не забыли ли вы случайно открыть Redis без авторизации. Причём происходило всё это одновременно, автоматически и без какого-либо личного отношения к вам. Просто в современном интернете публичный IP-адрес воспринимается ботами примерно так же, как шведский стол воспринимается голодными туристами.

До этого момента мы рассматривали CrowdSec на примере относительно классического сценария: один сервер, локальные журналы, локальная блокировка. Именно здесь у многих читателей может возникнуть вполне закономерный вопрос: если всё заканчивается анализом логов и записью правил в межсетевой экран, действительно ли CrowdSec настолько отличается от Fail2Ban? Ответ одновременно и простой, и сложный. На небольшом VPS разница действительно может оказаться не столь драматичной. Если у вас один сервер с SSH, Postfix и nginx, старый добрый Fail2Ban по-прежнему способен выполнять свою работу великолепно. Более того, он будет потреблять меньше ресурсов и потребует меньше времени на сопровождение. Настоящее преимущество CrowdSec начинает проявляться тогда, когда инфраструктура перестаёт помещаться в голове одного администратора и превращается в распределённую систему.

Первый такой сценарий - использование Cloudflare или любого другого обратного прокси. Практически любая публичная инфраструктура сегодня скрывается за CDN. Это позволяет экономить трафик, защищаться от DDoS-атак и ускорять доставку контента. Однако у этой схемы есть неприятный побочный эффект. С точки зрения приложения все запросы начинают приходить от прокси-сервера, а не от реальных пользователей. Если ничего дополнительно не настраивать, nginx будет видеть примерно такую картину:

127.0.0.1 - - [17/Jun/2026:15:41:03 +0000] "GET /wp-login.php HTTP/1.1" 404
127.0.0.1 - - [17/Jun/2026:15:41:04 +0000] "GET /.env HTTP/1.1" 404
127.0.0.1 - - [17/Jun/2026:15:41:05 +0000] "GET /phpmyadmin HTTP/1.1" 404

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

Исправление ситуации требует дополнительной настройки nginx:

http {

    real_ip_header CF-Connecting-IP;

    set_real_ip_from 173.245.48.0/20;
    set_real_ip_from 103.21.244.0/22;
    set_real_ip_from 103.22.200.0/22;
    set_real_ip_from 103.31.4.0/22;
    set_real_ip_from 141.101.64.0/18;
    set_real_ip_from 108.162.192.0/18;

    real_ip_recursive on;
}

После этого журналы начинают содержать реальные адреса клиентов:

198.51.100.25 - - [17/Jun/2026:15:41:03 +0000] "GET /wp-login.php HTTP/1.1" 404
203.0.113.77 - - [17/Jun/2026:15:41:04 +0000] "GET /.env HTTP/1.1" 404
192.0.2.54 - - [17/Jun/2026:15:41:05 +0000] "GET /phpmyadmin HTTP/1.1" 404

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

Ещё интереснее становится, когда дело доходит до Kubernetes. Вообще попытка использовать классический Fail2Ban внутри кластера заслуживает отдельной главы в учебниках по инженерной психологии. Потому что очень быстро возникает фундаментальный вопрос: а где именно он должен работать? В Pod с приложением? В Ingress Controller? На узлах кластера? И как ему вообще управлять iptables, если контейнеры являются эфемерными сущностями?

Представим типичный современный кластер:

Internet
    ↓
Cloudflare
    ↓
Ingress NGINX
    ↓
Service
    ↓
Deployment
    ↓
Pod

Теперь попробуем встроить в эту схему Fail2Ban. Первой идеей обычно становится запуск контейнера рядом с приложением:

Pod
├── application
└── fail2ban

Через некоторое время выясняется, что журналы находятся в другом месте, IP-адреса приходят от Ingress, а любые изменения iptables внутри Pod практически не влияют на остальную инфраструктуру. В этот момент Kubernetes обычно задаёт немой вопрос:

"Ты вообще кто и почему решил, что можешь менять состояние узла?"

CrowdSec подходит к этой задаче иначе. Вместо попытки встроиться в отдельный контейнер он использует архитектуру, которая лучше соответствует облачной модели эксплуатации. Например, агент можно развернуть как DaemonSet:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: crowdsec-agent
  namespace: crowdsec

В результате экземпляр CrowdSec появляется на каждом узле кластера и получает доступ к необходимым данным.

На практике большинство инженеров используют официальный Helm-чарт:

helm repo add crowdsec https://crowdsecurity.github.io/helm-charts

helm repo update

После чего создают собственный файл параметров:

container_runtime: containerd

agent:
  acquisition:
    - namespace: ingress-nginx
      podName: ingress-nginx-controller-*
      program: nginx

  collections:
    - crowdsecurity/nginx
    - crowdsecurity/http-cve
    - crowdsecurity/base-http-scenarios

lapi:
  dashboard:
    enabled: false

Установка выглядит вполне привычно:

helm upgrade --install crowdsec \
    crowdsec/crowdsec \
    --namespace crowdsec \
    --create-namespace \
    -f values.yaml

После этого CrowdSec начинает анализировать журналы Ingress Controller так же, как раньше анализировал access.log обычного nginx. Только теперь он делает это в распределённой среде, понимая специфику Kubernetes и не пытаясь притворяться, будто весь мир до сих пор состоит из одного виртуального сервера.

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

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

До этого момента CrowdSec выглядит практически идеальным решением. Он понимает современные журналы событий, умеет работать в Kubernetes, интегрируется с различными источниками данных и позволяет использовать коллективную аналитику угроз. Именно здесь обычно появляются два лагеря читателей. Первый начинает мысленно удалять Fail2Ban со всех серверов компании. Второй недоверчиво смотрит на новую систему и задаёт вполне разумный вопрос: "А где подвох?" И, как это обычно бывает в инженерии, подвох действительно существует. Потому что не бывает универсальных решений, одинаково хорошо подходящих для всех сценариев эксплуатации.

Первое, что необходимо понимать перед внедрением CrowdSec, - он заметно сложнее Fail2Ban. Если последний можно описать одной фразой "прочитал журнал, нашёл совпадение, заблокировал адрес", то CrowdSec представляет собой набор взаимосвязанных компонентов. Acquisition отвечает за получение событий, парсеры преобразуют данные в единый формат, сценарии определяют вредоносное поведение, Local API принимает решения, а Bouncer'ы реализуют реакцию на обнаруженные угрозы. Каждая из этих частей приносит дополнительную гибкость, но одновременно увеличивает сложность сопровождения. Это не недостаток проекта как такового, а неизбежная цена за расширение функциональности. В определённый момент инфраструктура становится настолько сложной, что простых решений уже недостаточно.

Очень показательной оказывается ситуация с диагностикой. Например, администратор замечает, что CrowdSec не блокирует очевидную атаку на nginx. В мире Fail2Ban процесс расследования выглядел бы примерно так: открыть журнал, проверить регулярное выражение, немного поругаться на синтаксис и попытаться понять, почему совпадение не произошло. В CrowdSec приходится анализировать всю цепочку обработки событий.

Первым делом проверяем, читает ли система журналы:

sudo cscli metrics

Затем убеждаемся, что коллекции действительно установлены:

sudo cscli collections list

Проверяем наличие сценариев:

sudo cscli scenarios list

После этого исследуем процесс разбора событий:

sudo cscli explain \
    --file /var/log/nginx/access.log \
    --type nginx

Типичный вывод может выглядеть следующим образом:

line: 198.51.100.77 - - [17/Jun/2026:18:32:41 +0000] "GET /.env HTTP/1.1" 404

        PARSERS:
            crowdsecurity/nginx-logs

        SCENARIOS:
            crowdsecurity/http-probing

        DECISION:
            ban

Для начинающего инженера подобный объём информации может показаться избыточным. Однако после нескольких серьёзных расследований начинаешь понимать, насколько ценным является прозрачный конвейер принятия решений. Вместо загадочного "что-то не работает" появляется возможность последовательно проверить каждый этап обработки.

Отдельного разговора заслуживает работа с исключениями. Любая система защиты рано или поздно начинает сталкиваться с ложными срабатываниями. Например, внутренние системы мониторинга могут выполнять частые проверки сервисов. Нагрузочное тестирование способно напоминать атаку перебором. Некоторые корпоративные прокси объединяют огромное количество пользователей за одним адресом. В результате возникает необходимость исключить определённые IP-адреса из анализа.

В CrowdSec это реализуется достаточно удобно.

Например, можно вручную добавить адрес в список исключений:

sudo cscli decisions add \
    --ip 10.0.0.15 \
    --duration 720h \
    --type captcha

А для доверенных диапазонов использовать специальную конфигурацию:

# /etc/crowdsec/parsers/s02-enrich/whitelists.yaml

name: corp_whitelist
description: Corporate addresses

whitelist:
  reason: "internal network"

  ip:
    - "10.0.0.0/8"
    - "172.16.0.0/12"
    - "192.168.0.0/16"

После внесения изменений не стоит забывать о перезапуске агента:

sudo systemctl restart crowdsec

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

Ещё одна крайне полезная возможность CrowdSec - интеграция с внешними системами реагирования. Локальная блокировка через nftables хороша для отдельных серверов, однако в высоконагруженных системах гораздо эффективнее отсеивать нежелательный трафик как можно раньше. И здесь особенно интересно выглядит интеграция с Cloudflare.

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

Для этого устанавливается соответствующий Bouncer:

sudo apt install crowdsec-cloudflare-bouncer

Создаётся API-токен Cloudflare с правами управления правилами фильтрации, после чего выполняется настройка:

cloudflare_config:
  accounts:
    - name: production
      api_token: "CF_API_TOKEN"
      zone: "example.com"

После запуска Bouncer решения CrowdSec начинают распространяться на уровень Cloudflare. Практический эффект оказывается весьма ощутимым. Снижается нагрузка на ingress-контроллеры, уменьшается количество бесполезных запросов к приложениям, сокращается объём журналов и экономится пропускная способность каналов связи. Особенно заметно это становится на публичных API и проектах с высокой посещаемостью.

Однако именно здесь необходимо сделать важное замечание. Несмотря на все свои достоинства, CrowdSec не является серебряной пулей. Он не заменяет своевременное обновление программного обеспечения, не исправляет ошибки конфигурации и не спасает от публикации административных интерфейсов без аутентификации. Наличие самого современного инструмента обнаружения угроз никак не компенсирует ситуацию, когда кто-то случайно публикует в интернет Redis без пароля или разворачивает Grafana с учётной записью admin/admin.

Иногда складывается впечатление, что часть индустрии воспринимает средства защиты как магические артефакты. Достаточно установить правильный продукт - и безопасность наступит сама собой. Реальность гораздо прозаичнее. Безопасность представляет собой последовательность инженерных компромиссов, процессов и привычек. CrowdSec способен существенно усилить защиту инфраструктуры, но не способен отменить необходимость здравого смысла. И именно поэтому, прежде чем окончательно ответить на вопрос "нужен ли переход с Fail2Ban на CrowdSec", необходимо честно поговорить о том, где каждый из этих инструментов действительно находится на своём месте.

И вот здесь мы наконец подходим к той части разговора, которую почему-то очень не любят в технических статьях. Большинство материалов устроено предельно просто: автор выбирает любимый инструмент, объявляет его лучшим решением на все случаи жизни и оставляет читателя с ощущением, что достаточно выполнить несколько команд установки, чтобы все проблемы исчезли. Реальная эксплуатация работает совершенно иначе. Практически любое инженерное решение представляет собой компромисс между сложностью, стоимостью сопровождения и фактическими рисками. Поэтому честный ответ на вопрос "что лучше - Fail2Ban или CrowdSec?" звучит так: это зависит от того, какую инфраструктуру вы защищаете.

Представим небольшой сервер компании из десяти человек. На нём работает nginx, почтовый сервер и SSH для нескольких администраторов. Никаких контейнеров, никаких облачных балансировщиков, никаких публичных API с миллионами запросов. В такой ситуации Fail2Ban продолжает оставаться великолепным выбором. Он устанавливается буквально за несколько минут, практически не потребляет ресурсы и не требует отдельного изучения архитектуры. Более того, именно в подобных сценариях переход на CrowdSec может оказаться избыточным. Не потому, что CrowdSec плохой, а потому, что сложность решения должна соответствовать сложности задачи.

Например, конфигурация Fail2Ban для такого сервера может выглядеть следующим образом:

# /etc/fail2ban/jail.local

[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 5
backend  = systemd

[sshd]
enabled = true

[nginx-http-auth]
enabled = true

[postfix]
enabled = true

[dovecot]
enabled = true

После запуска всё это начинает работать практически самостоятельно:

sudo systemctl enable fail2ban
sudo systemctl start fail2ban

sudo fail2ban-client status

Вывод может выглядеть следующим образом:

Status
|- Number of jail:      4
`- Jail list:   sshd, nginx-http-auth, postfix, dovecot

Проверка состояния SSH-защиты:

sudo fail2ban-client status sshd

Например:

Status for the jail: sshd

Currently failed: 3
Total failed: 84
Currently banned: 2
Total banned: 14

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

Но теперь представим другую картину. Компания использует Kubernetes. Весь внешний трафик проходит через Cloudflare. Есть несколько публичных API. Часть сервисов работает в Docker, часть - в кластере, а журналы собираются в централизованную систему наблюдаемости. Разработчики постоянно выкатывают новые версии приложений через конвейеры непрерывной доставки, а инфраструктура уже давно перестала помещаться в голове одного человека.

Типичная схема может выглядеть так:

Internet
    ↓
Cloudflare
    ↓
Kubernetes Ingress
    ↓
Services
    ↓
Deployments
    ↓
Pods
    ↓
Loki
    ↓
Grafana

В подобной среде классический Fail2Ban начинает испытывать серьёзные ограничения.

Во-первых, возникает вопрос о местоположении точки принятия решений. Где именно следует анализировать события? На ingress? На узлах? В контейнерах?

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

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

Именно здесь CrowdSec начинает оправдывать свою сложность.

Если попытаться свести всё к простой таблице, получится примерно следующая картина.

Критерий Fail2Ban CrowdSec
Простота установки Отличная Средняя
Потребление ресурсов Минимальное Низкое
Локальные журналы Отлично Отлично
Kubernetes Неудобно Отлично
Docker Ограниченно Хорошо
Cloudflare Требует настройки Отлично
Коллективная аналитика Нет Да
Распределённые атаки Слабо Хорошо
Простота сопровождения Высокая Средняя
Гибкость Средняя Очень высокая

Но даже эта таблица не отражает самого главного различия между двумя подходами.

Fail2Ban представляет собой инструмент реактивной защиты. Что-то произошло на вашем сервере - система отреагировала.

Условно говоря:

Атака
 ↓
Логи
 ↓
Обнаружение
 ↓
Блокировка

CrowdSec стремится действовать немного на опережение.

Его модель выглядит иначе:

Атака на тысячи серверов
 ↓
Коллективное наблюдение
 ↓
Агрегация информации
 ↓
Репутационный анализ
 ↓
Решение
 ↓
Блокировка ещё до развития атаки

Именно это изменение философии можно считать самым важным событием в развитии подобных инструментов за последние годы. Интернет перестал быть набором независимых серверов, каждый из которых защищается в одиночку. Он превратился в огромное распределённое пространство, где атакующие обмениваются инфраструктурой, арендуют облачные мощности, используют заражённые устройства и автоматизируют практически всё. Попытка защищаться от подобных угроз исключительно локальными средствами начинает напоминать ситуацию, в которой жители многоквартирного дома договариваются никогда не рассказывать соседям о подозрительных людях в подъезде.

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

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

И, пожалуй, именно в этом заключается главная мысль всей статьи. Современная инфраструктура уже давно перестала быть одним VPS с Apache и локальными журналами событий. Она стала сложной, облачной, распределённой и временами совершенно безумной. Боты научились использовать ротацию IP-адресов, домашние прокси, арендованные облачные ресурсы и адаптивные сценарии сканирования. Иногда, наблюдая за журналами публичного API, возникает ощущение, что по ту сторону работают не автоматические сканеры, а очень настойчивые рекрутеры, которым отказал Senior DevOps-инженер.

Именно поэтому сегодня защищаться в одиночку становится всё сложнее. Особенно в мире, где ботнетов иногда кажется больше, чем свободных специалистов по эксплуатации на рынке труда.