nftables: проверка правил firewall в изолированном netns без риска потерять доступ

0
8
Обложка статьи: nftables: проверка правил firewall в изолированном netns без риска потерять доступ

Правила firewall опасны тем, что ошибка проявляется как потеря доступа к серверу, а исправить её можно только с консоли. Проверять правила сразу на рабочей машине рискованно, а чтение конфигурации глазами не гарантирует, что разрешённое действительно работает, а запрещённое запрещено. Решение: изолированное сетевое пространство имён (network namespace, netns). В нём можно создать «сервер» и «клиента», применить правила, послать реальные соединения и посмотреть результат, не затрагивая сеть хоста. Ниже набор правил, скрипт проверки и порядок переноса на рабочий сервер.

Статья опирается на логику направления «Сетевая безопасность» из методики зрелости Группы Сбер (источник); это методика для крупных компаний, мы используем её как ориентир и пересказываем своими словами. Проверка выполнена на Debian 12, nftables 1.0.6, ядро 6.1: скрипт выполнялся на сервере, после него не осталось ни пространств имён, ни виртуальных интерфейсов, а правила хоста не менялись. Основы nftables: firewall в Linux.

Что должно получиться

Уровень Что это значит на практике
2. Гигиенический Сеть сегментирована, правила firewall пересматриваются и проверяются, а не только пишутся

Критерии сформулированы нами по мотивам методики, это ориентир, а не оценка соответствия.

Идея: два пространства имён и виртуальный кабель

Сетевое пространство имён — изолированный набор интерфейсов, таблиц маршрутизации и правил firewall. Правила, загруженные внутри пространства, не влияют на хост. Схема проверки: пространство zsrv (проверяемый «сервер» с адресом 10.99.0.1), пространство zcli (клиент 10.99.0.2) и пара виртуальных интерфейсов veth между ними. На «сервере» запускаются простые слушатели на портах 22, 80 и 8080, на нём же применяются правила; «клиент» пытается подключиться.

Набор правил

Файл /etc/nftables.conf: политика «запрещено всё, кроме разрешённого», лимиты и набор заблокированных адресов, изменяемый на ходу.

#!/usr/sbin/nft -f
# /etc/nftables.conf: пример набора правил для сервера (политика «запрещено всё, кроме разрешённого»)
flush ruleset

table inet filter {
    # адреса и сети, с которых соединения запрещены (изменяется на ходу командой nft add/delete element)
    set blocked4 {
        type ipv4_addr
        flags interval
        elements = { 198.51.100.0/24 }
    }

    chain input {
        type filter hook input priority 0; policy drop;

        iif lo accept
        ct state invalid drop
        ct state established,related accept

        ip saddr @blocked4 counter drop

        # ping: не чаще 5 в секунду
        icmp type echo-request limit rate 5/second burst 10 packets accept

        # SSH: не более 3 новых соединений в минуту с одного адреса (ограничение подбора)
        tcp dport 22 ct state new meter ssh-new { ip saddr limit rate 3/minute burst 3 packets } accept

        # веб
        tcp dport { 80, 443 } accept

        # всё остальное считаем и отбрасываем по политике
        counter
    }

    chain forward {
        type filter hook forward priority 0; policy drop;
    }

    chain output {
        type filter hook output priority 0; policy accept;
    }
}
Правило Что делает
policy drop в цепочке input Всё входящее запрещено, если не разрешено явно
ct state established,related accept Разрешает ответы на исходящие соединения сервера
ip saddr @blocked4 counter drop Отбрасывает пакеты от адресов из набора и считает их
icmp ... limit rate 5/second Ограничивает частоту ping
meter ssh-new { ip saddr limit rate 3/minute burst 3 packets } Не более трёх новых соединений в минуту с одного адреса на порт 22 (замедляет подбор пароля)
tcp dport { 80, 443 } accept Разрешает веб
итоговый counter Считает отбрасываемые пакеты политикой по умолчанию

Порт 8080 в наборе намеренно не разрешён: в тесте это «служба, которая не должна быть доступна снаружи», и политика по умолчанию должна её закрыть.

Скрипт проверки

Запускайте от root. Скрипт создаёт пространства и интерфейсы с именами zsrv, zcli и zveth0/1, а в конце, в том числе при ошибке, удаляет их и останавливает слушатели. Файл с правилами положите рядом как /tmp/nft_ruleset.nft.

#!/bin/bash
set -u
NS_S=zsrv; NS_C=zcli
cleanup() { ip netns pids $NS_S 2>/dev/null | xargs -r kill 2>/dev/null; ip netns del $NS_S 2>/dev/null; ip netns del $NS_C 2>/dev/null; }
trap cleanup EXIT
cleanup
ip netns add $NS_S; ip netns add $NS_C
ip link add zveth0 type veth peer name zveth1
ip link set zveth0 netns $NS_S; ip link set zveth1 netns $NS_C
ip -n $NS_S addr add 10.99.0.1/24 dev zveth0; ip -n $NS_S link set zveth0 up; ip -n $NS_S link set lo up
ip -n $NS_C addr add 10.99.0.2/24 dev zveth1; ip -n $NS_C link set zveth1 up
for p in 22 80 8080; do ip netns exec $NS_S python3 -m http.server $p --bind 10.99.0.1 >/dev/null 2>&1 & done
sleep 1
echo "=== без правил"
ip netns exec $NS_C curl -s -o /dev/null -m 2 -w "port 8080 http=%{http_code}\n" http://10.99.0.1:8080/
echo "=== проверка синтаксиса"
ip netns exec $NS_S nft -c -f /tmp/nft_ruleset.nft && echo syntax-ok
echo "=== применяем правила в netns сервера"
ip netns exec $NS_S nft -f /tmp/nft_ruleset.nft && echo applied
sleep 1
echo "--- 80 (разрешён)"; ip netns exec $NS_C curl -s -o /dev/null -m 3 -w "http=%{http_code}\n" http://10.99.0.1:80/
echo "--- 8080 (не разрешён, ожидаем таймаут)"; ip netns exec $NS_C curl -s -o /dev/null -m 2 -w "http=%{http_code}\n" http://10.99.0.1:8080/; echo "curl exit=$? (28 = таймаут)"
echo "--- ping x3"; ip netns exec $NS_C ping -c 3 -W 1 -q 10.99.0.1 | tail -2
echo "--- SSH-порт: 6 быстрых новых соединений подряд"
ok=0; fail=0; for i in 1 2 3 4 5 6; do if ip netns exec $NS_C curl -s -o /dev/null -m 1 http://10.99.0.1:22/; then ok=$((ok+1)); else fail=$((fail+1)); fi; done; echo "успешных=$ok отброшенных=$fail"
echo "--- блокировка адреса клиента через набор"
ip netns exec $NS_S nft add element inet filter blocked4 { 10.99.0.2 }
ip netns exec $NS_C curl -s -o /dev/null -m 2 -w "80 после блокировки: http=%{http_code}\n" http://10.99.0.1:80/; echo "curl exit=$?"
ip netns exec $NS_S nft delete element inet filter blocked4 { 10.99.0.2 }
ip netns exec $NS_C curl -s -o /dev/null -m 3 -w "80 после снятия блокировки: http=%{http_code}\n" http://10.99.0.1:80/
echo "--- счётчики"
ip netns exec $NS_S nft list ruleset | grep -E "counter|elements"
echo "--- набор"
ip netns exec $NS_S nft list set inet filter blocked4

Ожидаемый результат

Проверка Что должно быть
Порт 8080 без правил http=200 (служба работает)
nft -c -f syntax-ok: синтаксис правильный
Порт 80 после применения правил http=200
Порт 8080 после применения правил http=000, код curl 28 (таймаут): пакеты отброшены молча
Ping 3 раза 0% потерь (лимит 5 в секунду не превышен)
6 быстрых соединений на порт 22 успешных 3, отброшенных 3: сработало ограничение
Адрес клиента добавлен в blocked4 порт 80 даёт таймаут; после nft delete element снова http=200
nft list ruleset Счётчики: у правила блокировки 2 пакета, у итогового правила 5 (это отброшенные запросы к 8080)

Именно так выглядел вывод на проверке. Если что-то отличается, ошибка в правилах, и вы нашли её без вреда для сервера.

Перенос на рабочий сервер без потери доступа

  1. Откройте запасную сессию SSH и не закрывайте её. Подготовьте доступ с консоли гипервизора.
  2. Убедитесь, что порт SSH разрешён в вашем наборе правил и что порт совпадает с настоящим (в примере 22). Если вы подключаетесь с адреса, который не должен попадать под лимит, добавьте разрешение для адресов администраторов до правила с лимитом.
  3. Проверьте синтаксис: sudo nft -c -f /etc/nftables.conf.
  4. Сохраните текущие правила: sudo nft list ruleset > /root/nft.before.
  5. Примените с автоматическим откатом. Запланируйте возврат прежних правил через две минуты, затем примените новые:
    sudo systemd-run --on-active=2min --unit=nft-rollback /usr/sbin/nft -f /root/nft.before
    sudo nft -f /etc/nftables.conf

    Если всё работает и вы остались подключены, отмените откат: sudo systemctl stop nft-rollback.timer.

  6. Включите автозагрузку: sudo systemctl enable --now nftables (служба читает /etc/nftables.conf).
  7. Проверьте извне реальные порты по плану тестов: что открыто, то работает, что закрыто, не отвечает.

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

Управление набором на ходу

sudo nft add element inet filter blocked4 { 203.0.113.50 }
sudo nft delete element inet filter blocked4 { 203.0.113.50 }
sudo nft list set inet filter blocked4

Набор позволяет блокировать адреса без перезагрузки правил: его можно наполнять автоматикой, например из CrowdSec и Fail2ban. Добавленные таким образом элементы пропадают после перезагрузки, если не записать их в файл правил.

Диагностика

Симптом Причина и что делать
Скрипт не создаёт пространства имён Нет прав root или не установлен пакет iproute2. Запускайте от root, проверьте команду ip netns
nft -c сообщает об ошибке синтаксиса Исправьте указанную строку; для набора с flags interval элементы с диапазоном должны быть в формате сети или диапазона
Все проверки дают таймаут Не разрешён ct state established или слушатели не запущены. Проверьте nft list ruleset и ss -ltn в пространстве сервера
Лимит SSH срабатывает слишком рано на рабочем сервере Один адрес (общий NAT) создаёт много соединений. Увеличьте burst или разрешите адреса администраторов выше правила
После применения пропал доступ Откройте запасную сессию или консоль; сработает автоматический откат; проверьте разрешение порта SSH

Где это в модели зрелости

Материал относится к направлению «Сетевая безопасность» (материалы направления, карта зрелости). Уровень 2 требует, чтобы правила firewall пересматривались и контролировались: воспроизводимая проверка правил в изолированной среде делает пересмотр безопасным.

Как проверить

  1. Скрипт проверки выполняется без ошибок, ожидаемые результаты совпадают с таблицей.
  2. После скрипта на хосте нет остатков: ip netns list пуст, интерфейсов zveth* нет.
  3. Правила на рабочем сервере применены с откатом, порты проверены извне.
  4. Набор правил хранится в репозитории или журнале изменений, проверка выполняется при каждом изменении.

Источники

  • Методика оценки уровня зрелости кибербезопасности компании, Группа Сбер: sberbank.ru.
  • Документация nftables (Wiki проекта netfilter): wiki.nftables.org; руководство man ip-netns.
  • NIST SP 800-41 Rev. 1, Guidelines on Firewalls and Firewall Policy: csrc.nist.gov. Международная практика, не российский норматив.

Оставьте свой ответ