Тариф успешно добавлен в корзину
В корзину
url image

Nftables: руководство по работе с файрволом нового поколения Linux

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

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

Один из современных инструментов для реализации и настройки брандмауэра в Linux — пакет nftables. Он позволяет управлять правилами фильтрации сетевого трафика и является частью пакетного фильтра ядра Linux (netfilter).

Чем отличается от iptables

Файрвол nftables — новый инструмент, который приходит на смену iptables. Мы кратко рассмотрим их основные отличия. 

Iptables давно работает на серверах, поэтому имеет привычный, но громоздкий и неочевидный для новичков синтаксис. Nftables — это его современный аналог со структурированным, компактным и логичным синтаксисом.
Расширения для iptables сделали кодовую базу достаточно раздутой, что усложняет его поддержку и приводит к дублированию функций. В nftables попытались устранить эту проблему. Кроме того, у nftables есть другие преимущества:

  • новая универсальная инфраструктура наборов (set);
  • возможность управлять IPv4 и IPv6 без использования дополнительных инструментов;
  • улучшенная поддержка динамических обновлений наборов правил;
  • гибкость в создании пользовательских цепочек, в отличие от жёстко заданного набора стандартных цепочек в iptables.

Итак, nftables — это более современное решение, чем iptables. Но сообщество linux в общем и системные администраторы в частности не всегда используют нововведения, поскольку это может затруднить поддержку без того сложных систем, а в новом инструменте могут встречаться недоработки. 

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

Установка nftables

Для работы с nftables будем использовать ОС Debian. Сначала необходимо убедиться, что на сервере установлены необходимые пакеты и удалены пакеты, связанные с iptables — они могут мешать друг другу и путать при проверках правил. Например, администратор может вносить изменения только в пакете iptables, не зная, что фактически в системе активен nftables.

Для работы с файрволом на сервере должен быть установлен пакет nftables. Проверить это можно с помощью пакетного менеджера dpkg:

dpkg -l | grep nftables
Вывод dpkg при проверке наличия пакета nftables

Если службы nftables на вашем сервере нет, его можно установить через apt:

apt install nftables

Убедиться, что на вашем сервере отсутствует iptables, можно через dpkg:

dpkg -l | grep iptab

Чтобы удалить iptables, используйте утилиту apt:

apt purge iptables

После установки nftables необходимо запустить службу nftables.service и добавить её в автозагрузку:

systemctl enable nftables.service
systemctl start nftables.service

Теперь при запуске сервера правила будут загружаться из файла конфигурации: /etc/nftables.conf.

Служба nftables.service также позволяет производить загрузку правил из конфигурации через команду:

systemctl restart nftables.service

Управление nftables

Общий синтаксис правил

Чтобы проверить действующие правила, используйте команду:

nft [-a] list ruleset

Дополнительный ключ -a необходим, чтобы видеть номера правил, например, для удаления.

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

alias nft-ls='nft -a list ruleset'

После этого в текущей сессии bash вызовите команду через nft-ls для вывода правил. Чтобы оставить данный псевдоним для каждой сессии, можно добавить эту команду в .bash_rc или .bash_alias нужного пользователя.

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

nft – оператор – объект – семейство – таблица – цепочка – правило – действие

  • Оператор — действие с объектом: add, delete, list, insert и т. д.
  • Объект — элемент,  с которым выполняют действия: rule, chain, table.
  • Семейство — семейство адресации. Операции применяются к пакетам только того семейства, которое указано: например, ip только IPv4, ip6 только IPv6, inet одновременно IPv4 и IPv6 и т. д. Может принимать следующие значения: ip, ip6, inet, erp, bridge, netdev.
  • Правило – условие, по которому нужно определить подходящий пакет.
  • Таблица, цепочка — способ организации структуры: все правила должны быть в цепочках, а цепочки — в таблицах.
  • Действие — что необходимо сделать с пакетом, который попал под правило.

Если вы только что установили nftables, поставили службу nftables.service в автозагрузку и запустили её, то на сервере должны работать правила, которые входят в пакет nftables и находятся в /etc/nftables.conf:

Проверка текущих правил на сервере

В правилах есть таблица filter семейства inet и цепочки input, forward и output. В конфигурации по умолчанию указывается семейство правил inet. Оно объединяет протоколы IPv4 и IPv6, что позволяет унифицировать семейства ip и ip6 и упростить создание правил. Если при создании таблицы не указать семейство, то по умолчанию будет использоваться семейство ip, которое работает только с IPv4. 

Но, как мы ранее упоминали, ничто не мешает изменить названия цепочек и таблиц на другие, поскольку поведение цепочек определяется хуками (hook input/forward/output) и типами (type filter). Если определённые типы или хуки фреймворка netfilter не задействованы ни в одной цепочке, то пакеты будут проходить через эти цепочки без обработки. Это отличает nftables от iftables.

Добавление основных таблиц и цепочек

Для примера создадим собственные цепочки и добавим в них минимальный набор правил, необходимый для работы сервера:

Собственные названия цепочек в nftables

Советуем придерживаться оригинальных названий цепочек — это облегчит новому системному администратору работу с файрволом. Далее создадим правила с нуля, чтобы понять, как управлять nftables:

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

nft flush ruleset

Теперь на сервере не работает ни одного правила.

Добавим базовые таблицы и цепочки:

nft add table inet filter
nft add chain inet filter input '{type filter hook input priority filter; policy accept;}'
nft add chain inet filter forward '{type filter hook forward priority filter; policy drop;}'
nft add chain inet filter output '{type filter hook output priority filter; policy accept;}'

Так, мы почти полностью повторили все правила из базовой конфигурации. Но запретили пересылку пакетов, предназначенных не для нашего сервера, дальше по сети (в цепочке forward указали действие для всех пакетов как drop).

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

Создание таблиц и базовых цепочек


Добавление правил

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

  • meta — метасущности, например, интерфейсы:
  oif <интерфейс-отправитель НОМЕР>
  iif <интерфейс-получатель НОМЕР>
  oifname <интерфейс-отправитель ИМЯ>
  iifname <интерфейс-получатель ИМЯ>

(параметры oif и iif принимают строковые значения, которые конвертируются в номер)
(параметры oifname и iifname более гибкие, но они медленнее из-за необходимости выполнять сравнение строк)
  • icmp:
  type <тип icmp>
  • ip:
  daddr <адрес получателя>
  saddr <адрес отправителя>
  • ipv6:
  daddr <адрес получателя>
  saddr <адрес отправителя>
  • tcp:
  dport <порт получателя>
  sport <порт отправителя>
  • udp:
  dport <порт получателя>
  sport <порт отправителя>
  • ct (connection tracking):
  state <new | established | related | invalid>
  • log:
    prefix <дополнительная строка в начале сообщения>
    level <emerg | alert | crit | err | warn [default] | notice | info | debug | audit>

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

  • accept — принять пакет.
  • drop — отбросить пакет.
  • continue — продолжить обработку правил. Если не указать действие в конце правила, то это действие будет работать по умолчанию.
  • return — позволяет вернуть обработку пакета в предыдущую цепочку. Если цепочка базовая, то применяется действие из политики (policy) базовой цепочки.
  • jump CHAIN — перенаправляет обработку пакета в начало другой цепочки CHAIN. То есть текущая оценка пакета будет продолжаться в новой цепочке до вынесения решения/действия (например, accept или drop) или возврата к предыдущей цепочке через return.

Эти списки не исчерпывающие. Но они включают популярные субъекты и действия, которые можно совершить с пакетом после совпадения с правилом.

Разберём создание правил на примере создания базовой конфигурации. Допустим, на сервере нужно обеспечить:

  • беспрепятственную работу служб на сервере с localhost;
  • доступ по SSH;
  • проверку доступности сервера с помощью ping;
  • возможность сервера отвечать на запросы, инициированные локальной системой (например, обновлять пакеты);
  • подключение к сервисам на самом сервере, например, ftp или http/https.

Весь порядок действий выполняют следующие команды:

nft add rule inet filter input iifname "lo" accept comment \"Accept any localhost traffic\”
nft add rule inet filter input tcp dport 22 accept comment \"Accept ssh\"
nft add rule inet filter input icmp type echo-request accept comment \"Accept icmp echo-request\"
nft add rule inet filter input ct state established,related accept comment \"Accept traffic originated from us\"
nft add rule inet filter input tcp dport '{80,443}' accept comment \"Accept http/https \"
nft add inet filter input tcp dport '{20,21,35000-35999}' accept comment \"Accept ftp\"

Допускается указывать конкретное место для вставки правила с помощью оператора add. Для этого нужно узнать его номер — это можно сделать через оператор list и ключ -a:

nft -a list ruleset # Выводит все текущие правила 
nft -a list chain inet filter input # Выводит только правила в цепочке input

Например, если вы указали правило handle 2, то новое правило появится сразу после него:

nft add rule inet filter input handle 2 tcp dport '{80,443}' accept comment \"Accept http/https \"

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

Когда вы добавляете правила с помощью оператора add без указания места, то они по умолчанию записываются в конец цепочки. Если нужно вставить правило в начало или другое конкретное место (например, чтобы оно обрабатывалось раньше), то можно воспользоваться оператором insert. Он позволяет добавлять правило перед тем, что вы укажете в выражении. 

Для примера добавим логирование подключений к ftp и поставим его прямо перед правилом для портов ftp (в нашем случае — handle 11):

nft insert rule inet filter input handle 11 tcp dport 21 ct state new log prefix \"New FTP connection: \"  continue

Если в команде insert не указать место для правила, то оно будет поставлено первым.

Суть этого правила: оно вставляется (insert) в цепочку input таблицы filter (семейство inet) вместо 11 правила, но под другим номером. Правило отбирает новые (ct state new) TCP-соединения на 21-й порт (tcp dport 21), логирует их с префиксом “ New FTP connection: " (log prefix) и передаёт пакет дальше по цепочке (continue).

Сообщения правил log передаются в ядро и посмотреть их можно с помощью journald или dmesg:

Логирование событий в nftables

Порядок обработки правил в этом случае важен. Если добавить правило логирования после правила Accept ftp, то логирования не произойдёт — пакет уже будет принят и передан ftp предыдущим правилом.

Изменение политики для цепочки

После добавления правил можно заблокировать доступ к серверу для остальных портов и служб, которые не попали в правила, указав политику drop. Nftables будет работать по принципу «запрещено всё, что не разрешено явно».

nft chain inet filter input '{type filter hook input priority filter; policy drop;}'

Очень важно менять политику цепочки в последнюю очередь. Если вы не успели указать доступ по SSH в разрешённые правила или ошибочно ограничили доступ с определённого хоста (например, через saddr), и ваш текущий хост в него не входит, то сервер сразу разорвёт соединение. В этом случае поможет перезагрузка сервера (при загрузке прочитаются правила из /etc/nftables.conf) или сброс правил через команды по vnc:

nft flush ruleset # Сброс всех правил
nft -f /etc/nftables.conf # Чтение последней рабочей конфигурации
systemctl restart nftables.service # Можно и так перечитать из /etc/nftables.conf

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

*/15 * * * * /usr/sbin/nft -f /etc/nftables.conf

Таким образом правила будут загружаться из конфигурации по умолчанию в nftables каждые 15 минут. Если доступ пропадёт, можно просто подождать, пока сработает задание на загрузку правил.

Если правила были значительно изменены, и вы не хотите их перезаписать старыми из конфигурации, то можно изменить сам файл загрузки (/etc/nftables.conf) на другой или создать предварительно файл с рабочей конфигурацией файрвола в любом другом каталоге ОС с указанием в задаче cron.

Сохранение правил

В команде cron видно, как загружаются правила из конфигурации. Сохранение в файл происходит в два шага: сначала добавляется строка команды flush ruleset (через утилиту echo), и только потом правила записываются через утилиту nft.
Поэтому для сохранения правил нужно использовать команды:

echo "flush ruleset" > /путь/до/конфигурации
nft -s list ruleset >> /путь/до/конфигурации

Без flush ruleset правила добавляются к текущей конфигурации, не перезаписывая их полностью, что может привести к проблемам.
Сейчас правила, которые мы добавляли ранее, в nftables выглядят так:

Правила nftables после всех настроек

Изменение правила

Если вы ошиблись или нужно изменить добавленное правило, это можно сделать через оператор replace. Допустим, мы хотим расширить возможный диапазон пассивных портов для ftp (порты 35000-35999). В iptables пришлось бы сначала удалять правило и добавлять новое. Желательно — на то же место, если их порядок имеет значение в контексте текущей конфигурации на сервере. 

Для примера изменим диапазон, добавив порты до 36999. Это можно сделать с помощью  команды:

nft replace rule inet filter input handle 11 tcp dport '{ 20-21, 35000-36999 }' accept comment \"New accept ftp\"
Изменения правила с помощью replace

Удаление правил

Допустим, необходимо «отключить» службу ftp или вы просто хотите запретить к ней доступ. Тогда нужно удалить соответствующее правило. 

В нашем случае команда для удаления правил ftp будет такой:

nft delete rule inet filter input handle 17
Удаление правила с помощью delete

Множества

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

Наборы могут быть как именованные, так и анонимные. 

Анонимные лучше использовать, когда точно известен набор элементов, с которым вы хотите работать, поскольку для добавления нового элемента придётся полностью менять правило. В примерах мы уже использовали анонимные множества при добавлении правил, но не акцентировали на них внимание. Пример — конструкции вида “{20-21, 35000-36999}” или “{80,443}” в правилах. 

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

Создадим набор с любым названием, например, blackhole, в который будем добавлять подсети:

nft add set inet filter blackhole '{type ipv4_addr; flags interval; comment "drop all packets from these hosts";}'

Обратите внимание на необязательную опцию flags interval — с её помощью можно будет указать подсети. Если этого не сделать, будет возможность только добавления отдельных адресов.

Добавим туда приватные подсети:

nft add element inet filter blackhole {10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16}

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

Добавление множества blackhole в nftables

Пока мы определились только с элементами, с которыми хотим работать, но не указали, что нужно с ними делать. Поэтому добавим логирование и блокировку пакетов с этих адресов из blackhole:

nft insert rule inet filter input ip saddr @blackhole drop
nft insert rule inet filter input ip saddr @blackhole ct state new log prefix \"New connection in blackhole: \" continue

Обратите внимание. Мы добавили правила через insert, чтобы поместить их в начало цепочки. Это нужно, чтобы сначала заблокировать все пакеты и подключения из множества. Иначе бы эти правила не сработали — их бы перекрыли правила для SSH, http/https и FTP, которые открывают доступ со всех хостов, и они обрабатывались бы первыми.

Теперь попробуем подключиться из приватной сети по SSH, FTP и выполнить запросы ping. В логах сервера все такие подключения будут детально записаны с указанием типа (ICMP или конкретный порт).

Логирование и работа правил для множества blackhole

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

nft delete rule inet filter input handle 23
nft delete rule inet filter input handle 24
nft delete set inet filter blackhole
Удаление множества blackhole

Шпаргалка

КомандаНазначение

Работа со службой

systemctl enable nftables.serviceдобавление в автозагрузку
systemctl start nftables.serviceзапуск службы
systemctl restart nftables.serviceперезапуск службы
Работа с конфигурацией
nft [-a] list rulesetпросмотр текущих правил
nft [-a] list chain FAMILY TABLE CHAIN_NAMEпросмотр текущих правил для цепочки CHAIN_NAME
nft flush rulesetсброс всех текущих правил
nft -f /etc/nftables.confзагрузка правил из файла

echo "flush ruleset" > /путь/до/конфигурации

nft -s list ruleset >> /путь/до/конфигурации

создание файла с правилами
Работа с таблицами и цепочками
nft add table FAMILY TABLE_NAMEсоздание таблицы TABLE_NAME с семейством FAMILY (ip, ip6, inet, erp, bridge, netdev)
nft add chain FAMILY TABLE_NAME CHAIN_NAME '{type TYPE hook HOOK priority PRIORITY; policy POLICY;}'создание базовой цепочки CHAIN_NAME с хуком HOOK (prerouting, input, forward, output или postrouting) с типом TYPE (filter, route или nat) и политикой POLICY
nft chain FAMILY TABLE_NAME CHAIN_NAME '{ [ type TYPE hook HOOK priority PRIORITY ; policy POLICY ; ] }'изменение цепочки (обратите внимание: отсутствует оператор add)
nft delete chain FAMILY TABLE_NAME CHAIN_NAMEудаление цепочки CHAIN_NAME из таблицы TABLE_NAME
nft flush chain FAMILY TABLE_NAME CHAIN_NAMEочистка всех правил в цепочке CHAIN_NAME и таблице TABLE_NAME
nft flush table TABLE_NAMEудаление таблицы TABLE_NAME

Работа с правилами

nft add rule FAMILY TABLE_NAME CHAIN_NAME <handle HANDLE> RULE ACTIONдобавление правила RULE после номера HANDLE  в цепочку CHAIN_NAME таблицы TABLE_NAME с действием ACTION (accept, drop, continue, return, jump CHAIN_NAME)
nft insert rule FAMILY TABLE_NAME CHAIN_NAME <handle HANDLE> RULE ACTIONвставка правила RULE вместо номера HANDLE в цепочку CHAIN_NAME таблицы TABLE_NAME с действием ACTION
nft replace rule FAMILY TABLE_NAME CHAIN_NAME handle HANDLE RULE ACTIONизменение правила RULE под номером HANDLE в цепочке CHAIN_NAME таблицы TABLE_NAME с действием ACTION
nft delete rule FAMILY TABLE_NAME CHAIN_NAME handle HANDLEудаление конкретного правила RULE под номером HANDLE из цепочки CHAIN_NAME таблицы TABLE_NAME

Работа с множествами

nft add set FAMILY TABLE_NAME SET_NAME '{type TYPE; <flags FLAGS;> <comment "COMMENT";>}'добавление множества SET_NAME в таблицу TABLE_NAME с типом TYPE (ipv4_addr, ipv6_addr, ether_addr, inet_proto, inet_service, mark), флагами FLAGS (constant, dynamic, interval, timeout) и комментарием COMMENT
nft add element FAMILY TABLE_NAME SET_NAME {ELEMENT_1, ELEMENT_2,...}добавление элементов ELEMENT_1, ELEMENT_2 во множество SET_NAME
nft delete element FAMILY TABLE_NAME SET_NAME {ELEMENT_1, ELEMENT_2,...}удаление элементов ELEMENT_1, ELEMENT_2 во множество SET_NAME
nft delete set FAMILY TABLE_NAME SET_NAMEудаление множества SET_NAME из таблицы TABLE_NAME

Примеры

nft add chain inet filter input '{type filter hook input priority filter; policy accept;}'добавление базовой цепочки input
nft add rule inet filter input iifname "lo" accept commentразрешить loopback
nft add rule inet filter input tcp dport PORT acceptразрешить подключение tcp к порту PORT
nft add rule inet filter input udp dport PORT acceptразрешить подключение udp к порту PORT
nft add rule inet filter input ip saddr ADDRESS tcp dport PORT dropзапретить подключение к порту PORT с адреса ADDRESS (допускается указывать подсеть с маской)
nft add rule inet filter input ip saddr ADDRESS dropполностью запретить все подключения с адреса ADDRESS (допускается указывать подсеть с маской)
nft add rule inet filter input icmp type echo-request acceptразрешить эхо-запросы icmp
nft add rule inet filter input ct state established,related accept разрешить отвечать на запросы, инициированные локальной системой
nft add rule inet filter input tcp dport '{80,443}' acceptразрешить http и https
nft insert rule inet filter input handle HANDLE tcp dport PORT ct state new log prefix \"STRING\"  continueвставить правило логирования новых подключений к порту PORT вместо HANDLE со строкой STRING
nft add rule inet filter input tcp dport '{ PORT_START-PORT_FINISH}' acceptразрешить подключения tcp к портам из диапазона  PORT_START-PORT_FINISH (допускается указывать несколько диапазонов через запятую)
nft add set inet filter blackhole '{type ipv4_addr; flags interval; comment "drop all packets from these hosts";}'создание множества blackhole для добавления в него подсетей
nft add element inet filter blackhole {10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16}добавление приватных подсетей во множество blackhole
nft insert rule inet filter input ip saddr @blackhole dropзапретить все подключения из множества blackhole
nft add set inet filter blackhole_port '{type inet_service; flags interval; comment "drop all packets from these hosts";}'создание множества blackhole_port для добавления в него портов
nft add element inet filter blackhole_port {PORT_START-PORT_FINISH}добавление диапазона портов PORT_START-PORT_FINISH во множество blackhole_port
nft insert rule inet filter input tcp dport @blackhole_port ip saddr @blackhole dropзапрет на доступ к портам из множества blackhole_port c адресов из множества blackhole

Этот материал был полезен?

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