Firewall transparente com nftables e VLANs

3

Eu quero pedir conselhos sobre práticas recomendadas na criação de firewalls transparentes.

Eu tenho 2 segmentos de rede e o serviço CentOS com 2 interfaces 10G. Quero filtrar / monitorar / limitar / descartar tráfego entre segmentos. O tráfego está marcado. Devo desviar o tráfego para filtragem e etiquetá-lo de volta ou impossível manipulá-lo marcado?

Agora o esquema se parece com:

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

Eu quero:

PCs--|                                                              |--PCs
PCs--|--untag--[Switch]--tag--**[Firewall]**--tag--[Switch]--untag--|--PCs
PCs--|                                                              |--PCs
    
por Severgun 29.06.2017 / 15:04

1 resposta

2

TL; DR: nftables, no nível da ponte, pode lidar bem com pacotes marcados ou não marcados, usando regras ligeiramente diferentes. Todo o trabalho de marcação pode ser feito no lado do Linux, fazendo com uma ponte com reconhecimento de vlan, portanto, nenhuma mudança de configuração é necessária nos switches, seja qual for a escolha feita no firewall para nftables.

Muita documentação interessante sobre o teste de VLANs pode ser encontrada nesta série de blogs (especialmente parte IV, mesmo que algumas informações possam não ser totalmente precisas):

Fun with veth-devices, Linux bridges and VLANs in unnamed Linux network namespaces I II III IV V VI VII VIII

Vamos colocar dois modelos minimalistas do firewall (em um namespace de rede). trunk100 e trunk200 estão vinculados aos dois switches enviando pacotes marcados com vlan 100 dos computadores à esquerda e pacotes com vlan 200 marcados dos computadores à direita. Observe que aqui as tags de VLANs podem ser explicitamente exibidas no outro lado, seja criando uma subinterface com o ID de VLAN do outro, seja adicionando diretamente o ID de VLAN do outro lado à interface de tronco.

  1. sub-interfaces vlan colocando pacotes não marcados na bridge

    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
    

    Neste caso, os pacotes marcados que chegam através do trunk100 e do trunk200 são divididos em subinterfaces por vlan e os pacotes não são marcados. A ponte ainda está ciente das VLANs em uso e está aplicando a filtragem de vlan em fontes e destinos. nft adicionará suas próprias restrições. Os pacotes de saída serão retagulados assim que chegarem na interface de tronco pai.

  2. marcou pacotes diretamente na ponte

    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
    

Para este caso mais simples, os pacotes marcados atravessam a ponte enquanto retêm sua tag vlan.

Aqui está um único conjunto de regras nftables mostrando como ambos os casos são tratados. iifname foi escolhido aqui em vez de iif , então o mesmo conjunto de regras pode funcionar nos dois casos (sem ter um erro devido a uma interface ausente). Normalmente, iif deve ser preferido. Há entradas adicionais no contador apenas para verificar o que exatamente correspondeu ou não (com 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;
    }
}

Observe que essas regras poderiam ter sido escritas ainda mais detalhadamente. Exemplo:

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

ou

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

Quando a primeira configuração estiver em uso (pacotes não marcados através de subinterfaces), somente as regras clássicas serão correspondentes. Quando a segunda configuração estiver em uso, apenas as regras explicitamente usando vlan corresponderão. Portanto, este conjunto de regras duplas, permitindo a resolução ARP básica, bem como permitir que a VLAN 100 faça o ping da VLAN 200, mas não o contrário, funcionará em ambos os casos.

Esse conjunto de regras deve estar funcionando quando usado com os nftables v0.6 do CentOS (não testado no kernel do CentOS) ou com os nftables atuais v0.8.3.

Limitações atuais conhecidas:

Os nftables da v0.8.3 não podem usar conntrack da maneira que era possível com interações de ebtables / iptables. Parece que há planos sobre isso, veja este PDF: filtragem de ponte com nftables . Então, isso torna as regras de estado muito difíceis de implementar.

Note também que o nftables ainda tem (a partir de 0.8.3) problemas de exibição: nft list ruleset -a cairá vlan das regras "descompiladas" se nenhuma das suas opções forem usadas. Exemplo, essas duas regras:

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

Quando exibido de volta com 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

É somente com nft --debug=netlink list ruleset -a que vai despejar o bytecode, que está claro que essas são de fato duas regras diferentes (os dados estão aqui em little endian):

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 ]

O CentOS 'v0.6 (testado no kernel 4.15) também tem seus próprios problemas de exibição "decompile":

ip protocol icmp icmp type echo-request

é exibido como:

icmp type echo-request counter

que faz um erro de sintaxe se tentado como está na v0.6 (mas está bem na v0.8.3).

    
por 06.04.2018 / 22:42