Короткий ответ

Установка пакета ≠ защита. Нужен jail sshd enabled, backend = systemd на Ubuntu с journal, banaction в тот firewall, что фильтрует (UFW → ufw, иначе nftables-multiport), ignoreip на LAN 10.0.20.0/24, проверка set sshd banip и nc с тестового IP. Fail2Ban не замена ключей и CIDR. Если уже стоит и не банит — диагностика jail. Хост host.example (10.0.20.10), пользователь admin.

Симптомы и как отличить

Ставите с нуля или пересобираете «как надо». Отличие от hardening SSH: здесь пакет бана, не sshd_config. Сначала ключи: парольный SSH, sshd. Firewall должен быть включён: UFW/nft.

Возможные причины «поставил — не банит»

Разжёвано в соседней статье. При установке чаще всего: нет jail.local, backend file на journal-only хосте, iptables action при чистом nft без compat.

Диагностика до установки

dpkg -l fail2ban ufw | grep ^ii
sudo ufw status
systemctl is-active ssh
sudo journalctl -u ssh -n 5 --no-pager

Выберите datapath: UFW или nftables.service, не оба.

Решение

1. Пакет

sudo apt-get update
sudo apt-get install -y fail2ban
sudo systemctl enable --now fail2ban

Не копируйте целиком jail.conf в jail.local навсегда — потом боль при апдейте. Только дельты в jail.d.

2. Jail sshd

Если UFW active:

sudo tee /etc/fail2ban/jail.d/10-sshd.local >/dev/null <<'EOF'
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 10.0.20.0/24
bantime = 1h
findtime = 10m
maxretry = 4
banaction = ufw

[sshd]
enabled = true
backend = systemd
port = ssh
filter = sshd
EOF

Если UFW нет, nft:

banaction = nftables-multiport
sudo fail2ban-client -t
sudo systemctl restart fail2ban
sudo fail2ban-client status
sudo fail2ban-client status sshd

fail2ban-client -t проверяет конфиг в актуальных версиях пакета; если флага нет — journalctl -u fail2ban после restart.

3. Доказать бан

С лабораторного адреса, не со своего jump (он в ignoreip):

sudo fail2ban-client set sshd banip 203.0.113.50
sudo fail2ban-client status sshd
sudo ufw status numbered | grep 203 || sudo nft list ruleset | grep 203.0.113.50
sudo fail2ban-client set sshd unbanip 203.0.113.50

Ожидание: IP в Banned list и в firewall. Только строка в /var/log/fail2ban.log без правила — action не тот; чините по соседней статье.

4. Не банить себя

ignoreip с LAN и jump. Не 0.0.0.0/0. Мониторинг с WAN-IP вынесите или добавьте /32.

5. Другие jail

nginx-http-auth, recidive — после рабочего sshd. Не включайте всё из jail.conf сразу.

Настройка, которая реально банит, включает мониторинг самого Fail2Ban. journalctl -u fail2ban на ошибки nft/ufw: command not found сразу после install — значит action не из пакета или PATH в systemd unit. Пакет Ubuntu кладёт actions в /etc/fail2ban/action.d/. Не копируйте action с CentOS firewallcmd.

banaction_allports нужен jail'ам, которые банят не один порт (recidive). Для sshd достаточно multiport/ssh.

IPv6: в jail.conf современных версий allowipv6 = auto. Проверьте fail2ban-client get sshd banip умеет v6. UFW должен фильтровать ip6tables/nft inet. Иначе боты с AAAA игнорируют бан.

Логи fail2ban ротируйте (logrotate.d/fail2ban пакетом). Переполненный лог не останавливает бан, но слепит расследование.

Связка с sshd: после ключей-only jail всё ещё ловит Invalid user и Failed publickey (в aggressive). Это шум сканеров. Сузьте 22 CIDR — шум упадёт сильнее любого maxretry.

Не включайте jail sshd дважды под разными именами с одним filter — двойной бан/ошибки. fail2ban-client status список уникален.

Тест без чужого IP: используйте документацию fail2ban-client set sshd banip как выше. Не устраивайте сами brute-force на прод с домашнего IP, если он не в ignoreip — запрётесь.

Документ в заявке: файл 10-sshd.local, вывод status sshd, скрин/текст nft/ufw с тестовым IP. Это определение «банит, а не только пишет лог».

Фильтры: не копируйте failregex с gist без fail2ban-regex на вашем journal. Ubuntu sshd пишет sshd[pid]: внутри journal полей; backend systemd вытаскивает MESSAGE. Если regex ждёт pam_unix а у вас только Failed publickey — поднимите mode или оставьте normal и закройте пароль.

ignorecommand и ignoreregex — для ложных срабатываний CI. Не ignore все Failed.

После apt-get upgrade fail2ban проверьте, что jail.d на месте и status sshd жив. Иногда меняется дефолтный backend.

Храните jail.d в ansible; jail.conf не в git целиком.

Проверка bantime: fail2ban-client get sshd bantime. Согласуйте с политикой IR (час vs сутки). Слишком короткий при открытом пароле бесполезен; слишком длинный при ложном regex — lockout офиса.

Не ставьте action = %(action_mwl)s думая, что это «бан плюс письмо», пока не проверите, что MTA есть. Иначе action падает, бана нет. Начните с banaction = ufw без почты. Письма — второй шаг, когда status sshd уже показывает Banned IP list.

usedns = no уменьшает задержки и ложные баны по PTR. Для SSH обычно no.

Пакет python3-pyinotify не обязателен для sshd jail на systemd backend. Не ставьте лишнее «чтобы fail2ban заработал».

Как проверить, что проблема устранена

sudo fail2ban-client status sshd
systemctl is-enabled fail2ban
sudo grep -E 'enabled|banaction|backend' /etc/fail2ban/jail.d/10-sshd.local

Тестовый banip виден в UFW/nft. SSH admin с LAN жив. После maxretry с чужого стенда — Ban (осторожно с IP стенда). Ключи SSH по-прежнему no password.

Если не помогло

Переходите в Fail2Ban не блокирует: regex, journalmatch, Docker, IPv6. Не маскируйте sshd.

Профилактика

  • jail.d в ansible.
  • Алерт по ошибкам action в fail2ban.log.
  • После смены UFW↔nft — снова banip тест.
  • Слой 0: CIDR на 22.

FAQ

defaults-debian.conf уже enabled sshd

Да на многих Ubuntu. Ваш 10-sshd.local должен дополнять backend/banaction. fail2ban-client get sshd banaction — истина.

recidive jail

Банит повторников дольше. Включайте когда sshd jail точно банит, иначе рецидив по «Found» без Ban бесполезен.

mode=aggressive

Больше матчей, больше ложных. После ключей-only часто достаточно normal + Invalid user.

fail2ban в контейнере

NET_ADMIN и тот же namespace, что фильтр. Обычно ставят на хост.

Нужен ли при VPN-only SSH

Низкий приоритет. Всё равно полезен против ошибок allow. Не вместо VPN.