Если в iptables накопилось несколько тысяч правил, а часть из них показывает нулевые счётчики, ревизия назрела. Причин две: длинные цепочки замедляют обработку пакетов, а устаревшие блокировки бьют по легитимному трафику - офису, мониторингу, партнёрским API.
Короткий ответ на главный вопрос: устаревшим считается правило, не сработавшее ни разу за период наблюдения (на практике берут 30 дней), бан с истёкшим bantime и блокировка адреса, который числится в белом списке. Удалять такое нужно по одному правилу, с резервной копией и отложенным автооткатом, чтобы не потерять SSH-доступ.
Дальше разбираем порядок работ: снять снимок текущего состояния, найти кандидатов на удаление, безопасно почистить, синхронизировать белый список, зафиксировать результат в отчёте и поставить сбор данных на расписание.
Зачем чистить устаревшие блокировки IP и чем опасны накопленные правила
Ревизия нужна, когда правила перестали отражать реальность: адреса, которые вы блокировали год назад, больше не атакуют, а часть подсетей наоборот понадобилась для доступа. Плюс файрвол с длинными цепочками начинает влиять на обработку пакетов, и это уже вопрос производительности, а не аккуратности.
Как накопленные правила влияют на производительность сервера
iptables проходит цепочку последовательно: пакет сравнивается с правилами сверху вниз, пока не найдётся совпадение или не сработает политика по умолчанию. Значит, время обработки растёт вместе с длиной цепочки. Если правило с совпадением стоит в конце INPUT из 5000 записей, ядро пройдёт все 5000 сравнений для каждого такого пакета. При 1000 правил на невысоком трафике вы этого не заметите, при 10 000 правил и сотнях тысяч пакетов в секунду рост нагрузки в softirq становится видимым.
nftables устроен иначе: адреса и порты складываются в sets, а поиск по ним идёт по хешу, а не перебором. Для iptables ту же задачу решает ipset. Итог: тысячи отдельных правил DROP по адресам - плохая идея, а одно правило с сетом из тех же адресов работает быстро. Подробное сравнение трёх инструментов с готовыми конфигами есть в материале настройка файрвола в Linux: сравнение iptables, nftables и ufw.
Отдельный фактор - conntrack. Таблица соединений растёт с числом активных сессий, а не с числом правил, но именно она даёт отказ, когда упирается в nf_conntrack_max: в логах появляется строка table full, dropping packet, и трафик сыпется без всякой связи с цепочками. Смотреть её состояние полезно до и после чистки.
mpstat -P ALL 1 5 grep -E 'NET_RX|NET_TX' /proc/softirqs cat /proc/sys/net/netfilter/nf_conntrack_count cat /proc/sys/net/netfilter/nf_conntrack_max conntrack -S
Универсального порога, после которого пора чистить, нет. Разница между сервером с 200 правилами и сервером с 8000 правил проявляется по-разному в зависимости от профиля трафика, поэтому единственный корректный способ получить цифру для своей системы - снять метрики до ревизии и повторить замеры после неё на том же профиле нагрузки.
Какие риски создают устаревшие баны и ложные блокировки
Главный риск не в производительности, а в потерянном доступе. Вот сценарии, которые встречаются чаще всего:
- IP офиса или VPN-шлюза попал в бан Fail2ban после серии неверных паролей от одного сотрудника. Инженеры теряют доступ к панели и SSH.
- Система мониторинга забанена за частые проверки на закрытом порту. Алерты пропадают именно тогда, когда нужны.
- Партнёрский API упёрся в правило DROP, которое добавили при разборе старого инцидента и не сняли.
- Правило с нулевым счётчиком пакетов занимает место и путает при разборе нового инцидента: непонятно, оно вообще работает или нет.
- Один и тот же IP закрыт дважды - вручную в iptables и через Fail2ban. При снятии одного бана трафик всё равно не идёт, и это выглядит как поломка защиты.
- Неаккуратное удаление правил по SSH оставляет сервер без доступа, и поднимать его приходится через консоль провайдера.
Перед удалением проверяйте каждый адрес по чек-листу: он не входит в ignoreip, не принадлежит вашим подсетям, не используется для мониторинга или бэкапов, а доступ к серверу у вас есть не только по SSH, но и через консоль гипервизора или KVM провайдера. Базовые принципы доступа и усиления хоста разобраны в статье политика безопасности сервера Linux: управление доступом и защита.
Признаки, что ревизия нужна в этом месяце: растёт CPU на softirq без роста трафика, приходят жалобы на доступ, в цепочках много правил с нулевыми счётчиками, есть баны, которые старше bantime, правила и баны дублируют друг друга.
Инвентаризация: как собрать текущее состояние блокировок в iptables, nftables и Fail2ban
Начинайте со снимка. Все команды ниже только читают данные, менять правила на этом шаге не нужно. Выгрузку удобно складывать в отдельный каталог с датой.
mkdir -p /root/fw-audit/$(date +%F) iptables-save > /root/fw-audit/$(date +%F)/iptables.rules iptables -L -v -n --line-numbers > /root/fw-audit/$(date +%F)/iptables-counters.txt nft -a list ruleset > /root/fw-audit/$(date +%F)/nft.ruleset
Сбор правил iptables и nftables с счётчиками пакетов
Ключ -v добавляет столбцы pkts и bytes, --line-numbers даёт номера для удаления, -n отключает обратный резолв DNS. Пример вывода INPUT:
Chain INPUT (policy DROP 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 48219 2893K ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0 2 1204 72K ACCEPT tcp -- * * 10.0.0.0/8 0.0.0.0/0 tcp dpt:22 3 0 0 DROP tcp -- * * 203.0.113.44 0.0.0.0/0
Читается так: правило 2 пропустило 1204 пакета, правило 3 не сработало ни разу. Нулевые pkts и bytes - первый признак кандидата на удаление, но не приговор: правило может ждать редкого сценария.
Счётчики обнуляются при перезагрузке и при восстановлении правил через iptables-restore без ключа -c. Если вы чистите сервер раз в год, нулевой счётчик может означать всего лишь недавний reboot. Фиксируйте дату снимка и повторяйте выгрузку минимум через 30 дней, прежде чем что-то удалять. В nftables счётчики есть только у правил со statement counter, поэтому для аудита их иногда добавляют временно:
nft -a list chain inet filter input nft add rule inet filter input counter comment "audit-mark"
Если сеть описана большим количеством правил, а не сетами, посмотрите методику из разбора практический аудит сетевой инфраструктуры: там показано, как сопоставлять реально открытые порты с разрешениями в правилах.
Выгрузка банов и сроков Fail2ban
Fail2ban показывает состояние по тюрьмам (jails). Пять команд закрывают почти все вопросы аудита:
fail2ban-client status fail2ban-client status sshd fail2ban-client get sshd bantime fail2ban-client get sshd findtime fail2ban-client get sshd maxretry fail2ban-client get sshd ignoreip
Параметры читаются так: maxretry задаёт число неудачных попыток, findtime - окно, в котором они считаются, bantime - срок блокировки. Значение bantime = -1 означает постоянный бан до ручного снятия, такие адреса нужно проверять отдельно. В свежих версиях Fail2ban есть сводная команда fail2ban-client banned, которая выводит забаненные адреса по всем тюрьмам; если её в вашей сборке нет, выгружайте по каждой тюрьме через status.
for jail in $(fail2ban-client status | awk -F: '/Jail list/ {print $2}' | tr -d ' ' | tr ',' ' '); do
fail2ban-client status "$jail" | sed -n '/Banned IP list/p' >> /root/fw-audit/$(date +%F)/f2b-banned.txt
done
Активные баны хранятся в памяти демона и в базе /var/lib/fail2ban/fail2ban.sqlite3, если включён dbpurge/Database. Точную схему таблиц смотрите через .schema в sqlite3, чтобы не строить запросы на догадках. Отдельно сверьте список банов с iptables и nftables: один и тот же адрес может быть закрыт и правилом, и баном.
Как выявить устаревшие и неиспользуемые блокировки: критерии и анализ
Кандидатов на удаление определяем по четырём признакам: нулевые счётчики пакетов за период наблюдения, истёкший или бессрочный бан, пересечение с белым списком, дубликат существующего правила или бана.
Анализ счётчиков пакетов: правила, сработавшие ноль раз
Отфильтровать правила iptables с нулевым счётчиком можно одной строкой: второй столбец в выводе -L -v -n это pkts.
iptables -L INPUT -v -n --line-numbers | awk 'NR>2 && $2==0 {print $1, $4, $10, $11}'
iptables -L FORWARD -v -n --line-numbers | awk 'NR>2 && $2==0 {print $1, $4, $10, $11}'
Дальше читаем контекст. Правило DROP для адреса, которого нет в конфигах мониторинга и в логах за полгода, почти наверняка лишнее. Правило для старого диапазона облачного провайдера может понадобиться при следующем инциденте, и тогда его лучше не удалять, а переписать в set вместе с остальными адресами того же провайдера. Правило, привязанное к редкому сезонному сценарию (например, доступ подрядчика на время отчётного периода), имеет смысл не удалять, а задокументировать: дата добавления, владелец, срок пересмотра.
Правила с нулевыми счётчиками, попавшие в белый список адресов, отдельно проверяйте на логику: часто выясняется, что правило ACCEPT стоит ниже правила DROP, и потому не работает. Общие подходы к блокировке адресов и подсетей с автоматизацией собраны в материале блокировка IP-адресов: стратегии, инструменты и автоматизация.
Проверка сроков банов Fail2ban и пересечений с белым списком
Второй источник кандидатов - баны Fail2ban. Сверяем три множества: активные баны, ignoreip и адреса, которые точно должны иметь доступ.
fail2ban-client get sshd ignoreip fail2ban-client banned fail2ban-client status sshd
Типичная находка: в Banned IP list висит адрес системы мониторинга, потому что она стучится на закрытый порт и набирает maxretry. Адрес обязан быть в ignoreip, но оказался забанен раньше, чем его туда добавили. Изменение ignoreip само по себе не всегда снимает уже существующий бан - надёжнее добавить адрес в белый список, перезагрузить тюрьму и, если бан остался, снять его вручную.
fail2ban-client reload sshd
Сводная таблица для анализа выглядит так:
| Критерий | Как проверить | Решение |
|---|---|---|
| Нулевой счётчик за 30 дней | iptables -L -v -n, awk по pkts | Удалить или перенести адреса в set |
| Бан старше bantime | fail2ban-client banned и bantime тюрьмы | Снять unban, проверить причину бана в логах |
| Адрес в ignoreip, но в бане | Сравнить вывод ignoreip и banned | Перезагрузить тюрьму, затем unban |
| Дубликат правила | iptables-save и nft list ruleset рядом | Оставить одно правило в самом верхнем слое |
| Бессрочный бан (bantime = -1) | fail2ban-client get sshd bantime | Перевести на конечный срок или снять вручную |
Безопасное удаление лишних правил: пошаговый алгоритм
Порядок работ: резервная копия, проверка своего доступа, удаление по одному правилу, проверка после каждого шага, сохранение конфигурации, отчёт. Работайте из tmux или screen, чтобы разрыв сессии не убил процесс на середине.
Резервное копирование правил перед чисткой
mkdir -p /root/fw-audit/$(date +%F) iptables-save > /root/fw-audit/$(date +%F)/iptables.rules nft list ruleset > /root/fw-audit/$(date +%F)/nft.ruleset cp /etc/fail2ban/jail.local /root/fw-audit/$(date +%F)/jail.local.bak fail2ban-client status sshd > /root/fw-audit/$(date +%F)/sshd-status.txt
Восстановление iptables выполняется целиком, команда заменяет весь набор правил, а не добавляет отдельные строки:
iptables-restore < /root/fw-audit/2026-09-23/iptables.rules nft -f /root/fw-audit/2026-09-23/nft.ruleset systemctl restart fail2ban
Копии держите вне сервера: scp или rsync на бэкап-хост. Восстановление из бэкапа стоит один раз проверить на тестовом стенде, иначе в нужный момент выяснится, что файл не читается или в нём правила без нужной политики. Общий порядок настройки защиты, включая сохранение правил после перезагрузки, описан в руководстве файрвол для Linux-сервера: настройка защиты.
Удаление правил iptables и nftables без потери доступа
Сначала зафиксируйте, откуда вы подключены и какое правило пускает вас на сервер. Удалять его нельзя ни при каких обстоятельствах.
echo $SSH_CONNECTION who iptables -S | grep -E 'dport 22|your-management-subnet'
Перед первым удалением поставьте страховку - отложенное восстановление всего набора правил. Если через 10 минут вы всё ещё на связи, задание снимается. Это дешевле, чем поднимать сервер через консоль провайдера.
echo "iptables-restore < /root/fw-audit/$(date +%F)/iptables.rules" | at now + 10 minutes atq atrm 3
В iptables удаление идёт по номеру строки, взятой из вывода с --line-numbers, и номера после каждого удаления сдвигаются, поэтому перечитывайте список. В nftables удаление идёт по handle.
iptables -D INPUT 3 nft -a list chain inet filter input nft delete rule inet filter input handle 12
После каждого удаления открывайте новую SSH-сессию и проверяйте рабочие сервисы. Правило, которое выглядит лишним в выводе, может держать доступ для бэкапов или деплоя, поэтому не удаляйте больше одного-двух правил за итерацию.
Снятие устаревших банов Fail2ban
Снимайте бан после того, как адрес добавлен в белый список, иначе тюрьма заблокирует его повторно при следующей же неудачной попытке.
fail2ban-client set sshd unbanip 203.0.113.44 fail2ban-client unban 203.0.113.44 fail2ban-client unban --all
Последняя команда снимает все баны во всех тюрьмах: она удобна при массовой чистке, но полностью обнуляет защиту до следующего срабатывания фильтров. Применяйте её в окно обслуживания и после неё сразу проверяйте, что фильтры работают, например тестовым подключением на закрытый порт с внешнего хоста.
Белый список IP для Fail2ban и файрвола: как настроить и не конфликтовать
Белый список - это условие, которое должно выполняться раньше блокирующих правил. Если он стоит ниже, толку от него нет: пакет уже отброшен. Настраивать его нужно на двух уровнях - в Fail2ban и в файрволе.
Настройка ignoreip в Fail2ban
[DEFAULT] ignoreip = 127.0.0.1/8 ::1 198.51.100.0/24 192.168.10.5 bantime = 1h findtime = 10m maxretry = 5 [sshd] enabled = true mode = aggressive
Правки вносите в jail.local, а не в jail.conf, чтобы они не потерялись при обновлении пакета. Перечитайте конфигурацию и проверьте, что значение применилось:
fail2ban-client reload fail2ban-client get sshd ignoreip
ignoreip не заменяет сетевые ограничения: он только исключает адрес из фильтров Fail2ban. Если адрес уже в бане, после reload проверьте статус тюрьмы и при необходимости снимите бан вручную.
Whitelist в nftables и ipset для iptables
В nftables белый список удобно держать в interval-сете, тогда в него влезают и отдельные адреса, и подсети.
nft add set inet filter whitelist '{ type ipv4_addr; flags interval; }'
nft add element inet filter whitelist '{ 198.51.100.0/24, 192.168.10.5 }'
nft insert rule inet filter input ip saddr @whitelist accept
nft -a list chain inet filter input
Для iptables ту же роль выполняет ipset с типом hash:net.
ipset create whitelist hash:net ipset add whitelist 198.51.100.0/24 ipset add whitelist 192.168.10.5 iptables -I INPUT 1 -m set --match-set whitelist src -j ACCEPT ipset save > /etc/ipset.conf
Проверьте результат счётчиками: у правила ACCEPT для сета pkts должны расти. Если счётчик стоит на нуле, а трафик от доверенного адреса идёт, значит правило ниже блокирующего, и его надо поднять наверх.
Регламент регулярной чистки блокировок
Разовая чистка ничего не решает: через полгода накопятся те же тысячи правил. Нужен процесс с периодичностью, ролями и понятным набором шагов.
Периодичность и роли в регламенте
Для серверов с публичным доступом и активным Fail2ban разумный цикл - раз в месяц. Для внутренних хостов со стабильным трафиком - раз в квартал. Внеплановый аудит запускайте после инцидента с brute-force, после смены поставщика услуг или при жалобах на доступ.
| Роль | Задача |
|---|---|
| DevOps-инженер | Собирает снимок, анализирует счётчики и баны, готовит список кандидатов |
| Тимлид или владелец сервиса | Утверждает список на удаление, отвечает за окно обслуживания |
| Дежурный инженер | Подтверждает доступ к серверу после чистки, включая альтернативный канал |
Окно обслуживания выбирайте вне пиковых часов, уведомляйте команду и держите под рукой консоль гипервизора. Шаги внутри окна всегда идут в одном порядке: бэкап, инвентаризация, анализ, удаление, проверка доступа, сохранение правил, отчёт.
Автоматизация с cron и systemd timer
Автоматизировать стоит сбор данных и напоминание, а не удаление. Скрипт, который сам вычищает правила без человека, однажды снесёт то, что держит прод.
0 3 1 * * /usr/local/bin/firewall-audit.sh >> /var/log/firewall-audit/cron.log 2>&1
#!/usr/bin/env bash
set -euo pipefail
DEST=/var/log/firewall-audit/$(date +%F)
mkdir -p "$DEST"
iptables-save > "$DEST/iptables.rules" 2>/dev/null || true
nft list ruleset > "$DEST/nft.ruleset" 2>/dev/null || true
fail2ban-client status > "$DEST/fail2ban-status.txt" 2>/dev/null || true
for jail in $(fail2ban-client status | awk -F: '/Jail list/ {print $2}' | tr -d ' ' | tr ',' ' '); do
fail2ban-client status "$jail" > "$DEST/fail2ban-$jail.txt"
done
echo "snapshot: $DEST"
Расписание через systemd выглядит так:
[Unit] Description=Firewall audit snapshot [Service] Type=oneshot ExecStart=/usr/local/bin/firewall-audit.sh [Timer] OnCalendar=monthly Persistent=true [Install] WantedBy=timers.target
systemctl enable --now firewall-audit.timer systemctl list-timers firewall-audit.timer
Ключ Persistent=true закрывает пропущенные запуски после простоя сервера. Уведомление о готовом снимке удобно отправлять в тимлид-канал: так ревизия не остаётся незамеченной.
Шаблон отчёта по блокировкам для команды
Отчёт нужен, чтобы через полгода было понятно, почему правило исчезло. Держите его рядом с задачей в тикете или в вики, чтобы данные были воспроизводимы.
Структура и поля отчёта
| Поле | Что писать |
|---|---|
| Дата и окно | Дата аудита и время работ |
| Сервер | Имя хоста, IP, роль |
| Ответственный | Кто проводил, кто утвердил |
| Слой защиты | iptables, nftables, Fail2ban, Nginx |
| Объект | Правило с номером или handle, конкретный IP или подсеть |
| Причина | Нулевой счётчик, истёкший бан, дубликат, попадание в белый список |
| Действие | Удалено, перенесено в set, снят бан, добавлено в ignoreip |
| Статус | Выполнено, отложено, требует пересмотра |
Отдельным блоком идут метрики до и после: число правил в цепочках INPUT и FORWARD, число активных банов, загрузка CPU в softirq и значение nf_conntrack_count в момент замера.
Пример заполненного отчёта
| Параметр | До чистки | После чистки |
|---|---|---|
| Сервер | web-01 | web-01 |
| Правил в INPUT | 1240 | 1120 |
| Правил с нулевыми счётчиками | 120 | 0 |
| Активных банов Fail2ban | 68 | 23 |
| Адресов в ignoreip | 4 | 7 |
| nf_conntrack_count | 41000 | 41000 |
Пример заполнения по строкам: удалено 120 правил iptables с нулевыми счётчиками за 30 дней, снято 45 банов Fail2ban, три адреса добавлены в ignoreip (офисный шлюз, сервер мониторинга, хост бэкапов), 12 правил для адресов одного облачного провайдера перенесены в ipset. Причины указаны для каждого объекта, чтобы решение можно было перепроверить.
Чек-лист: аудит и очистка блокировок за 30 минут
- Сделайте бэкап: iptables-save, nft list ruleset, копия jail.local вне сервера.
- Проверьте свой доступ: echo $SSH_CONNECTION, наличие консоли провайдера.
- Поставьте страховку: отложенное восстановление правил через at на 10 минут.
- Выгрузите правила с counters: iptables -L -v -n --line-numbers и nft -a list ruleset.
- Выгрузите баны Fail2ban: fail2ban-client status по каждой тюрьме и fail2ban-client banned.
- Сверьте баны и правила с ignoreip и белым списком в файрволе.
- Выберите кандидатов: нулевые счётчики за 30 дней, истёкшие баны, дубликаты, правила ниже ACCEPT для доверенных адресов.
- Удаляйте по одному правилу: iptables -D по номеру, nft delete rule по handle.
- После каждого шага проверяйте доступ и работу сервисов новой сессией.
- Снимайте баны только после добавления адреса в ignoreip.
- Сохраните изменения и убедитесь, что они переживут перезагрузку.
- Заполните отчёт, приложите метрики до и после, отметьте, что удалять нельзя без пересмотра.
Дальше поставьте сбор снимков на расписание и пересматривайте правила через 30 дней: только повторный замер покажет, что вы удалили именно мусор, а не редкое, но нужное правило.