Прозрачный межсетевой экран с nftables и VLAN

Я хочу попросить вас совета передового опыта в прозрачной сборке брандмауэра.

У меня есть 2 сегмента сети и CentOS serv с 2 интерфейсами 10G. Я хочу фильтровать / отслеживать / ограничивать / отбрасывать трафик между сегментами. Трафик помечен. Должен ли я разархивировать трафик для фильтрации и вернуть его обратно, или nftable сможет обработать его с тегами?

Теперь схема выглядит так:

PCs--|                                         |--PCs
PCs--|--untag--[Switch]--tag--[Switch]--untag--|--PCs
PCs--|                                         |--PCs

Я хочу:

PCs--|                                                              |--PCs
PCs--|--untag--[Switch]--tag--**[Firewall]**--tag--[Switch]--untag--|--PCs
PCs--|                                                              |--PCs

1 ответ

TL;DR: nftables на уровне моста может нормально обрабатывать как тегированные, так и нетегированные пакеты, используя немного другие правила. Всю работу с тегами можно выполнить на стороне Linux, создав мост с поддержкой vlan, поэтому не нужно менять конфигурацию на коммутаторах, независимо от того, какой выбор был сделан в брандмауэре для nftables.

В этой серии блогов можно найти много интересной документации по тестированию VLAN (особенно часть IV, даже если некоторые сведения могут быть не совсем точными):

Развлекайтесь с veth-устройствами, мостами Linux и виртуальными локальными сетями в безымянных сетевых пространствах имен I II III IV V VI VII VIII

Давайте поместим две минималистичные модели брандмауэра (в пространство имен сети). trunk100 а также trunk200 связаны с двумя коммутаторами, отправляющими помеченные пакеты vlan 100 с левых компьютеров, и помеченные пакеты vlan 200 с правых компьютеров. Обратите внимание, что здесь тегам VLAN явно разрешено появляться на другой стороне либо путем создания подчиненного интерфейса с идентификатором VLAN другой стороны, либо путем непосредственного добавления идентификатора VLAN другой стороны к интерфейсу транка.

  1. подинтерфейсы vlan, помещающие непомеченные пакеты в мост

    ip link add fw0 type bridge vlan_filtering 1
    ip link set fw0 up
    for trunk in 100 200; do
        for vlan in 100 200; do
            ip link add link trunk$trunk name trunk$trunk.$vlan type vlan id $vlan
            ip link set trunk$trunk.$vlan master fw0
            bridge vlan add vid $vlan pvid untagged dev trunk$trunk.$vlan
            bridge vlan del vid 1 dev trunk$trunk.$vlan
            ip link set trunk$trunk.$vlan up
        done
    done
    bridge vlan del vid 1 dev fw0 self
    

    В этом случае помеченные пакеты, поступающие через trunk100 и trunk200, разделяются на подинтерфейсы для каждого vlan, и пакеты не маркируются. Мост все еще осведомлен об используемых VLAN и применяет фильтрацию VLAN на источниках и адресатах. nft добавит свои ограничения. Исходящие пакеты будут повторно помечены, как только они поступят на интерфейс родительского транка.

  2. помеченные пакеты прямо в мост

    ip link add fw0 type bridge vlan_filtering 1
    ip link set fw0 up
    for trunk in 100 200; do
        ip link set trunk$trunk master fw0
        for vlan in 100 200; do
            bridge vlan add vid $vlan tagged dev trunk$trunk
        done
        bridge vlan del vid 1 dev trunk$trunk
        ip link set trunk$trunk up
    done
    bridge vlan del vid 1 dev fw0 self
    

В этом более простом случае помеченные пакеты пересекают мост, сохраняя свой тег vlan.

Вот один набор правил nftables, показывающий, как обрабатываются оба случая. iifname был выбран здесь вместо iif поэтому один и тот же набор правил может работать в обоих случаях (без ошибки из-за отсутствия интерфейса). Обычно iif должно быть предпочтительным. Есть дополнительные записи счетчика, чтобы проверить, что именно соответствовало или не совпадало (с nft list ruleset -a):

#!/usr/sbin/nft -f

flush ruleset

table bridge filter {
    chain input {
        type filter hook input priority -200; policy drop;
    }

    chain forward {
        type filter hook forward priority -200; policy drop;
        counter
        arp operation request counter
        arp operation reply counter
        vlan type arp arp operation request counter
        vlan type arp arp operation reply counter
        arp operation request counter accept
        arp operation reply counter accept
        vlan type arp arp operation request counter accept
        vlan type arp arp operation reply counter accept
        ip protocol icmp icmp type echo-request counter
        ip protocol icmp icmp type echo-reply counter
        vlan type ip icmp type echo-request counter
        vlan type ip icmp type echo-reply counter
        iifname trunk100.100 ip protocol icmp icmp type echo-request counter accept
        oifname trunk100.200 ip protocol icmp icmp type echo-reply counter accept
        vlan id 100 vlan type ip icmp type echo-request counter accept
        vlan id 200 vlan type ip icmp type echo-reply counter accept
    }

    chain output {
        type filter hook output priority 200; policy drop;
    }
}

Обратите внимание, что эти правила могли быть написаны еще более подробно. Пример:

iifname "trunk100.100" ether type ip ip protocol icmp icmp type echo-request

или же

ether type vlan vlan id 200 vlan type ip ip protocol icmp icmp type echo-reply

Когда используется первая настройка (нетегированные пакеты через подчиненные интерфейсы), будут соответствовать только классические правила. Когда используется вторая настройка, будут совпадать только правила, явно использующие vlan. Таким образом, этот набор двойных правил, разрешающий базовое разрешение ARP, а также позволяющий VLAN 100 проверять связь с VLAN 200, но не наоборот, будет работать в обоих случаях.

Этот набор правил должен работать при использовании с CentOS nftables v0.6 (не тестировалась на ядре CentOS) или с текущими nftables v0.8.3.

Текущие известные ограничения:

Nftables с v0.8.3 не может использовать conntrack так, как это было возможно с взаимодействиями ebtables / iptables. Похоже, есть планы по этому поводу, см. Этот PDF: фильтрация моста с помощью nftables. Так что это очень усложняет реализацию правил с сохранением состояния.

Также обратите внимание, что nftables по-прежнему (на 0.8.3) имеет проблемы с отображением: nft list ruleset -a упадет vlan из "декомпилированных" правил, если ни один из его параметров не используется. Пример, эти два правила:

nft add rule bridge filter forward ip protocol icmp counter
nft add rule bridge filter forward vlan type ip ip protocol icmp counter

Когда отображается обратно с nft list ruleset -a (V0.8.3):

        ip protocol icmp counter packets 0 bytes 0 # handle 23
        ip protocol icmp counter packets 0 bytes 0 # handle 24

Это только с nft --debug=netlink list ruleset -a это сбросит байт-код, и станет ясно, что это действительно два разных правила (данные представлены в порядке с прямым порядком байтов):

bridge filter forward 23 22 
  [ payload load 2b @ link header + 12 => reg 1 ]
  [ cmp eq reg 1 0x00000008 ]
  [ payload load 1b @ network header + 9 => reg 1 ]
  [ cmp eq reg 1 0x00000001 ]
  [ counter pkts 0 bytes 0 ]

bridge filter forward 24 23 
  [ payload load 2b @ link header + 12 => reg 1 ]
  [ cmp eq reg 1 0x00000081 ]
  [ payload load 2b @ link header + 16 => reg 1 ]
  [ cmp eq reg 1 0x00000008 ]
  [ payload load 1b @ network header + 9 => reg 1 ]
  [ cmp eq reg 1 0x00000001 ]
  [ counter pkts 0 bytes 0 ]

CentOS v0.6 (протестировано на ядре 4.15) также имеет свои собственные проблемы с декомпиляцией:

ip protocol icmp icmp type echo-request

отображается как:

icmp type echo-request counter

который делает синтаксическую ошибку при попытке, как в v0.6 (но хорошо в v0.8.3).

Другие вопросы по тегам