Nftables Host absichern: Unterschied zwischen den Versionen

Aus Xinux Wiki
Zur Navigation springen Zur Suche springen
Zeile 2: Zeile 2:
 
*Bei einem frisch installierten Debian oder Ubuntu System sieht die Konfiguration so aus
 
*Bei einem frisch installierten Debian oder Ubuntu System sieht die Konfiguration so aus
 
*Diese stellt ein Zustand da, der an iptables erinnert.
 
*Diese stellt ein Zustand da, der an iptables erinnert.
*Wir haben die filter Tabelle und 3 Ketten.
+
*Wir haben die filter Tabelle und 3 Ketten: INPUT OUTPUT und FORWARD.
 
*Wenn wir die Konfiguration laden wird impliziet die Default Policy accept gesetzt.
 
*Wenn wir die Konfiguration laden wird impliziet die Default Policy accept gesetzt.
 +
 
=Datei=
 
=Datei=
 
*cat /etc/nftables.conf
 
*cat /etc/nftables.conf

Version vom 9. November 2022, 13:13 Uhr

Standard

  • Bei einem frisch installierten Debian oder Ubuntu System sieht die Konfiguration so aus
  • Diese stellt ein Zustand da, der an iptables erinnert.
  • Wir haben die filter Tabelle und 3 Ketten: INPUT OUTPUT und FORWARD.
  • Wenn wir die Konfiguration laden wird impliziet die Default Policy accept gesetzt.

Datei

  • cat /etc/nftables.conf
#!/usr/sbin/nft -f
flush ruleset
table inet filter { 
        chain INPUT {
                type filter hook input  priority filter;
                }
       chain OUTPUT {
                type filter  hook output  priority filter; 
                }
       chain FORWARD{
                type filter  hook forward  priority filter; 
                }




Syntax Allgemein

Die momentan in der inet Familie vorhandenen Tabellen sieht man mit:

nft list tables inet

Die momentan in der filter Tabelle aus der inet Familie gestetzen Ketten und Regeln sieht man mit:

nft list table inet filter

Der einzige Defaultwert hier ist die Familie ip, was nur IPv4 Verkehr sieht. Im Gegensatz dazu sieht inet sowohl IPv4 als auch IPv6.

Setzen der Default Policy

table inet filter { 
	chain INPUT {
		type filter hook input  priority filter; policy drop;
		}
       chain OUTPUT {
		type filter  hook output  priority filter; policy drop;
		}
       chain FORWARD{
		type filter  hook forward  priority filter; policy drop;
		}
}

Firewall-Skripte

  • Bei Nftables wird empfohlen die keine eigenen Bashskripte für die Firewall zu schreiben.
  • Stattdessen sollte man Konfigurationsdateien nutzen.
  • Diese sind übersichtlicher und man kann eine laufende Konfiguration direkt dumpen.

Eklärung

table inet filter - Es handelt sich um eine Tabelle mit dem Namen filter, dies ist von Typ inet was ipv4 und ipv6 einschliesst.
chain INPUT - Die Kette INPUT ist vom Type filter und hängt an der input hook und hat die Standard Priorität filter
chain OUTPUT - Die Kette INPUT ist vom Type filter und hängt an der input hook und hat die Standard Priorität filter
chain FORWARD - Die Kette INPUT ist vom Type filter und hängt an der input hook und hat die Standard Priorität filter
  • Diese Zeilten stellen den Zustand her der bei iptables normal ist.
  • Es wird mit den Tabellen input,output und forward gearbeitet.
type filter hook input priority filter;
type filter hook output priority filter;
type filter hook forward priority filter;
  • Wir lehnen alle Pakete die nicht matchen ab.
policy drop - Die Default policy drop bedeutet ablehnen

established und related Pakekte (Connection Tracking)

  • Eine Verbindungen den Status established, nachdem das erste Paket erlaubt wird.
  • Dafür schaut es, ob ein Paket mit Status new, die Bedingungen für die Annahme erfüllt.
  • related Pakete stehen in Beziehung zu einer established Verbindung, beispielsweise ICMP Nachrichten.
  • Die Idee ist nun alle established und related Pakekte freizuschalten und nur zu entscheiden.
  • Wir schalten nur frei ob eine Verbindung überhaupt aufgebaut werden darf.

Hinzufügen der established und related Regeln

table inet filter { 
	chain INPUT {
		type filter hook input  priority filter; policy drop;
		ct state established,related accept
		}
               chain OUTPUT {
		type filter  hook output  priority filter; policy drop;
		ct state established,related accept
		}
               chain FORWARD{
		type filter  hook forward  priority filter; policy drop;
		ct state established,related accept
	        }
}

Minimal Skript einer Firwall

table inet filter { 
	chain INPUT {
		type filter hook input  priority filter; policy drop;
		ct state established,related accept
		iifname "lo" ct state accept
		tcp dport 22 ct state accept
	}
 
	chain OUTPUT {
		type filter  hook output  priority filter; policy drop;
		ct state established,related accept
		ct state new accept
	}

	chain FORWARD{
		type filter  hook forward  priority filter; policy drop;
		ct state established,related accept
	}
}

Dies wird folgendermaßen umgesetzt:

$ vi fw.nft

---

#!/usr/sbin/nft -f
add table inet filter
add chain inet filter INPUT { type filter hook input priority filter; policy drop; }
add chain inet filter OUTPUT { type filter hook output priority filter; policy drop; }
add chain inet filter FORWARD { type filter hook forward priority filter; policy drop; }

# Basic rules for communication with established connections
add rule inet filter INPUT ct state established,related accept
add rule inet filter FORWARD ct state established,related accept
add rule inet filter OUTPUT ct state established,related accept

Neu verwendete Syntax:

  • Hänge Regeln an die Kette an

add rule familiy table chain_name <conditions> target

  • Interface des einkommenden Paketes
iifname device name
  • Überprüfen auf bestimmte Zustände des Paketes
ct state <states>

Erste zutreffende Regeln

Im jetztigen Zustand wird das erste Paket immer abgelehnt und das Gerät könnte nichtmal mit sich selbst kommunizieren. Auch nach und von außen wird jede Verbindung abgelehnt, was auch eine bestehende SSH-Verbindung bei Aktivierung der Firewall unterbrechen würde. Damit das nicht passiert müssen folgende Regeln hinzugefügt werden:

$ vi fw.nft

---

#!/usr/sbin/nft -f
add table inet filter
add chain inet filter INPUT { type filter hook input priority filter; policy drop; }
add chain inet filter OUTPUT { type filter hook output priority filter; policy drop; }
add chain inet filter FORWARD { type filter hook forward priority filter; policy drop; }

# Basic rules for communication with itself and established connections
add rule inet filter INPUT ct state established,related accept
add rule inet filter FORWARD ct state established,related,new accept
add rule inet filter OUTPUT ct state established,related accept
add rule inet filter INPUT iifname lo ct state new accept

# Enable SSH to firewall
add rule inet filter INPUT ct state new tcp dport 22 accept

Status nach firewall start

$ firewall start

---

table inet filter {
    chain INPUT {
        type filter hook input priority filter; policy drop;
        ct state established,related accept
        iifname "lo" ct state new accept
        ct state new tcp dport 22 accept

    }
    
    chain OUTPUT {
        type filter hook output priority filter; policy drop;
        ct state established,related,new accept
    }

    chain FORWARD {
        type filter hook forward priority filter; policy drop;
        ct state established,related accept
    }
}

Das Logging

nftables kann in das Systemlogbuch, was normalerweise /var/log/syslog ist, schreiben. Es sollen nun alle abgelehnten Pakete geloggt werden, d.h. eine Regel vor der Anwendung der Default Policy. Im Gegensatz zu den anderen Zielen bricht log nicht die weitere Verarbeitung in der Kette ab.

$ vi fw.nft

---

#!/usr/sbin/nft -f
add table inet filter
add chain inet filter INPUT { type filter hook input priority filter; policy drop; }
add chain inet filter OUTPUT { type filter hook output priority filter; policy drop; }
add chain inet filter FORWARD { type filter hook forward priority filter; policy drop; }

# Basic rules for communication with itself and established connections
add rule inet filter INPUT ct state established,related accept
add rule inet filter FORWARD ct state established,related,new accept
add rule inet filter OUTPUT ct state established,related accept
add rule inet filter INPUT iifname lo ct state new accept

# Enable SSH to firewall
add rule inet filter INPUT ct state new tcp dport 22 accept

# Log dropped packets.
add rule inet filter INPUT limit rate 5/minute log prefix "--nftables-drop-input--"
add rule inet filter OUTPUT limit rate 5/minute log prefix "--nftables-drop-output--"
add rule inet filter FORWARD limit rate 5/minute log prefix "--nftables-drop-forward--"

Neu verwendete Syntax: Logge das Pakete mit diesem Präfix:

log prefix <prefix string>

Man kann sich anschauen, was aktuell geloggt wird:

tail -f /var/log/syslog | grep nftables

---

Sep 15 14:58:21 fw-linkai kernel: [93778.514323] --nftables-drop-forward--IN=ens19 OUT=ens18 MAC=f2:8c:80:a8:c0:cc:12:05:0c:18:11:6b:08:00 SRC=10.82.244.8 DST=78.46.102.180 LEN=76 TOS=0x10 PREC=0x00 TTL=63 ID=25389 DF PROTO=UDP SPT=34193 DPT=123 LEN=56
Sep 15 14:58:31 fw-linkai kernel: [93788.764377] --nftables-drop-forward--IN=ens19 OUT=ens18 MAC=f2:8c:80:a8:c0:cc:12:05:0c:18:11:6b:08:00 SRC=10.82.244.8 DST=172.104.134.72 LEN=76 TOS=0x10 PREC=0x00 TTL=63 ID=40828 DF PROTO=UDP SPT=58350 DPT=123 LEN=56
Sep 15 14:58:42 fw-linkai kernel: [93799.014461] --nftables-drop-forward--IN=ens19 OUT=ens18 MAC=f2:8c:80:a8:c0:cc:12:05:0c:18:11:6b:08:00 SRC=10.82.244.8 DST=65.21.184.1 LEN=76 TOS=0x10 PREC=0x00 TTL=63 ID=32369 DF PROTO=UDP SPT=54458 DPT=123 LEN=56

ICMP freischalten

$ vi firewall

---

...
add rule inet filter INPUT ct state new meta l4proto icmp icmp type echo-request accept

# Log dropped packets.
...

Neu verwendete Syntax:

  • IPv4 und IPv6 Layer 4 Protokoll
meta l4proto protocol
  • Nur Echo-Anfragen freischalten
icmp type echo-request

Forwarding

Damit Pakete weitergeleitet werden können, muss als erstes FORWARDING im Kernel aktiviert werden.

Aktivierung

$ echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
$ sysctl -p

---

net.ipv4.ip_forward = 1

SNAT

Rechner in einem LAN können nicht ohne weiteres mit dem WAN kommunizieren, da an die lokale IP-Adresse der Rechner im LAN nicht von außen geroutet werden kann. Um eine Internetverbindung aufzubauen, muss die Adresse aus dem LAN in eine öffentliche umgeschrieben werden.

$ vi fw.nft

---

#!/usr/sbin/nft -f
define WANDEV = ens18
define WANIP = 10.82.229.11
define LAN = 10.82.244.0/24
...
add table inet nat
add chain inet nat PREROUTING { type nat hook prerouting priority dstnat; policy accept; }
add chain inet nat POSTROUTING { type nat hook postrouting priority srcnat; policy accept; }
...
add rule inet nat POSTROUTING oifname $WANDEV ip saddr $LAN snat to $WANIP

# Log dropped packets.
...

Neu verwendete Syntax:

  • Definieren einer Variable
define variable_name = value
  • Interface des herausgehenden Paketes:
oifname device name
  • IPv4-Adresse des Ursprungpaketes
ip saddr <source address>

Absichern von Netzen

Momentan wird nichts vom LAN zum WAN weitergeleitet. Um nur bestimmte Anwendungen zu erlauben kann man die für diese designierten Ports freischalten.

$ vi fw.nft

---

#!/usr/sbin/nft -f
define WANDEV = ens18
define LANDEV = ens19
define WANIP = 10.82.229.11
define LAN = 10.82.244.0/24
...
# SNAT and open certain ports for internet access of client
add rule inet nat POSTROUTING oifname $WANDEV ip saddr $LAN snat to $WANIP
add rule inet filter FORWARD ct state new iifname $LANDEV oifname $WANDEV ip saddr $LAN meta l4proto icmp icmp type echo-request accept
add rule inet filter FORWARD ct state new iifname $LANDEV oifname $WANDEV ip saddr $LAN udp dport 53 accept
add rule inet filter FORWARD ct state new iifname $LANDEV oifname $WANDEV ip saddr $LAN tcp dport { 25, 53, 80, 143, 443, 465, 993 } accept
# Log dropped packets.
...

Neu verwendete Syntax:

Bestimmte Ziel-Ports angeben

transport_protocol dport { port number }

Status nach firewall start

$ firewall start

---

table inet filter {
    chain INPUT {
        type filter hook input priority filter; policy drop;
        ct state established,related accept
        iifname "lo" ct state new accept
        ct state new tcp dport 22 accept

    }
    
    chain OUTPUT {
        type filter hook output priority filter; policy drop;
        ct state established,related,new accept
    }

    chain FORWARD {
        type filter hook forward priority filter; policy drop;
        ct state established,related accept
        ct state new iifname "ens19" oifname "ens18" ip saddr 10.82.244.0/24 icmp type echo-request jump LAN2WAN
        ct state new iifname "ens19" oifname "ens18" ip saddr 10.82.244.0/24 udp dport 53 jump LAN2WAN
        ct state new iifname "ens19" oifname "ens18" ip saddr 10.82.244.0/24 tcp dport { 25, 53, 80, 143, 443, 465, 993 } jump LAN2WAN
    }
}
table inet nat {
    chain PREROUTING {
        type nat hook prerouting priority dstnat; policy accept;
    }

    chain POSTROUTING {
        type nat hook postrouting priority srcnat; policy accept;
        oifname "ens18" ip saddr 10.82.244.0/24 snat ip to 10.82.229.11
    }
}

Eigene Ketten

Man kann auch Ketten ohne Default Policy oder Hooks erstellen, die mehrere Regeln zusammenfassen. In diese Ketten gelangt man durch die Basisketten.

$ vi fw.nft

---

#!/usr/sbin/nft -f
...
# Custom chain: Forward traffic from with the LAN
add chain inet filter LAN2WAN
add rule inet filter LAN2WAN ct state new iifname $LANDEV oifname $WANDEV ip saddr $LAN accept
...
add rule inet filter FORWARD meta l4proto icmp icmp type echo-request jump LAN2WAN
add rule inet filter FORWARD udp dport 53 jump LAN2WAN
add rule inet filter FORWARD tcp dport { 25, 53, 80, 143, 443, 465, 993 } jump LAN2WAN

Neu verwendete Syntax:

Springe in eine andere Kette

jump target

Limits setzten

Man kann die Anzahl die eine Regel annimmt zeitlich begrenzen. Dafür fügt man ’‘’limit rate’’’ in die Regel ein. Falls nur 5 Pakete pro Minute geloggt werden sollen:

$ vi fw.nft

---
#!/usr/sbin/nft -f
...
# Log dropped packets. Max. 5/min
add rule inet filter INPUT limit rate 5/minute log prefix "--nftables-drop-input--"
add rule inet filter OUTPUT limit rate 5/minute log prefix "--nftables-drop-output--"
add rule inet filter FORWARD limit rate 5/minute log prefix "--nftables-drop-forward--"

VPNs ermöglichen

Damit VPN-Verbindungen von außen aufgebaut werden können müssen die UDP-Ports 500 und 4500 für IPSec-Protokolle offen sein. Nachdem eine Secure Association hergestellt wurde, müssen ESP Pakete von der Firewall zugelassen und die entpackten Pakete weitergeleitet werden.

  • vim fw.nft
#!/usr/sbin/nft -f
...
define VPN = 192.168.178.0/24
...
# Establish rules for VPN connections but leave chains empty for toggling
outside this script
add chain inet filter IPSEC
add rule inet filter IPSEC accept
add rule inet filter INPUT iifname $WANDEV ct state new udp dport 500 jump IPSEC
add rule inet filter INPUT iifname $WANDEV ct state new udp dport 4500 jump IPSEC
add rule inet filter INPUT iifname $WANDEV ct state new meta l4proto esp jump IPSEC
add rule inet filter FORWARD iifname $WANDEV ip saddr $VPN ct state new jump IPSEC
...
# Log dropped packets. Max. 5/min
...

Der Weg nach außen muss in dem Fall nicht speziell freigeschaltet werden, da unsere Firewall sowieso alle neuen Pakete nach außen durchlässt. Damit aber ESP-Pakete korrekt generiert werden, muss die POSTROUTING-Regel für den Internetzugang der Clients angepasst werden. Ein Blick auf die Routing-Tabelle zeigt nämlich, …

  • ip route show table 220
192.168.178.0/24 via 10.82.229.1 dev ens18 proto static src 10.82.244.1

… dass nur Pakete mit einer Ursprungs-IP von 10.82.244.1 an das lokale Netz der VPN-Verbindung geleitet wird. Die bisherige SNAT-Regel schreibt jedoch alle Pakete auf die IP des WAN-Interfaces um. Also müssen wir die Ziel-IPs der VPN ausschließen:

#!/usr/sbin/nft -f
...
define VPN = 192.168.178.0/24
...
# SNAT and open certain ports for internet access of client
add rule inet nat POSTROUTING oifname $WANDEV ip saddr $LAN ip daddr != $VPN snat to $WANIP
...

Zum Vergleich die tcpdump-Analysen bei einem Ping auf einen der Rechner im VPN…

  • …ohne die Ziel-IPs auszuschließen: tcpdump -i ens18 icmp or esp
15:30:07.481373 IP fw-linkai > 192.168.178.2: ICMP echo request, id 2845, seq 1, length 64
15:30:08.493319 IP fw-linkai > 192.168.178.2: ICMP echo request, id 2845, seq 2, length 64
15:30:09.517369 IP fw-linkai > 192.168.178.2: ICMP echo request, id 2845, seq 3, length 64
  • …wenn die Ziel-IPs auszuschließen werden: tcpdump -i ens18 icmp or esp
15:27:31.091907 IP fw-linkai > 10.82.228.2: ESP(spi=0xc668795e,seq=0x4), length 136
15:27:31.093913 IP 10.82.228.2 > fw-linkai: ESP(spi=0xccf83bd8,seq=0x4), length 136
15:27:31.093913 IP 192.168.178.2 > 10.82.244.1: ICMP echo reply, id 32171, seq 1, length 64
15:27:32.093502 IP fw-linkai > 10.82.228.2: ESP(spi=0xc668795e,seq=0x5), length 136
15:27:32.095404 IP 10.82.228.2 > fw-linkai: ESP(spi=0xccf83bd8,seq=0x5), length 136
15:27:32.095404 IP 192.168.178.2 > 10.82.244.1: ICMP echo reply, id 32171, seq 2, length 64
15:27:33.095023 IP fw-linkai > 10.82.228.2: ESP(spi=0xc668795e,seq=0x6), length 136
15:27:33.096880 IP 10.82.228.2 > fw-linkai: ESP(spi=0xccf83bd8,seq=0x6), length 136
15:27:33.096880 IP 192.168.178.2 > 10.82.244.1: ICMP echo reply, id 32171, seq 3, length 64