iptables в Linux: устройство правил и безопасная настройка firewall

iptables — пользовательская утилита для настройки правил фильтрации и NAT, которые применяет подсистема Netfilter в ядре Linux. Правило задает, что ядро сделает с сетевым пакетом: пропустить, отбросить или изменить. Netfilter встроен в ядро с версии 2.4 (2001 год), но сам пакет iptables доступен в большинстве дистрибутивов и может не входить в минимальную установку — перед работой проверьте наличие команды и backend: iptables --version. Для изменения правил нужны соответствующие сетевые привилегии — обычно команду запускают через sudo; на уровне ядра это связано с capability CAP_NET_ADMIN.

Ниже разберу, как iptables обрабатывает пакет (таблицы и цепочки), из чего состоит правило, и соберу с нуля рабочий firewall для сервера: политики по умолчанию, разрешение нужных портов, NAT и сохранение правил. В конце — когда вместо iptables стоит смотреть на nftables.

Как iptables обрабатывает пакет: таблицы и цепочки

Каждый пакет, проходящий через систему, попадает в набор правил. Эти правила сгруппированы в цепочки (chains), а цепочки — в таблицы (tables). Таблица определяет, зачем обрабатывается трафик, а цепочка — на каком этапе пути пакета это происходит.

Пять встроенных цепочек соответствуют точкам на пути пакета:

  • INPUT — пакеты, адресованные самому хосту (входящий SSH, HTTP, ping к серверу);
  • OUTPUT — пакеты, которые хост отправляет сам (запрос к внешнему API, обновления);
  • FORWARD — транзитный трафик, идущий через хост, но не ему (актуально, когда машина работает как роутер или NAT-шлюз);
  • PREROUTING — обработка до маршрутизации, до того как ядро решило, куда направить пакет;
  • POSTROUTING — обработка после маршрутизации, перед выходом пакета из интерфейса.

Таблиц тоже несколько, и в каждой есть только часть цепочек:

Таблица Зачем Основные цепочки
filter Фильтрация: пропустить, отклонить или отбросить (таблица по умолчанию) INPUT, OUTPUT, FORWARD
nat Трансляция адресов: проброс портов, маскарадинг PREROUTING, INPUT, OUTPUT, POSTROUTING
mangle Правка заголовков пакета, маркировка и классификация трафика (метки для policy routing; собственно управление очередями и полосой выполняют tc и qdisc) все пять
raw Отметить пакеты до трекинга соединений (NOTRACK) PREROUTING, OUTPUT

Если таблицу не указать явно ключом -t, iptables работает с filter. Для базовой настройки firewall хватает filter (что пускать) и nat (проброс и маскарадинг); mangle и raw нужны в специфичных задачах. У таблицы nat четыре встроенные цепочки — PREROUTING, INPUT, OUTPUT и POSTROUTING; цепочка nat/INPUT применяется к пакетам, адресованным локальному узлу.

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

Из чего состоит правило

Правило — это условие плюс действие. Ядро сверяет пакет с условием, и если совпало, выполняет действие (target).

Часть правила За что отвечает Примеры
Критерий (условие) По каким признакам опознать пакет -p tcp, -s 192.168.1.10, --dport 22, -i eth0, -m conntrack --ctstate NEW
Действие (-j target) Что сделать с совпавшим пакетом ACCEPT, DROP, REJECT, LOG, DNAT, MASQUERADE
Счетчик Сколько пакетов и байт обработало правило виден в iptables -L -v

Основные ключи управления правилами:

Ключ Действие
-A <цепочка> Добавить правило в конец цепочки
-I <цепочка> [N] Вставить в начало или на позицию N
-D <цепочка> Удалить правило
-R <цепочка> N Заменить правило по номеру
-F [цепочка] Очистить цепочку (удалить все правила)
-P <цепочка> <target> Задать политику по умолчанию (ACCEPT или DROP)
-L -v -n --line-numbers Показать правила с счетчиками и номерами

Простой пример — закрыть доступ к порту базы данных (3306) для конкретного внешнего адреса:

iptables -A INPUT -p tcp -s 203.0.113.7 --dport 3306 -j DROP

Разбор по частям: -A INPUT добавляем в цепочку входящих; -p tcp протокол TCP; -s 203.0.113.7 только пакеты с этого IP; --dport 3306 порт назначения 3306; -j DROP молча отбросить. Чтобы снять правило, повторяют ту же строку, заменив -A на -D. Порт управления (SSH, 22) отдельным DROP вслепую лучше не трогать — как безопасно менять доступ к SSH и политику по умолчанию, разберу ниже: с резервной копией набора правил и автооткатом.

Важно про блокировку: DROP отбрасывает пакет без ответа (отправитель ждет тайаута), а REJECT отвечает уведомлением (по умолчанию ICMP port unreachable, для TCP можно вернуть RST). DROP тише и хуже выдает наличие фильтра сканерам, REJECT понятнее для своих клиентов.

Настройка firewall с нуля: пошагово

Соберу типичную политику для сервера: по умолчанию все входящее запрещено, разрешены только нужные службы. Команды выполняются от root (через sudo).

Шаг 0. Перед любыми изменениями сохраните текущий набор правил — к нему можно будет откатиться:

sudo iptables-save > /root/iptables.before

Восстановить сохраненное поможет sudo iptables-restore < /root/iptables.before. На удаленной машине применяйте новую конфигурацию через iptables-apply: утилита загружает правила и, если вы не подтвердите их в течение таймаута (по умолчанию 10 секунд), автоматически возвращает прежние — если новая политика оборвет SSH-сессию, доступ вернется сам.

Шаг 1. Пока не трогаем политики, сначала добавим разрешающие правила — иначе при удаленной работе можно отрезать себе SSH. Разрешаем уже установленные соединения и локальный интерфейс:

iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT

Первое правило — ключевое для stateful-фильтра: модуль отслеживания соединений (conntrack) помнит уже открытые сеансы, и ответы на исходящие запросы проходят автоматически, отдельные правила для них не нужны. Второе разрешает трафик на loopback (lo), без него ломаются локальные службы.

Шаг 2. Разрешаем нужные порты — SSH, а для веб-сервера еще HTTP и HTTPS. --ctstate NEW означает новые входящие соединения. SSH безопаснее открывать не всему миру, а только с доверенного адреса или подсети управления (ключ -s):

iptables -A INPUT -p tcp -s 203.0.113.0/24 --dport 22 -m conntrack --ctstate NEW -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -m conntrack --ctstate NEW -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -m conntrack --ctstate NEW -j ACCEPT

Если доступ по SSH нужен с произвольных адресов, ключ -s у первой строки убирают — но тогда порт стоит дополнительно прикрыть fail2ban или ограничением частоты подключений.

Шаг 3. Разрешающие правила добавлены, теперь можно закрыть все остальное политикой по умолчанию. Политика применяется к пакету, который не подошел ни под одно правило цепочки:

iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

Порядок именно такой: сначала разрешить SSH и established, и только потом ставить -P INPUT DROP. Если сделать наоборот на удаленной машине, текущая SSH-сессия оборвется. На незнакомой машине для подстраховки запускают отложенный сброс правил (например, задание в at через 5 минут), чтобы вернуть доступ, если правила окажутся неверными.

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

iptables -L INPUT -v -n --line-numbers

NAT: проброс портов и маскарадинг

Таблица nat нужна, когда хост раздает интернет локальной сети или прячет внутренние сервисы. Правила ставят в цепочки PREROUTING (правка адреса назначения) и POSTROUTING (правка адреса источника).

Маскарадинг — подмена адреса источника на IP внешнего интерфейса, чтобы машины из локальной сети выходили в интернет через шлюз. Это разновидность SNAT, которая сама подставляет текущий IP интерфейса (удобно для динамического адреса):

iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE

Ключ -s 192.168.1.0/24 ограничивает маскарадинг только своей локальной подсетью, а не всем проходящим трафиком; интерфейс eth0 и адрес подсети подставьте под свою схему.

Отдельно нужно включить пересылку пакетов в ядре, иначе транзитный трафик не пойдет:

sysctl -w net.ipv4.ip_forward=1

Чтобы значение сохранялось после перезагрузки, его прописывают в /etc/sysctl.conf или файл в /etc/sysctl.d/.

Проброс порта (DNAT) — перенаправить внешние запросы на внутренний сервер. Например, входящий трафик на порт 80 шлюза отдать на внутреннюю машину:

iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 192.168.1.100:80

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

Основные действия (targets)

Действие завершает правило и решает судьбу пакета. filter — основная таблица для решений ACCEPT/DROP, но это цели-вердикты, и встречаются они в цепочках разных таблиц; SNAT и DNAT применяются в таблице nat в поддерживаемых цепочках:

Действие Что делает Где применяют
ACCEPT Пропустить пакет любая (вердикт)
DROP Молча отбросить, без ответа любая (вердикт)
REJECT Отклонить с уведомлением (ICMP или TCP RST) filter, mangle
LOG Записать в системный журнал, не меняя судьбу пакета любая
RETURN Прервать текущую цепочку (см. пояснение ниже) любая
DNAT Подменить адрес назначения (проброс) nat, PREROUTING
SNAT Подменить адрес источника (статический IP) nat, POSTROUTING
MASQUERADE SNAT с автоподстановкой IP интерфейса nat, POSTROUTING

RETURN работает по-разному в зависимости от цепочки: в пользовательской цепочке он возвращает обработку к следующему правилу вызвавшей цепочки, а во встроенной цепочке «предыдущей» нет — там RETURN приводит к применению политики этой цепочки по умолчанию.

LOG обычно ставят перед DROP отдельным правилом, чтобы и записать попытку, и отбросить пакет: сам LOG пропускает пакет дальше по цепочке.

IPv6 и проверка backend

iptables управляет только IPv4. Для IPv6 есть отдельная утилита ip6tables со своими таблицами и цепочками — и это частая брешь: если хост отвечает по IPv6, а правила заданы только для IPv4, остается открытый путь в обход всей IPv4-политики. Поэтому политику по умолчанию и разрешающие правила повторяют и для IPv6 через ip6tables, либо IPv6 осознанно отключают — но только когда это обосновано архитектурой.

Перед настройкой стоит проверить, какая утилита и какой backend активны:

iptables --version
ip6tables -L -n
nft list ruleset

В выводе iptables --version будет пометка nf_tables или legacy. Не смешивайте legacy- и nft-backend: правила, заданные через iptables-legacy и iptables-nft, живут в разных наборах и не видят друг друга, из-за чего часть правил может молча не применяться. nft list ruleset показывает итоговый набор в терминах nftables — удобно свериться, что все правила действительно на месте.

Как сохранить правила

Правила iptables живут в памяти ядра и сбрасываются при перезагрузке. Сначала посмотрите текущий набор — его печатает iptables-save:

iptables-save

Единой команды сохранения нет: способ зависит от дистрибутива. В Debian и Ubuntu ставят пакет iptables-persistent (служба netfilter-persistent), который держит правила в /etc/iptables/rules.v4 и rules.v6 и поднимает их при старте. В RHEL, CentOS и Fedora за это отвечает служба iptables из пакета iptables-services (команда service iptables save пишет в /etc/sysconfig/iptables). Для IPv6 — отдельные файлы и утилита ip6tables-save.

Результат обязательно проверяют после перезагрузки: делают reboot и убеждаются командами iptables -L -n и ip6tables -L -n, что политика по умолчанию и правила поднялись — иначе после первого же рестарта сервер останется без firewall.

nftables как современная альтернатива

С ядра 3.13 (2014 год) в Linux есть nftables — единый фреймворк, который заменяет сразу iptables, ip6tables, arptables и ebtables одной утилитой nft и одним синтаксисом. Netfilter Project перевел iptables в режим legacy-поддержки и рекомендует новые конфигурации делать на nftables.

При этом резкой ломки нет. В современных дистрибутивах (Debian 10, Ubuntu 20.10, RHEL 8 и новее) команда iptables по умолчанию — это уже обертка iptables-nft: привычный синтаксис остается, а правила под капотом транслируются в nftables. Проверить, какой режим активен, можно так:

iptables --version

В выводе будет пометка nf_tables или legacy. Готовую конфигурацию iptables удобно переносить на новый синтаксис утилитой iptables-translate, которая печатает эквивалентную команду nft. Изучать iptables по-прежнему стоит: он остается в ходу на множестве серверов и в документации, а понимание таблиц и цепочек напрямую переносится на nftables.

Где применяется iptables на практике

Настройка firewall на iptables — базовый навык системного администратора и DevOps-инженера: закрыть лишние порты сервера, пробросить трафик на внутренние сервисы, поднять NAT-шлюз, залогировать подозрительные подключения, связать правила с fail2ban для защиты от перебора паролей. Понимание таблиц, цепочек и порядка правил переносится и на nftables, и на надстройки вроде firewalld и ufw.

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

Разобрать сетевую безопасность, iptables и администрирование Linux по шагам помогает курс Администратор Linux в Otus. Посмотреть формат занятий и уровень до оплаты можно на бесплатных вебинарах — там разбирают конкретные задачи и отвечают на вопросы.

Смежные темы: Скриптовые языки для админов и разработчиков, Установка Linux с флешки.

FAQ

В чем разница между stateless- и stateful-фильтрацией?
Stateless-правило смотрит на каждый пакет по отдельности (IP, порт, протокол) и не знает контекста. Stateful-фильтр через модуль conntrack помнит состояние соединения и различает новые пакеты и ответы на уже открытые сеансы, поэтому правило с --ctstate ESTABLISHED,RELATED пропускает ответный трафик без отдельных разрешений.

Чем -m state отличается от -m conntrack?
Это два модуля отслеживания состояний. Старый -m state --state считается устаревшим, но еще работает; актуальный вариант — -m conntrack --ctstate с теми же значениями (NEW, ESTABLISHED, RELATED, INVALID) и более широкими возможностями. В новых правилах лучше использовать conntrack.

Что выбрать новичку — iptables, nftables или firewalld?
Для одиночного сервера проще начать с высокоуровневой надстройки: ufw в Ubuntu или firewalld в RHEL и Fedora. iptables и nftables дают полный контроль и нужны, когда стандартных профилей не хватает. При этом firewalld и ufw под капотом опираются на тот же netfilter.

Выводы

  • iptables — пользовательская утилита; правила применяет подсистема Netfilter в ядре, а менять их можно с сетевыми привилегиями (обычно через sudo).
  • Правила сгруппированы в цепочки (INPUT, OUTPUT, FORWARD, PREROUTING, POSTROUTING) и таблицы (filter, nat, mangle, raw); по умолчанию используется filter.
  • Внутри цепочки срабатывает первое подошедшее правило, поэтому порядок важен; на все несовпавшее действует политика по умолчанию (-P).
  • Безопасный порядок настройки: сделать бэкап (iptables-save) и применять через iptables-apply, сначала разрешить established, loopback и SSH с нужного адреса, и только потом ставить -P INPUT DROP.
  • NAT (маскарадинг и проброс портов) живет в таблице nat и требует включенной пересылки net.ipv4.ip_forward=1; маскарадинг ограничивают своей подсетью через -s.
  • IPv6 настраивают отдельно через ip6tables, иначе остается открытый путь в обход IPv4-политики; backend (legacy или nf_tables) не смешивают.
  • Правила не сохраняются сами: их выгружают через iptables-save, поднимают при старте пакетом автозагрузки под свой дистрибутив и проверяют после перезагрузки.
  • В современных дистрибутивах iptables — это обертка над nftables; для новых конфигураций рекомендуется nftables, но понимание iptables остается базой.
OTUS Журнал
Скидка 5% 14-20 сентября на курсы (popup)