Hlavní navigace

nftables: příklad konfigurace firewallu a vzorové situace

14. 1. 2021
Doba čtení: 4 minuty

Sdílet

 Autor: Depositphotos
Linuxový firewall iptables je tu s námi téměř dvacet let, ale je postupně nahrazován novým moderním řešením zvaným nftables. Dnes propojíme dříve předvedené znalosti a postavíme si firewall.

V předchozích dílech našeho seriálu o nftables jsme probrali hlavní vlastnosti tohoto moderního linuxového firewallu. Už víme, jak vytvářet tabulky, přidávat do nich pravidla a podle nich provádět běžné akce. Dnes si ukážeme, jak to všechno propojit dohromady a vytvořit si konfiguraci pro firewall.

Vše budeme demonstrovat na několika vzorových situacích, se kterými se můžete v praxi setkat. Každé nasazení Linuxu má svá specifika a tomu musíme přizpůsobit i konfiguraci firewallu.

Je třeba také vědět, kam máme pravidla do systému ukládat, aby byla automaticky načtena při startu. Obvykle to zajišťuje služba nftables.service a v příslušném unit souboru je také možné se dozvědět, jak vypadá standardní cesta ke konfiguraci. V Debianu je to /etc/nftables.conf a tam bychom také měli nastavení zapisovat.

Následující příklady počítají s konfigurací pro IPv4 a IPv6 zároveň. Jednak by to dnes měla být samozřejmost, ale především nás to s nftables nestojí téměř žádné úsilí navíc. Pokud použijeme tabulku z rodiny inet, můžeme stejnými pravidly pokrýt oba světy.

Pracovní stanice

U běžného koncového pracovního stroje chceme povolit komunikaci směrem ven a omezit to, co může přicházet směrem k nám. Obvykle chceme povolit jen odpovědi na námi vytvořený provoz a ICMP pakety.

V následujícím příkladu tedy vytvoříme hooky pro řetězce input, forward a output. To podstatné se bude nacházet v řetězci input, ve kterém budeme vše nepovolené zahazovat. Poté zajistíme zahození neplatných paketů hned na začátku, následuje povolení paketů náležících k existujícímu spojení a provoz z loopbacku. Poté povolíme ICMP a ICPv6 s limitem 10 paketů za sekundu.

Protože naše stanice nefunguje jako router, budeme automaticky zahazovat vše v řetězci forward a navíc si zapneme počítadlo, abychom věděli, kolik toho případně zahazujeme.

Naopak v řetězci outout povolíme veškerý provoz z naší stanice a také ho můžeme volitelně počítat. Pokud bychom nepotřebovali záznamy, můžeme tuto část úplně vynechat, protože výchozí politika je vždy accept.

table inet filter {
    chain input {
        type filter hook input priority 0; policy drop;
        ct state invalid counter drop
        ct state {established, related} counter accept
        iifname "lo" accept
        meta l4proto icmp meta nfproto ipv4 \
            limit rate 10/second accept
        meta l4proto ipv6-icmp meta nfproto ipv6 \
            limit rate 10/second accept
    }

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

    chain output {
        type filter hook output priority 0; policy accept;
        counter
    }
}

Server

Na server máme jiné požadavky, protože ten musí na vybraných portech poskytovat služby. Kromě toho bychom často některé porty chtěli otevřít jen pro určité rozsahy IP adres. Opět nechceme přeposílat žádný provoz a volitelně můžeme také filtrovat vlastní výstup.

Důležité také je, aby náš server správně reagoval na traceroute, tedy aby správně odmítal pakety na UDP portech 33434–33499. Podle slušného odmítnutí utilita náš stroj detekuje a vypíše správné informace. Pokud bychom pakety potichu zahazovali, skončí detekce jen nekonečnou řadou hvězdiček, protože odpověď nikdy nedorazí.

define ADMIN_IP = {
    192.0.2.0/24,
    198.51.100.0/24,
    2001:db8::/32
}

table inet firewall {
    chain input {
        type filter hook input priority 0; policy drop;
        ct state invalid counter drop
        ct state {established, related} counter accept
        iifname "lo" accept
        meta l4proto icmp meta nfproto ipv4 \
            limit rate 10/second accept
        meta l4proto ipv6-icmp meta nfproto ipv6 \
            limit rate 10/second accept
        tcp dport { http, https } accept
        tcp dport { ssh } ip saddr $ADMIN_IP accept
        udp dport { 33434-33499 } reject
    }

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

    chain output {
        type filter hook output priority 0; policy accept;
    }
}

Router

Následující příklad se týká základního routeru propojující síť WAN a LAN. Platí přitom, že komunikace pro daný stroj zajišťující funkci routeru je povolena pouze z LAN, až na výjimky jako ICMP. Zároveň je předávaná komunikace povolena jen směrem z LAN do WAN a obráceně jen v tom případě, že byla zahájena směrem z LAN.

DT2021 tip

table inet firewall {
    chain output {
        type filter hook output priority 100; policy accept;
    }

    chain input {
        type filter hook input priority 0; policy drop;
        iifname "lan0" accept
        meta l4proto icmp meta nfproto ipv4 \
            limit rate 10/second accept
        meta l4proto ipv6-icmp meta nfproto ipv6 \
            limit rate 10/second accept
        udp dport { 33434-33499 } reject
    }

    chain forward {
        type filter hook forward priority 0; policy drop;
        iifname "lan0" oifname "wan0" accept
        iifname "wan0" oifname "lan0" ct state related,established accept
    }
}

NAT s maškarádou

Klasické použití na routeru, který má jednu veřejnou IPv4 adresu. Použijeme maškarádu, která po odroutování zdrojovou adresu paketu přepíše primární IP adresou výstupního rozhraní WAN.

table ip nat {
    chain prerouting {
        type nat hook prerouting priority 0; policy accept;
    }

    chain postrouting {
        type nat hook postrouting priority 100; policy accept;
        oifname "wan0" masquerade
    }
}

SNAT

Pokud máme statickou IP adresu, je pro nás výhodnější použít SNAT (source NAT), který nemusí vyhledávat informace v maškarádovací tabulce a stačí mu staticky přepsat adresu v hlavičce. Je to výrazně výkonnější a takový NAT má tedy vyšší propustnost.

table ip nat {
    chain prerouting {
        type nat hook prerouting priority 0; policy accept;
    }

    chain postrouting {
        type nat hook postrouting priority 100; policy accept;
        ip saddr 192.168.1.0/24 oif "eth0" snat to 192.0.2.1
    }
}

Autor článku

Petr Krčmář pracuje jako šéfredaktor serveru Root.cz. Studoval počítače a média, takže je rozpolcen mezi dva obory. Snaží se dělat obojí, jak nejlépe umí.