Fail2Ban vs реальный мир: как меня ломали и почему это не спасло

Диагноз: ты настроил Fail2Ban и думаешь, что теперь защищён?

Поздравляю. Ты потратил вечер, воткнул fail2ban, прописал jail для SSH, посмотрел как он бодро банит IP-адреса в логе — и лёг спать с чистой совестью. А утром проснулся и обнаружил, что сервер живёт своей жизнью, в /root/.ssh/authorized_keys появился незнакомый ключ, а в крон-таблице что-то майнит.

Знакомо? Я через это прошёл. И не один раз.

Короче, давай без соплей: Fail2Ban — это полезный инструмент, но он не серебряная пуля. Он закрывает ровно одну дыру из десяти. А оставшиеся девять — открыты, потому что большинство туториалов заканчиваются на «apt install fail2ban» и «systemctl enable fail2ban».

Что будет в этом рецепте
  • Как работает Fail2Ban и почему он не спасает от реальных атак
  • Реальные векторы взлома, которые Fail2Ban не видит
  • Правильная настройка fail2ban настройка ssh на Ubuntu 22.04
  • Скрипт полного аудита и укрепления SSH-сервера
  • Слоёная защита: fail2ban + ufw + ключи + honeypot
  • Чеклист «что делать, если тебя уже ломают прямо сейчас»

Читай внимательно — особенно раздел про то, как обойти fail2ban за 30 секунд. Спойлер: это не хакерская магия, это математика.

Причины: почему Fail2Ban не защищает так, как ты думаешь

Прежде чем лечить — давай поймём, от чего именно fail2ban спасает, а от чего нет. Иначе будешь полоскать горло при переломе ноги.

1. Fail2Ban реагирует только на то, что уже записано в лог

Это банально, но именно здесь зарыта большая часть проблем. Fail2Ban читает лог, считает неудачные попытки, банит IP. Всё. Он не видит трафик в реальном времени, не анализирует пакеты, не знает про slowloris, не понимает TLS fingerprinting.

Если атакующий делает одну попытку в 30 секунд с разных IP-адресов — fail2ban молчит как рыба. Потому что порог не достигнут. По факту это называется distributed brute force, и именно так работают современные ботнеты.

2. По умолчанию настройки fail2ban — это решето

Дефолтный maxretry = 5 и bantime = 10m — это смех. За 10 минут бота отпустят, он поменяет IP через прокси и продолжит. Типичный пароль из 8 символов ломается за миллионы попыток, но если у тебя 100 000 IP-адресов в ботнете, каждый делает по 4 попытки — fail2ban не видит ни одного нарушителя.

3. Fail2Ban не защищает от атак с правильным ключом

Если утёк приватный ключ SSH — fail2ban бесполезен. Авторизация пройдёт с первой попытки, в лог не запишется ничего подозрительного. Ни единого бана. Тишина. А потом — добро пожаловать в систему.

4. Fail2Ban не мониторит боковые входы

SSH — это один вектор. Но если у тебя открыт порт 8080 с устаревшим WordPress, открыт phpMyAdmin на стандартном URL, или торчит наружу Redis без пароля — fail2ban смотрит в другую сторону. Он защищает то, что ты ему сказал защищать. Не больше.

5. Fail2Ban легко обходится через IPv6 или смену IP

Если у атакующего есть /48 подсеть IPv6 (а у хорошего VPS-провайдера это стандарт) — он может делать попытки с триллионов уникальных адресов. Твой fail2ban будет радостно банить каждый, записывать в iptables, пока таблица не распухнет и сервер не упадёт уже от самой защиты. Это называется ban amplification attack.

Вывод: Fail2Ban решает задачу «отбить тупые однопоточные боты с одного IP». Это полезно. Это нужно. Но это примерно 20% реальной защиты SSH от брутфорса — и ещё меньше от целевых атак.

Рецепт: слоёная защита SSH — от правильного Fail2Ban до honeypot

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

Подготовка: что нужно

  • Ubuntu 20.04 / 22.04 или Debian 11/12 (на других — аналогично, с поправкой на пути)
  • Root или sudo доступ
  • Твой публичный SSH-ключ (если его нет — сначала сгенерируй, иначе рискуешь выгнать себя)
  • 15 минут времени и кружка кофе
Важно: Прежде чем трогать SSH-конфиг — открой второй терминал с активной сессией. Если что-то пойдёт не так, не потеряешь доступ. Это не паранойя, это опыт.

Шаг 1: Обновление и установка инструментов

Обновляем систему и ставим всё необходимое одной командой:

apt update && apt upgrade -y
apt install -y fail2ban ufw iptables-persistent net-tools curl wget unattended-upgrades

Проверяем, что fail2ban установился и запустился:

systemctl status fail2ban
fail2ban-client status

Шаг 2: Генерация SSH-ключей (если их нет)

Делаем это на своей машине, не на сервере:

ssh-keygen -t ed25519 -C "myserver-$(date +%Y%m%d)" -f ~/.ssh/myserver_ed25519

Копируем публичный ключ на сервер:

ssh-copy-id -i ~/.ssh/myserver_ed25519.pub root@YOUR_SERVER_IP

Проверяем, что вход по ключу работает, прежде чем отключать парольную аутентификацию:

ssh -i ~/.ssh/myserver_ed25519 root@YOUR_SERVER_IP echo "Key auth works"

Шаг 3: Укрепление конфига SSH

Бэкапим оригинальный конфиг и переписываем:

cp /etc/ssh/sshd_config /etc/ssh/sshd_config.<a class="wpil_keyword_link" href="https://it-apteka.com/category/rezervnoe-kopirovanie/" target="_blank"  rel="noopener" title="Резервное копирование" data-wpil-keyword-link="linked"  data-wpil-monitor-id="1163">backup</a>.$(date +%Y%m%d)

Теперь открываем /etc/ssh/sshd_config и приводим к такому виду (или дописываем в конец через Drop-In директорию — это чище):

cat > /etc/ssh/sshd_config.d/99-hardening.conf << 'EOF'
# Порт — меняем со стандартного. Не панацея, но убирает 90% тупых ботов
Port 2222

# Только IPv4 если IPv6 не нужен
#AddressFamily inet

# Только ключи. Пароли — в топку.
PasswordAuthentication no
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys

# Отключаем всё лишнее
PermitRootLogin prohibit-password
PermitEmptyPasswords no
ChallengeResponseAuthentication no
UsePAM yes
X11Forwarding no
PrintMotd no
AllowAgentForwarding no
AllowTcpForwarding no

# Таймауты — не давать боту сидеть и думать
LoginGraceTime 20
MaxAuthTries 3
MaxSessions 5
MaxStartups 3:50:10

# Алгоритмы — только современные
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group14-sha256
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com

# Логируем всё
LogLevel VERBOSE

# Разрешаем только нужных пользователей (замени на своего)
AllowUsers deploy admin YOUR_USERNAME
EOF

Проверяем конфиг на ошибки и перезапускаем:

sshd -t && systemctl restart sshd
Про порт: Смена порта с 22 на нестандартный убирает из логов 95% шума от тупых ботов. Это не security through obscurity — это экономия ресурсов fail2ban и читаемость логов. Целевую атаку это не остановит, но целевые атаки — отдельная история.

Шаг 4: Правильная настройка Fail2Ban для SSH

Никогда не редактируй /etc/fail2ban/jail.conf напрямую — он перезапишется при обновлении. Создаём свой конфиг:

cat > /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
# Игнорируем наши IP (добавь свои через пробел или CIDR)
ignoreip = 127.0.0.1/8 ::1 YOUR_HOME_IP/32

# Бан на 7 дней. Не 10 минут. Семь. Дней.
bantime  = 7d

# Прогрессивный бан: каждый следующий бан дольше
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 30d

# Окно наблюдения — 1 час
findtime = 1h

# Порог — 3 попытки за час, и ты в бане
maxretry = 3

# Бэкенд — используем systemd там где он есть
backend = systemd

# Уведомления на почту (раскомментируй и настрой)
#destemail = you@example.com
#sendername = Fail2Ban
#mta = sendmail
#action = %(action_mwl)s

[sshd]
enabled = true
# Если поменял порт — укажи его здесь
port = 2222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
findtime = 1h
bantime = 7d

# Дополнительные жёсткие правила для злостных нарушителей
[sshd-aggressive]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/auth.log
# Тот, кто делает 10 попыток — получает месяц
maxretry = 10
findtime = 24h
bantime = 30d

EOF

Перезапускаем и проверяем статус:

systemctl restart fail2ban
fail2ban-client status sshd
fail2ban-client status sshd-aggressive

Шаг 5: Настройка UFW (правильный firewall)

UFW — это обёртка над iptables, которая не позволяет выстрелить себе в ногу. fail2ban vs ufw работают вместе: ufw задаёт базовые правила, fail2ban динамически добавляет баны.

# Сначала — политики по умолчанию
ufw default deny incoming
ufw default allow outgoing

# Разрешаем SSH на новом порту (замени 2222 на свой)
ufw allow 2222/tcp comment 'SSH custom port'

# Разрешаем нужные сервисы (раскомментируй что нужно)
# ufw allow 80/tcp comment 'HTTP'
# ufw allow 443/tcp comment 'HTTPS'

# Включаем (yes — подтверждаем)
ufw --force enable
ufw status verbose
Важно: Убедись, что правило для SSH добавлено ДО включения ufw. Иначе получишь заблокированный сервер и будешь звонить в поддержку хостинга в 3 ночи. Проверено на коллегах.

Шаг 6: Скрипт автоматической проверки безопасности SSH

Создаём скрипт, который можно запускать по крону или вручную — он покажет всё подозрительное за последние 24 часа:

cat > /usr/local/bin/ssh-security-check.sh << 'SCRIPT'
#!/bin/bash
# SSH Security Daily Check
# Запуск: <a class="wpil_keyword_link" href="https://it-apteka.com/tag/bash/" target="_blank"  rel="noopener" title="Bash" data-wpil-keyword-link="linked"  data-wpil-monitor-id="1164">bash</a> /usr/local/bin/ssh-security-check.sh

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

echo -e "${BLUE}=== SSH Security Check $(date) ===${NC}"
echo ""

# 1. Текущие баны Fail2Ban
echo -e "${YELLOW}[1] Активные баны Fail2Ban:${NC}"
fail2ban-client status sshd 2>/dev/null | grep -E "Currently banned|Total banned|Banned IP"
echo ""

# 2. Топ-10 атакующих IP за 24 часа
echo -e "${YELLOW}[2] Топ атакующих IP (24h):${NC}"
grep "Failed password\|Invalid user\|Connection closed by invalid user" /var/log/auth.log | \
  grep "$(date --date='24 hours ago' '+%b %_d')\|$(date '+%b %_d')" | \
  grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | \
  sort | uniq -c | sort -rn | head -10
echo ""

# 3. Успешные входы за 24 часа
echo -e "${YELLOW}[3] Успешные входы (могут быть подозрительными):${NC}"
grep "Accepted " /var/log/auth.log | \
  grep "$(date --date='24 hours ago' '+%b %_d')\|$(date '+%b %_d')" | \
  awk '{print $1, $2, $3, $9, $11}'
echo ""

# 4. Новые SSH-ключи в authorized_keys (за 24h)
echo -e "${YELLOW}[4] Изменения в authorized_keys (24h):${NC}"
find /root /home -name "authorized_keys" -newer /tmp/.lastcheck 2>/dev/null | while read f; do
  echo -e "${RED}ВНИМАНИЕ: изменён файл $f${NC}"
  ls -la "$f"
done
touch /tmp/.lastcheck
echo ""

# 5. Подозрительные крон-задачи
echo -e "${YELLOW}[5] Крон-задачи (проверь на посторонние):${NC}"
for user in root $(cut -f1 -d: /etc/passwd | grep -v "^#"); do
  cron=$(crontab -u "$user" -l 2>/dev/null | grep -v "^#\|^$")
  if [ -n "$cron" ]; then
    echo "  User $user:"
    echo "$cron" | sed 's/^/    /'
  fi
done
echo ""

# 6. Необычные прослушиваемые порты
echo -e "${YELLOW}[6] Открытые порты (сравни с ожидаемыми):${NC}"
ss -tlnp | grep LISTEN
echo ""

# 7. Последние изменения в /etc/passwd и /etc/sudoers
echo -e "${YELLOW}[7] Изменения в системных файлах (7 дней):${NC}"
find /etc -name "passwd" -o -name "sudoers" -o -name "shadow" 2>/dev/null | \
  xargs ls -la 2>/dev/null | awk '{print $6, $7, $8, $9}'
echo ""

echo -e "${GREEN}=== Проверка завершена ===${NC}"
SCRIPT

chmod +x /usr/local/bin/ssh-security-check.sh
echo "Скрипт создан. Запуск: bash /usr/local/bin/ssh-security-check.sh"

Добавляем в крон — пусть присылает отчёт каждое утро (настрой sendmail или mailx):

# Ежедневно в 07:00
echo "0 7 * * * root /usr/local/bin/ssh-security-check.sh >> /var/log/ssh-security.log 2>&1" > /etc/cron.d/ssh-security-check

Шаг 7: Защита от distributed brute force — rate limiting на уровне iptables

Это то, чего fail2ban один сделать не может. Ограничиваем количество новых соединений с одного IP на SSH-порт:

# Создаём правила iptables для rate limiting SSH
# Разрешаем не более 3 новых подключений с одного IP за 60 секунд

iptables -N SSH_LIMIT 2>/dev/null || iptables -F SSH_LIMIT

iptables -A INPUT -p tcp --dport 2222 -m state --state NEW -j SSH_LIMIT
iptables -A SSH_LIMIT -m recent --set --name SSH_TRACK --rsource
iptables -A SSH_LIMIT -m recent --update --seconds 60 --hitcount 4 --name SSH_TRACK --rsource -j DROP
iptables -A SSH_LIMIT -j ACCEPT

# Сохраняем правила
netfilter-persistent save
echo "Rate limiting активирован"
Что это делает: Даже если fail2ban не успел сработать, iptables физически не пропустит более 3 новых TCP-соединений с одного IP за 60 секунд. Для нормальной работы этого хватает, для брутфорса — нет.

Шаг 8: Настройка Fail2Ban для Nginx (бонус)

Если на сервере живёт веб — fail2ban nginx защита тоже нужна. Добавляем в /etc/fail2ban/jail.local:

cat >> /etc/fail2ban/jail.local << 'EOF'

[nginx-http-auth]
enabled = true
port    = http,https
logpath = /var/log/nginx/error.log
maxretry = 5
findtime = 10m
bantime = 1h

[nginx-limit-req]
enabled = true
port    = http,https
logpath = /var/log/nginx/error.log
maxretry = 10
findtime = 10m
bantime = 1h

[nginx-botsearch]
enabled  = true
port     = http,https
logpath  = /var/log/nginx/access.log
maxretry = 2
findtime = 1h
bantime  = 24h

EOF

systemctl restart fail2ban

Шаг 9: Простой SSH Honeypot (ловушка для сканеров)

Это не обязательно, но весело. Поднимаем фейковый SSH на порту 22 — он ничего не делает, только логирует подключения и сразу отдаёт их fail2ban:

# Устанавливаем honeypot (простой вариант через netcat + systemd)
cat > /usr/local/bin/ssh-honeypot.sh << 'HONEYPOT'
#!/bin/bash
# Простой SSH honeypot на порту 22
# Логирует подключающихся и закрывает соединение

while true; do
  IP=$(nc -l -p 22 -q 1 2>/dev/null | head -1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+')
  logger -t ssh-honeypot "Connection attempt from $IP to honeypot port 22"
  echo "$(date): Honeypot hit from $IP" >> /var/log/ssh-honeypot.log
done
HONEYPOT

chmod +x /usr/local/bin/ssh-honeypot.sh

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

cat > /etc/fail2ban/filter.d/ssh-honeypot.conf << 'EOF'
[Definition]
failregex = .*ssh-honeypot.*Connection attempt from <HOST>.*
ignoreregex =
EOF

Добавляем jail в конфиг:

cat >> /etc/fail2ban/jail.local << 'EOF'

[ssh-honeypot]
enabled = true
filter = ssh-honeypot
logpath = /var/log/syslog
# Один стук в honeypot = сразу 30 дней бана
maxretry = 1
bantime = 30d

EOF

systemctl restart fail2ban
Логика honeypot: Настоящий клиент никогда не будет стучать на порт 22, если знает, что SSH сидит на 2222. Значит, любой, кто попробовал подключиться на 22 — это бот или сканер. Баним сразу и надолго.

Шаг 10: Скрипт итоговой проверки всей защиты

Запусти это после настройки — убедишься, что всё работает корректно:

cat > /usr/local/bin/check-ssh-hardening.sh << 'CHECK'
#!/bin/bash
echo "=== Проверка SSH-защиты ==="

# Fail2Ban
echo -n "[Fail2Ban] Статус: "
systemctl is-active fail2ban

echo -n "[Fail2Ban] Jail sshd активен: "
fail2ban-client status sshd &>/dev/null && echo "ДА" || echo "НЕТ"

# SSH конфиг
echo -n "[SSH] Парольная аутентификация отключена: "
grep -q "^PasswordAuthentication no" /etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf 2>/dev/null && echo "ДА" || echo "НЕТ — ПРОБЛЕМА!"

echo -n "[SSH] Root с паролем запрещён: "
grep -q "PermitRootLogin prohibit-password\|PermitRootLogin no" /etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf 2>/dev/null && echo "ДА" || echo "НЕТ — ПРОБЛЕМА!"

echo -n "[SSH] MaxAuthTries <= 3: "
val=$(grep "MaxAuthTries" /etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf 2>/dev/null | grep -oE '[0-9]+' | head -1)
[ "${val:-10}" -le 3 ] && echo "ДА ($val)" || echo "НЕТ ($val) — увеличь защиту"

# UFW
echo -n "[UFW] Firewall активен: "
ufw status | grep -q "Status: active" && echo "ДА" || echo "НЕТ"

# Автообновления
echo -n "[AutoUpdate] Unattended-upgrades: "
dpkg -l unattended-upgrades &>/dev/null && echo "Установлен" || echo "НЕТ — уязвимости не патчатся!"

echo ""
echo "=== Текущие баны ==="
fail2ban-client status sshd 2>/dev/null | grep "Banned IP\|Currently banned"

echo ""
echo "=== Итог ==="
echo "Если все строки выше зелёные — спи спокойно."
echo "Если есть НЕТ — читай статью внимательнее."
CHECK

chmod +x /usr/local/bin/check-ssh-hardening.sh
bash /usr/local/bin/check-ssh-hardening.sh

Осложнения: типичные ошибки и как их лечить

Окей, что-то пошло не так. Не переживай — это нормально. Вот чеклист.

Ошибка 1: Fail2Ban не блокирует IP — что делать?

Сначала проверяем, видит ли fail2ban логи вообще:

# Смотрим что fail2ban читает
fail2ban-client get sshd logpath
# Должен вернуть путь к auth.log или journal

# Проверяем работает ли фильтр на реальных строках
fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf | tail -20

# Если используешь systemd-journal, проверь backend
grep -i "backend" /etc/fail2ban/jail.local
# Для Ubuntu 22.04 часто нужен backend = systemd

Самая частая причина «fail2ban не блокирует» — неправильный logpath или backend. На Ubuntu 22.04 auth.log может не существовать, если rsyslog не установлен:

# Проверяем есть ли auth.log
ls -la /var/log/auth.log

# Если нет — устанавливаем rsyslog
apt install rsyslog -y
systemctl enable --now rsyslog

# Или переключаем fail2ban на systemd journal
sed -i 's/backend = .*/backend = systemd/' /etc/fail2ban/jail.local
systemctl restart fail2ban

Ошибка 2: Fail2Ban забанил меня самого

Классика жанра. Лечится просто, если есть доступ к консоли хостинга:

# Разбаниваем свой IP
fail2ban-client set sshd unbanip YOUR_IP

# Или разбаниваем из всех jail сразу
for jail in $(fail2ban-client status | grep "Jail list" | sed 's/.*Jail list://;s/,//g'); do
  fail2ban-client set $jail unbanip YOUR_IP 2>/dev/null
done

# Добавляем IP в белый список навсегда
echo "ignoreip = 127.0.0.1/8 ::1 YOUR_IP/32" >> /etc/fail2ban/jail.local
systemctl restart fail2ban

Ошибка 3: «fail2ban банит, но атаки продолжаются»

Это distributed brute force. Проверяем разброс IP-адресов:

# Смотрим атакующие подсети
grep "Failed password" /var/log/auth.log | \
  grep "$(date '+%b %_d')" | \
  grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | \
  sort | uniq -c | sort -rn | head -20

Если видишь много разных подсетей — включаем более агрессивный rate limiting и рассматриваем geo-blocking:

# Устанавливаем geoip tools
apt install -y geoip-bin geoip-database

# Блокируем все страны кроме нужных (пример — только RU и DE)
# Это делается через ipset + iptables, но это отдельная большая тема
# Простой вариант <a href="https://it-apteka.com/zapusk-skripta-ustanovki-microsoft-directx-net-framework-i-vc-v-steam-chto-jeto-i-kak-ispravit-zavisanie/" title="Запуск скрипта установки Microsoft DirectX, .NET Framework и VC++ в Steam — что это и как исправить зависание" target="_blank" rel="noopener"  data-wpil-monitor-id="1159">— через ufw + скрипт</a>:
echo "Для geo-blocking используй ipset + список из ipdeny.com"
echo "Или Cloudflare WAF если сайт за CF"

Ошибка 4: «После настройки SSH не могу войти»

Паника — понятна. Но сначала — консоль хостинга (VNC/KVM). Там заходим и лечим:

# Проверяем синтаксис конфига
sshd -t

# Смотрим на каком порту слушает sshd
ss -tlnp | grep sshd
# Или
netstat -tlnp | grep sshd

# Если поменял порт — не забыл ли разрешить его в ufw?
ufw status | grep 2222

# Временно откатываемся на бэкап конфига
cp /etc/ssh/sshd_config.backup.* /etc/ssh/sshd_config
systemctl restart sshd

Ошибка 5: Fail2Ban не запускается после перезагрузки

# Проверяем юнит
systemctl status fail2ban

# Смотрим ошибки в журнале
journalctl -u fail2ban -n 50

# Часто проблема — iptables ещё не загружен, когда fail2ban стартует
# Фикс: добавляем задержку или зависимость
systemctl edit fail2ban
# Добавляем:
# [Unit]
# After=network.target iptables.service ip6tables.service
# Requires=network.target

Ошибка 6: «fail2ban пропускает атаки через IPv6»

# Проверяем включён ли IPv6 jail
fail2ban-client status sshd | grep IPv6

# В jail.local для sshd добавляем явно:
# port = ssh
# (без указания конкретного номера — тогда fail2ban сам разберётся с IPv4/IPv6)

# Также убедись что ip6tables работает:
ip6tables -L f2b-sshd 2>/dev/null && echo "IPv6 jail активен" || echo "IPv6 jail отсутствует"

Чеклист «сервер ломают прямо сейчас»

🚨 Экстренный чеклист — если взлом идёт в реальном времени
  1. Смотрим кто подключён сейчас: who и w и ss -tnp | grep :22
  2. Рубим подозрительные сессии: pkill -KILL -u SUSPICIOUS_USER
  3. Блокируем IP вручную: iptables -A INPUT -s ATTACKER_IP -j DROP
  4. Меняем authorized_keys: проверяем /root/.ssh/authorized_keys и /home/*/.ssh/authorized_keys на посторонние ключи
  5. Проверяем крон: crontab -l и ls /etc/cron* и ls /var/spool/cron/
  6. Смотрим новые процессы: ps auxf — ищем майнеры, reverse shell
  7. Ищем новые исполняемые файлы: find /tmp /var/tmp /dev/shm -executable -type f 2>/dev/null
  8. Делаем снимок системы для анализа перед тем как что-то чинить
  9. Если сомневаешься — изолируй сервер от сети (firewall DROP all) и восстанавливай из бэкапа

Прогноз: что мы построили и чего ждать

Что в итоге получилось

Мы собрали не «просто fail2ban», а многоуровневую защиту SSH:

  • Слой 1 — SSH конфиг: отключили пароли, оставили только ключи, порезали MaxAuthTries, убрали лишние фичи. Это убивает 80% векторов авторизации.
  • Слой 2 — UFW: закрыли всё лишнее на уровне firewall. Меньше поверхность атаки — меньше проблем.
  • Слой 3 — iptables rate limiting: физически ограничили количество соединений. Даже если fail2ban спит — брутфорс не пройдёт.
  • Слой 4 — Fail2Ban с нормальными настройками: bantime 7 дней вместо 10 минут, прогрессивные баны, два jail с разными порогами.
  • Слой 5 — Honeypot: кто постучался на порт 22 — сразу в бан на 30 дней без разговоров.
  • Слой 6 — Мониторинг: скрипт, который каждое утро рассказывает что происходило ночью.

Что это не закрывает — честно

По факту, даже с этим стеком остаются векторы, которые требуют отдельного внимания:

  • Уязвимости в других сервисах — если на сервере живёт CMS с дырой, никакой fail2ban не поможет. Обновляй ПО.
  • Утечка приватного ключа — если ключ скомпрометирован, смени его. Сегодня.
  • Supply chain атаки — вредоносный пакет, который ты сам установил. Тут нужна отдельная история про контроль зависимостей.
  • Инсайдер — если кто-то из своих имеет доступ и плохие намерения. Fail2Ban тут вообще не при делах, это задача для аудита прав и мониторинга действий.
Реальный итог: После этих настроек 99% автоматизированных атак на SSH пройдут мимо — не потому что fail2ban такой умный, а потому что нет парольной аутентификации, нет стандартного порта, есть rate limiting и honeypot. Fail2Ban в этой схеме — полезный, но не главный игрок.

Следующие шаги (когда разберёшься с базой)

  • Настроить двухфакторную аутентификацию для SSH через Google Authenticator или YubiKey
  • Поднять VPN (WireGuard) и закрыть SSH от публичного интернета вообще
  • Настроить централизованный syslog — Graylog или ELK — чтобы видеть события со всех серверов в одном месте
  • Рассмотреть IDS/IPS — Suricata или Snort — для анализа трафика на уровне сигнатур
  • Настроить автоматические бэкапы с проверкой — потому что лучшая защита от взлома — это возможность быстро восстановиться
Есть вопросы или что-то пошло не так?

Пиши в комментарии — разберём твой конкретный случай. У каждого сервера свой характер, и иногда нужен индивидуальный подход.

Подписывайся на телеграм-канал IT-Аптека — там новые рецепты без воды: скрипты, конфиги, разборы инцидентов. Только то, что можно скопировать и применить.

Андрей Анатольевич
Author: Андрей Анатольевич

Руководитель ИТ / Кризис-менеджер 25 лет в IT: от инженера в МегаФоне до руководителя отдела. Знаю, как выглядит бардак: нестабильные сети, устаревшая инфраструктура, конфликты в команде, раздутые сроки. Помогаю бизнесу выходить из кризиса: навожу порядок в легаси, стабилизирую то, что разваливается, выстраиваю прогнозируемые процессы. Не раз возвращал к жизни ИТ-структуры — знаю цену хаосу. 📍 Ищу проект для полной реорганизации / стабилизации. 📬 Telegram: @over_dude ✉️ mail@it-apteka.com

Оставайтесь на связи

Рецепты от IT-боли. Без воды, без рекламы, без маркетинговой шелухи.

Подписаться на IT-Аптеку →

Мы ВКонтакте

IT-Аптека — советы, новости и помощь рядом.

Вступить в группу ВКонтакте →
Поделитесь:

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Прокрутить вверх