Nftables und layer2 Firewall: Unterschied zwischen den Versionen

Aus Xinux Wiki
Zur Navigation springen Zur Suche springen
(Die Seite wurde neu angelegt: „=Bridge-Filterung= =Arten von Bridge-Ketten= *Die Bridge-Familie bietet vier Kettenarten: ;prerouting: *Hier können Pakete vor der Forward-Datenbank (FDB) En…“)
 
 
(31 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 1: Zeile 1:
 +
=Template=
 +
*debian-template klonen mit dem Namen bridgefw
 +
=Vorab=
 +
;Bei Virtualisierungen Bridge Ports auf Promisc setzen
 +
*Das sind Adapater 2 und Adapater 3
 +
*Dies erlaubt der virtuellen Netzwerkkarte, auch Pakete zu empfangen, die nicht an ihre MAC-Adresse gerichtet sind - notwendig für den Bridge-Betrieb.
 +
[[Datei:Vm-promisc-1.png]]
 +
;VirtualBox
 +
*Unter "Erweitert" den Promiscuous Mode auf "Allow All" stellen (siehe Bild).
 +
;Proxmox/KVM
 +
*An der Linux-Bridge des Hosts ist nichts einzustellen.
 +
*Ist die Proxmox-Firewall für die VM aktiv, muss dort der MAC-Filter ausgeschaltet werden, sonst werden fremde MAC-Adressen verworfen.
 +
;In der VM selbst
 +
*Die Bridge schaltet ihre Ports beim Hochfahren automatisch in den Promiscuous Mode, hier ist nichts zu tun.
 +
 +
 +
=== Netzkonfiguration BRDIGEFW ===
 +
 +
{| class="wikitable" style="background-color: #f2f2f2;"
 +
! Parameter !! Wert !! Erläuterung
 +
|-
 +
| '''Netzwerk (NIC 1)''' || SERVER|| Interface-Zuweisung in VirtualBox
 +
|-
 +
| '''Netzwerk (NIC 2)''' || DMZ|| Interface-Zuweisung in VirtualBox (Promiscuous-Modus Allow all)
 +
|-
 +
| '''Netzwerk (NIC 3)''' || DMZ-OUT|| Interface-Zuweisung in VirtualBox (Promiscuous-Modus Allow all)
 +
|-
 +
| '''IP''' || 10.2XX.1.9 || Statische IP
 +
|-
 +
| '''CIDR''' || 24 || Classless Inter-Domain Routing Präfixlänge
 +
|-
 +
| '''GW''' || 10.2XX.1.1 || GATEWAY
 +
|-
 +
| '''NS''' || 10.88.2XX.21 || Resolver
 +
|-
 +
| '''FQDN''' || bridgefw.it2XX.int || Fully Qualified Domain Name
 +
|-
 +
| '''SHORT''' || smb || Short Name
 +
|-
 +
| '''DOM''' || it2XX.int|| Domain Name
 +
|}
 +
 +
=Setup=
 +
*debian-setup.sh -f bridgefw.it2XX.int -a 10.2XX.1.9/24 -n 10.88.2XX.21 -g 10.2XX.1.1
 +
=Auf dem Hostsystem=
 +
*vi ~/.ssh/config
 +
  Host bridgefw
 +
  Hostname 10.2XX.1.9
 +
  User kit
 +
  ProxyJump kit@fw
 +
;Key übertragen
 +
*ssh-copy-id bridgefw
 +
;Einloggen
 +
*ssh bridgefw
 +
 +
=Was ist eine Layer 2 Firewall?=
 +
*Eine normale Firewall arbeitet auf Layer 3 (IP-Ebene) und benötigt eine IP-Adresse im Datenpfad.
 +
*Eine Layer 2 Firewall greift dagegen auf Ethernet-Ebene (MAC) - sie kann '''transparent''' zwischen zwei Netzwerksegmente gestellt werden, ohne eine eigene IP-Adresse im Datenpfad zu benötigen.
 +
*Der Datenverkehr läuft über eine Bridge, die nftables zur Filterung nutzt.
 +
*Die Clients merken von der Firewall nichts: Gateway, Adressen und Subnetz bleiben unverändert.
 +
=Schaubild=
 +
{{#drawio:bridgefw}}
 +
 +
=Installation der Bridgeutils=
 +
*apt install bridge-utils
 +
*Das Paket liefert die Skripte, mit denen ifupdown die Optionen bridge_ports, bridge_fd und bridge_stp auswertet.
 +
 +
=/etc/network/interfaces=
 +
<pre>
 +
auto lo
 +
iface lo inet loopback
 +
 +
auto enp0s3
 +
iface enp0s3 inet static
 +
address 10.2XX.1.9/24
 +
gateway 10.2XX.1.1
 +
dns-nameservers 10.88.2XX.21
 +
dns-search it2XX.int
 +
 +
auto enp0s8
 +
iface enp0s8 inet manual
 +
 +
auto enp0s9
 +
iface enp0s9 inet manual
 +
 +
auto vmbr0
 +
iface vmbr0 inet manual
 +
    bridge_ports enp0s8 enp0s9
 +
    bridge_fd 0
 +
    bridge_stp no
 +
 +
</pre>
 +
;Hinweise zur Konfiguration
 +
;enp0s3:
 +
*Management-Interface mit eigener IP-Adresse. Es liegt '''nicht''' in der Bridge.
 +
;vmbr0 inet manual:
 +
*Die Bridge bekommt bewusst keine IP-Adresse - sie arbeitet rein transparent.
 +
;bridge_fd 0:
 +
*Forward Delay. Er wird nur bei aktivem STP genutzt: Die Ports durchlaufen dann die Zustände Listening und Learning, bevor sie Pakete weiterleiten.
 +
*Ohne STP schaltet der Kernel die Ports sofort auf Forwarding. Der Wert 0 macht das explizit.
 +
;bridge_stp no:
 +
*STP (Spanning Tree Protocol) ist deaktiviert. Da nur zwei Ports vorhanden sind, ist kein Loop möglich und STP nicht notwendig.
 +
;Bridge starten
 +
*ifup vmbr0
 +
 +
=Kontrolle der Bridge=
 +
;Welche Ports gehören zur Bridge und in welchem Zustand sind sie?
 +
*bridge link show
 +
;Welche MAC-Adressen hat die Bridge an welchem Port gelernt? (FDB)
 +
*bridge fdb show br vmbr0 | grep -v permanent
 +
;Welche Interfaces gehören zu Bridgen
 +
*brctl show
 +
bridge name bridge id STP enabled interfaces
 +
vmbr0 8000.76e085f914d6 no enp0s8
 +
enp0s9
 +
 +
=Erste Maschine hinte die Bridge Firewall plazieren=
 +
*www -> Interface auf DMZ-OUT ändern
 +
*Ping mal von www nach 1.1.1.1
 +
*Kontrolle auf der bridgefw auf den Schnittstellen enp0s8 und enp0s9 per tcpdump
 +
 
=Bridge-Filterung=
 
=Bridge-Filterung=
−
=Arten von Bridge-Ketten=
+
==Arten von Bridge-Ketten==
−
*Die Bridge-Familie bietet vier Kettenarten:
+
*Die Bridge-Familie bietet fünf Kettenarten (Hooks):
−
 
 
 
;prerouting:
 
;prerouting:
−
*Hier können Pakete vor der Forward-Datenbank (FDB) Entscheidung gefiltert werden.  
+
*Hier können Pakete vor der Forward-Datenbank (FDB) Entscheidung gefiltert werden.
−
*Die FDB liefert den Bridge-Port, der für eine bestimmte Ziel-MAC-Adresse verwendet wird.  
+
*Die FDB liefert den Bridge-Port, der für eine bestimmte Ziel-MAC-Adresse verwendet wird.
−
*Wenn es noch keinen Eintrag in der FDB für eine gegebene Ziel-MAC gibt, werden die Pakete an alle Bridge-Ports geflutet.  
+
*Wenn es noch keinen Eintrag in der FDB für eine gegebene Ziel-MAC gibt, werden die Pakete an alle Bridge-Ports geflutet.
 
*Nach der FDB-Entscheidung können Pakete entweder dem Eingangs- oder dem Weiterleitweg folgen.
 
*Nach der FDB-Entscheidung können Pakete entweder dem Eingangs- oder dem Weiterleitweg folgen.
 
;input:
 
;input:
−
*Hier können Pakete gefiltert werden, die an den IP-Stack übergeben werden.  
+
*Hier können Pakete gefiltert werden, die an den IP-Stack übergeben werden.
−
*Wenn Ihre Bridge-Schnittstelle eine IP-Adresse hat und Pakete an diese IP-Adresse gehen (oder diese IP-Adresse als Gateway verwendet wird), folgen die Pakete diesem Pfad (in diesem Fall verlassen die Pakete die Bridge, um in den IP-Stack einzutreten, also werden die Pakete "geroutet").
+
*Wenn die Bridge-Schnittstelle eine IP-Adresse hat und Pakete an diese IP-Adresse gehen, folgen die Pakete diesem Pfad (die Pakete verlassen die Bridge und treten in den IP-Stack ein).
−
;forward:  
+
;forward:
−
*Diese Hook kann verwendet werden, um Pakete zu filtern, die von einem Bridge-Port eingehen und an einen anderen Bridge-Port geliefert werden (dies ist der Bridge-Weiterleitungspfad, in diesem Fall werden die Pakete "gebridged").
+
*Diese Hook filtert Pakete, die von einem Bridge-Port eingehen und an einen anderen Bridge-Port geliefert werden (der Bridge-Weiterleitungspfad).
−
;output:  
+
*'''Im vorliegenden Szenario wird ausschließlich diese Chain genutzt''' - die Bridge hat keine IP-Adresse im Datenpfad, es wird rein gebridged.
−
*Hier können Pakete gefiltert werden, die vom IP-Stack kommen und deren Ziel der Bridge-Port ist.
+
;output:
−
;postrouting:  
+
*Hier können Pakete gefiltert werden, die vom IP-Stack kommen und deren Ziel ein Bridge-Port ist.
 +
;postrouting:
 
*Hier können Pakete gefiltert werden, die entweder vom IP-Stack kommen oder von einem anderen Bridge-Port weitergeleitet werden.
 
*Hier können Pakete gefiltert werden, die entweder vom IP-Stack kommen oder von einem anderen Bridge-Port weitergeleitet werden.
−
=Zustandslose Filterung=
+
 
−
Wenn Sie den TCP-Zielport in IPv4-Paketen filtern möchten:
+
==Bridge-Familie und br_netfilter==
−
*nft add rule bridge filter forward ether type ip tcp dport 22 accept
+
*Gebridgte Pakete laufen normalerweise '''nur''' durch die Ketten der Bridge-Familie, nicht durch ip/inet-Tabellen.
−
=Ein weiteres Beispiel zum Akzeptieren von ARP-Paketen=
+
*Ist jedoch das Kernelmodul br_netfilter geladen (z.B. automatisch durch Docker), laufen sie zusätzlich durch die ip/inet-Hooks. Das führt zu schwer nachvollziehbaren Effekten.
−
*nft add rule bridge filter forward ether type arp accept
+
*Kontrolle:
 +
lsmod | grep br_netfilter
 +
*Keine Ausgabe bedeutet: Modul nicht geladen, alles in Ordnung.
 +
 
 +
=ARP=
 +
*ARP ist im Gegensatz zur Layer 3 Firewall '''nicht''' automatisch freigeschaltet und muss explizit erlaubt werden.
 +
*Eine Layer 3 Firewall sieht ARP gar nicht, weil ARP kein IP-Protokoll ist. Die Bridge sieht dagegen jeden Ethernet-Frame.
 +
*Ohne ARP-Freischaltung ist keine Kommunikation im Netz möglich, da MAC-Adressen nicht aufgelöst werden können.
 +
*Beispiel zum Akzeptieren von ARP-Paketen: <code>nft add rule bridge filter forward ether type arp accept</code>
 +
 
 
=Zustandsabhängige Filterung=
 
=Zustandsabhängige Filterung=
−
*Die Bridge-Familie unterstützt die Verbindungsverfolgung seit Linux-Kernel 5.3.
+
*Die Bridge-Familie unterstützt Connection Tracking (Verbindungsverfolgung), ab Kernel 5.3.
−
*Sie müssen nur auf den Verbindungsstatusinformationen aus Ihrer Regelmenge übereinstimmen, um dies zu aktivieren.
+
*Durch Matching auf den Verbindungsstatus (<code>ct state</code>) können bestehende Verbindungen automatisch durchgelassen werden, ohne jede Richtung explizit freizuschalten.
−
*Für diejenigen, die mit iptables vertraut sind: Dies bietet einen Ersatz für br_netfilter und das -m physdev-Match für iptables.
+
;Die wichtigsten Zustände
−
=Beispiel: Zustandsabhängige Bridge-Firewall=
+
;new:
−
*Das folgende Beispiel zeigt, wie eine zustandsabhängige Bridge-Firewall bereitgestellt wird.  
+
*Erstes Paket einer Verbindung.
−
*Dies setzt voraus, dass die Bridge-Schnittstelle keine IP-Adresse hat.
+
;established:
−
=Angenommen, eine Bridge mit zwei Ports, eth0 und eth1=
+
*Paket gehört zu einer bereits bekannten Verbindung.
−
*Ein Desktop-Computer ist mit dem Bridge-Port eth0 verbunden.
+
;related:
−
*Ein Webserver (mit SSH für die Remote-Verwaltung) ist mit dem Bridge-Port eth1 verbunden.
+
*Paket gehört zu einer bekannten Verbindung, ist aber eine eigene (z.B. ICMP-Fehlermeldung zu einer TCP-Verbindung).
−
*Die Uplink-Verbindung erfolgt über den Bridge-Port eth2.
+
;Besonderheit in der Bridge
−
*Die folgende Richtlinie ermöglicht es dem Desktop-Computer und dem Webserver, eine Verbindung zu initiieren. Von außen:
+
*Connection Tracking gibt es hier nur für IP. ARP wird nicht verfolgt und braucht deshalb eigene Regeln.
−
*Es kann keine Verbindung zum Desktop-Computer initiiert werden.
+
 
−
*Verbindungen zu den HTTP- und SSH-Diensten zum Server sind erlaubt.
+
=Bridge Firewall=
−
*Von innen in die Bridge können der Desktop-Computer und der Webserver überall Verbindungen initiieren:
+
{{#drawio:bridge-fw}}
 +
 
 
=Regeln=
 
=Regeln=
−
*nft add table bridge filter
+
;Konzept
−
*nft add chain bridge filter forward '{type filter hook forward priority 0; }'
+
*<code>enp0s8</code> ist die '''offene''' Seite (z.B. Richtung Internet/unsicheres Netz)
−
*nft add rule bridge filter forward ct state established,related accept
+
*<code>enp0s9</code> ist die '''gefilterte''' Seite (z.B. internes Netz)
−
*nft add rule bridge filter forward iif { eth0, eth1 } oif eth2 ct state new accept
+
*<code>enp0s3</code> ist das Management-Interface im vertrauenswürdigen LAN, es wird hier nicht gefiltert
−
*nft add rule bridge filter forward iif eth2 oif eth1 ct state new tcp dport { 22, 80, 443 } accept
+
*Die Bridge selbst hat keine IP-Adresse und ist aus den gefilterten Netzen nicht erreichbar
 +
*Policy ist <code>drop</code> - alles was nicht explizit erlaubt ist, wird verworfen
 +
*cat /etc/nftables.conf
 +
<pre>
 +
#!/usr/sbin/nft -f
 +
 
 +
define open    = enp0s8
 +
define filter  = enp0s9
 +
 
 +
flush ruleset
 +
 
 +
table bridge filter {
 +
        chain forward {
 +
                type filter hook forward priority 0; policy drop;
 +
 
 +
                # Bestehende Verbindungen durchlassen (Connection Tracking)
 +
                ct state established,related accept
 +
 
 +
                # ARP freischalten (beide Richtungen notwendig)
 +
                iif $open  ether type arp accept
 +
                iif $filter ether type arp accept
 +
 
 +
                #### ICMP von filter nach open freischalten
 +
                #iif $filter oif $open ip protocol icmp ct state new accept
 +
 
 +
                #### DNS von filter nach open freischalten (UDP und TCP)
 +
                #iif $filter oif $open udp dport 53 ct state new accept
 +
                #iif $filter oif $open tcp dport 53 ct state new accept
 +
 
 +
                #### HTTP von filter nach open freischalten
 +
                #iif $filter oif $open tcp dport 80 ct state new accept
 +
 
 +
                #### HTTPS von filter nach open freischalten
 +
                #iif $filter oif $open tcp dport 443 ct state new accept
 +
 
 +
                #### DHCP: Clients auf der filter-Seite, Server auf der open-Seite
 +
                #iif $filter oif $open udp sport 68 udp dport 67 accept
 +
                #iif $open oif $filter udp sport 67 udp dport 68 accept
 +
 
 +
                #### Alles von open nach filter freischalten
 +
                #iif $open oif $filter ct state new accept
 +
 
 +
                # Abgelehnte Pakete loggen (sichtbar mit journalctl)
 +
                # begrenzt auf 10 Meldungen pro Sekunde
 +
                limit rate 10/second log prefix " nft-drop"
 +
        }
 +
}
 +
</pre>
 +
;Hinweis zur Reihenfolge
 +
*Die Regeln werden von oben nach unten abgearbeitet, das erste accept oder drop beendet die Prüfung.
 +
*established,related steht ganz oben, weil die meisten Pakete zu bestehenden Verbindungen gehören - das spart Rechenzeit.
 +
;Hinweis zu ICMP
 +
*Die ICMP-Regel matcht nur IPv4. IPv6 wird in diesem Szenario nicht betrachtet.
 +
;Hinweis zu DNS
 +
*DNS nutzt normalerweise UDP. Bei großen Antworten (z.B. DNSSEC) weicht es auf TCP aus. Ohne die TCP-Regel schlagen solche Anfragen scheinbar zufällig fehl.
 +
;Hinweis zu DHCP
 +
*Die DHCP-Regeln werden nur gebraucht, wenn Clients auf der gefilterten Seite ihre Adresse von einem Server auf der offenen Seite beziehen.
 +
*Connection Tracking hilft hier nicht: Der Client fragt per Broadcast an, die Antwort des Servers passt daher zu keiner bekannten Verbindung. Deshalb werden beide Richtungen ohne ct state freigeschaltet.
 +
;Hinweis zu VLANs
 +
*VLAN-getaggte Frames werden durch die Policy verworfen. Sollen getaggte Frames die Bridge passieren, sind eigene Regeln nötig. Das ist nicht Teil dieses Szenarios.
 +
;Hinweis zum Log
 +
*Das führende Leerzeichen in <code>" nft-drop"</code> ist Absicht - es verbessert die Lesbarkeit im Kernel-Log.
 +
*Die Begrenzung per limit verhindert, dass Broadcasts das Journal fluten. Pakete über dem Limit werden trotzdem verworfen, nur nicht mehr geloggt.
 +
 
 +
=Regel Handling=
 +
;Laden der Regeln
 +
*nft -f /etc/nftables.conf
 +
;Kontrolle der Regeln
 +
*nft list ruleset
 +
;Löschen der Regeln
 +
*nft flush ruleset
 +
;Regeln beim Booten laden
 +
*systemctl enable --now nftables
 +
*Der Dienst lädt beim Start /etc/nftables.conf.
 +
 
 +
=Achtung: Fail-open=
 +
*Eine Bridge ohne Regelwerk leitet '''alles''' weiter. Die Firewall ist dann ein einfaches Kabel.
 +
*Das passiert:
 +
**nach <code>nft flush ruleset</code>
 +
**wenn der Dienst nftables nicht aktiviert ist
 +
**wenn /etc/nftables.conf einen Syntaxfehler hat und nicht geladen wird
 +
*Nach jeder Änderung daher mit <code>nft list ruleset</code> prüfen, ob das Regelwerk wirklich aktiv ist.
 +
*Syntax vorher testen, ohne zu laden:
 +
nft -c -f /etc/nftables.conf
 +
 
 +
=Live Log der Regel Verstöße=
 +
*journalctl -f -t kernel -g "nft-drop"
 +
 
 +
=Verbindungen beobachten=
 +
*apt install conntrack
 +
;Alle erfassten Verbindungen anzeigen
 +
*conntrack -L
 +
;Neue Verbindungen live verfolgen
 +
*conntrack -E
 +
 
 +
=Fehlersuche mit Trace=
 +
*Mit nftrace lässt sich der Weg eines Pakets Regel für Regel verfolgen.
 +
*Eine zusätzliche Chain markiert die interessierenden Pakete, hier ICMP:
 +
nft add chain bridge filter trace '{ type filter hook prerouting priority 0; }'
 +
nft add rule bridge filter trace ip protocol icmp meta nftrace set 1
 +
*In einem zweiten Terminal mitlesen:
 +
nft monitor trace
 +
*Die Ausgabe zeigt für jedes markierte Paket jede durchlaufene Regel und das Ergebnis (accept/drop).
 +
*Zum Entfernen einfach das Regelwerk neu laden:
 +
nft -f /etc/nftables.conf
 +
 
 +
=Übung=
 +
*Regelwerk wie oben laden, alle mit #### markierten Regeln sind auskommentiert.
 +
*Parallel den Live-Log laufen lassen.
 +
;Schritt 1
 +
*Von einem Client auf der gefilterten Seite das Gateway anpingen. Was passiert, was steht im Log?
 +
*ICMP-Regel aktivieren, neu laden, erneut testen.
 +
;Schritt 2
 +
*Mit <code>dig</code> eine Namensauflösung testen, dann die DNS-Regeln aktivieren.
 +
;Schritt 3
 +
*Mit <code>curl</code> eine HTTP- und eine HTTPS-Seite abrufen, dann die Regeln für Port 80 und 443 aktivieren.
 +
;Schritt 4
 +
*Mit <code>conntrack -L</code> die entstandenen Verbindungen ansehen.
 +
*Warum kommt die Antwort des Webservers durch, obwohl es keine Regel von open nach filter gibt?
 +
;Schritt 5
 +
*Die beiden ARP-Regeln auskommentieren und neu laden. Was passiert mit bestehenden und mit neuen Verbindungen?
 +
*Tipp: <code>ip neigh flush all</code> auf dem Client leert den ARP-Cache.
 +
;Schritt 6
 +
*Den Dienst nftables stoppen bzw. <code>nft flush ruleset</code> ausführen und erneut testen. Was bedeutet das für den Betrieb?
 +
 
 +
=Weiterführende Artikel=
 +
*[[nftables schnellstart]]

Aktuelle Version vom 1. Oktober 2026, 08:27 Uhr

Template

  • debian-template klonen mit dem Namen bridgefw

Vorab

Bei Virtualisierungen Bridge Ports auf Promisc setzen
  • Das sind Adapater 2 und Adapater 3
  • Dies erlaubt der virtuellen Netzwerkkarte, auch Pakete zu empfangen, die nicht an ihre MAC-Adresse gerichtet sind - notwendig für den Bridge-Betrieb.

Vm-promisc-1.png

VirtualBox
  • Unter "Erweitert" den Promiscuous Mode auf "Allow All" stellen (siehe Bild).
Proxmox/KVM
  • An der Linux-Bridge des Hosts ist nichts einzustellen.
  • Ist die Proxmox-Firewall für die VM aktiv, muss dort der MAC-Filter ausgeschaltet werden, sonst werden fremde MAC-Adressen verworfen.
In der VM selbst
  • Die Bridge schaltet ihre Ports beim Hochfahren automatisch in den Promiscuous Mode, hier ist nichts zu tun.


Netzkonfiguration BRDIGEFW

Parameter Wert Erläuterung
Netzwerk (NIC 1) SERVER Interface-Zuweisung in VirtualBox
Netzwerk (NIC 2) DMZ Interface-Zuweisung in VirtualBox (Promiscuous-Modus Allow all)
Netzwerk (NIC 3) DMZ-OUT Interface-Zuweisung in VirtualBox (Promiscuous-Modus Allow all)
IP 10.2XX.1.9 Statische IP
CIDR 24 Classless Inter-Domain Routing Präfixlänge
GW 10.2XX.1.1 GATEWAY
NS 10.88.2XX.21 Resolver
FQDN bridgefw.it2XX.int Fully Qualified Domain Name
SHORT smb Short Name
DOM it2XX.int Domain Name

Setup

  • debian-setup.sh -f bridgefw.it2XX.int -a 10.2XX.1.9/24 -n 10.88.2XX.21 -g 10.2XX.1.1

Auf dem Hostsystem

  • vi ~/.ssh/config
 Host bridgefw
  Hostname 10.2XX.1.9
  User kit
  ProxyJump kit@fw
Key übertragen
  • ssh-copy-id bridgefw
Einloggen
  • ssh bridgefw

Was ist eine Layer 2 Firewall?

  • Eine normale Firewall arbeitet auf Layer 3 (IP-Ebene) und benötigt eine IP-Adresse im Datenpfad.
  • Eine Layer 2 Firewall greift dagegen auf Ethernet-Ebene (MAC) - sie kann transparent zwischen zwei Netzwerksegmente gestellt werden, ohne eine eigene IP-Adresse im Datenpfad zu benötigen.
  • Der Datenverkehr läuft über eine Bridge, die nftables zur Filterung nutzt.
  • Die Clients merken von der Firewall nichts: Gateway, Adressen und Subnetz bleiben unverändert.

Schaubild

Installation der Bridgeutils

  • apt install bridge-utils
  • Das Paket liefert die Skripte, mit denen ifupdown die Optionen bridge_ports, bridge_fd und bridge_stp auswertet.

/etc/network/interfaces

auto lo
iface lo inet loopback

auto enp0s3
iface enp0s3 inet static
 address 10.2XX.1.9/24
 gateway 10.2XX.1.1
 dns-nameservers 10.88.2XX.21
 dns-search it2XX.int

auto enp0s8
iface enp0s8 inet manual

auto enp0s9
iface enp0s9 inet manual

auto vmbr0
iface vmbr0 inet manual
    bridge_ports enp0s8 enp0s9
    bridge_fd 0
    bridge_stp no

Hinweise zur Konfiguration
enp0s3
  • Management-Interface mit eigener IP-Adresse. Es liegt nicht in der Bridge.
vmbr0 inet manual
  • Die Bridge bekommt bewusst keine IP-Adresse - sie arbeitet rein transparent.
bridge_fd 0
  • Forward Delay. Er wird nur bei aktivem STP genutzt: Die Ports durchlaufen dann die Zustände Listening und Learning, bevor sie Pakete weiterleiten.
  • Ohne STP schaltet der Kernel die Ports sofort auf Forwarding. Der Wert 0 macht das explizit.
bridge_stp no
  • STP (Spanning Tree Protocol) ist deaktiviert. Da nur zwei Ports vorhanden sind, ist kein Loop möglich und STP nicht notwendig.
Bridge starten
  • ifup vmbr0

Kontrolle der Bridge

Welche Ports gehören zur Bridge und in welchem Zustand sind sie?
  • bridge link show
Welche MAC-Adressen hat die Bridge an welchem Port gelernt? (FDB)
  • bridge fdb show br vmbr0 | grep -v permanent
Welche Interfaces gehören zu Bridgen
  • brctl show
bridge name	bridge id		STP enabled	interfaces
vmbr0		8000.76e085f914d6	no		enp0s8
							enp0s9

Erste Maschine hinte die Bridge Firewall plazieren

  • www -> Interface auf DMZ-OUT ändern
  • Ping mal von www nach 1.1.1.1
  • Kontrolle auf der bridgefw auf den Schnittstellen enp0s8 und enp0s9 per tcpdump

Bridge-Filterung

Arten von Bridge-Ketten

  • Die Bridge-Familie bietet fünf Kettenarten (Hooks):
prerouting
  • Hier können Pakete vor der Forward-Datenbank (FDB) Entscheidung gefiltert werden.
  • Die FDB liefert den Bridge-Port, der für eine bestimmte Ziel-MAC-Adresse verwendet wird.
  • Wenn es noch keinen Eintrag in der FDB für eine gegebene Ziel-MAC gibt, werden die Pakete an alle Bridge-Ports geflutet.
  • Nach der FDB-Entscheidung können Pakete entweder dem Eingangs- oder dem Weiterleitweg folgen.
input
  • Hier können Pakete gefiltert werden, die an den IP-Stack übergeben werden.
  • Wenn die Bridge-Schnittstelle eine IP-Adresse hat und Pakete an diese IP-Adresse gehen, folgen die Pakete diesem Pfad (die Pakete verlassen die Bridge und treten in den IP-Stack ein).
forward
  • Diese Hook filtert Pakete, die von einem Bridge-Port eingehen und an einen anderen Bridge-Port geliefert werden (der Bridge-Weiterleitungspfad).
  • Im vorliegenden Szenario wird ausschließlich diese Chain genutzt - die Bridge hat keine IP-Adresse im Datenpfad, es wird rein gebridged.
output
  • Hier können Pakete gefiltert werden, die vom IP-Stack kommen und deren Ziel ein Bridge-Port ist.
postrouting
  • Hier können Pakete gefiltert werden, die entweder vom IP-Stack kommen oder von einem anderen Bridge-Port weitergeleitet werden.

Bridge-Familie und br_netfilter

  • Gebridgte Pakete laufen normalerweise nur durch die Ketten der Bridge-Familie, nicht durch ip/inet-Tabellen.
  • Ist jedoch das Kernelmodul br_netfilter geladen (z.B. automatisch durch Docker), laufen sie zusätzlich durch die ip/inet-Hooks. Das führt zu schwer nachvollziehbaren Effekten.
  • Kontrolle:
lsmod | grep br_netfilter
  • Keine Ausgabe bedeutet: Modul nicht geladen, alles in Ordnung.

ARP

  • ARP ist im Gegensatz zur Layer 3 Firewall nicht automatisch freigeschaltet und muss explizit erlaubt werden.
  • Eine Layer 3 Firewall sieht ARP gar nicht, weil ARP kein IP-Protokoll ist. Die Bridge sieht dagegen jeden Ethernet-Frame.
  • Ohne ARP-Freischaltung ist keine Kommunikation im Netz möglich, da MAC-Adressen nicht aufgelöst werden können.
  • Beispiel zum Akzeptieren von ARP-Paketen: nft add rule bridge filter forward ether type arp accept

Zustandsabhängige Filterung

  • Die Bridge-Familie unterstützt Connection Tracking (Verbindungsverfolgung), ab Kernel 5.3.
  • Durch Matching auf den Verbindungsstatus (ct state) können bestehende Verbindungen automatisch durchgelassen werden, ohne jede Richtung explizit freizuschalten.
Die wichtigsten Zustände
new
  • Erstes Paket einer Verbindung.
established
  • Paket gehört zu einer bereits bekannten Verbindung.
related
  • Paket gehört zu einer bekannten Verbindung, ist aber eine eigene (z.B. ICMP-Fehlermeldung zu einer TCP-Verbindung).
Besonderheit in der Bridge
  • Connection Tracking gibt es hier nur für IP. ARP wird nicht verfolgt und braucht deshalb eigene Regeln.

Bridge Firewall

Regeln

Konzept
  • enp0s8 ist die offene Seite (z.B. Richtung Internet/unsicheres Netz)
  • enp0s9 ist die gefilterte Seite (z.B. internes Netz)
  • enp0s3 ist das Management-Interface im vertrauenswürdigen LAN, es wird hier nicht gefiltert
  • Die Bridge selbst hat keine IP-Adresse und ist aus den gefilterten Netzen nicht erreichbar
  • Policy ist drop - alles was nicht explizit erlaubt ist, wird verworfen
  • cat /etc/nftables.conf
#!/usr/sbin/nft -f

define open    = enp0s8
define filter  = enp0s9

flush ruleset

table bridge filter {
        chain forward {
                type filter hook forward priority 0; policy drop;

                # Bestehende Verbindungen durchlassen (Connection Tracking)
                ct state established,related accept

                # ARP freischalten (beide Richtungen notwendig)
                iif $open   ether type arp accept
                iif $filter ether type arp accept

                #### ICMP von filter nach open freischalten
                #iif $filter oif $open ip protocol icmp ct state new accept

                #### DNS von filter nach open freischalten (UDP und TCP)
                #iif $filter oif $open udp dport 53 ct state new accept
                #iif $filter oif $open tcp dport 53 ct state new accept

                #### HTTP von filter nach open freischalten
                #iif $filter oif $open tcp dport 80 ct state new accept

                #### HTTPS von filter nach open freischalten
                #iif $filter oif $open tcp dport 443 ct state new accept

                #### DHCP: Clients auf der filter-Seite, Server auf der open-Seite
                #iif $filter oif $open udp sport 68 udp dport 67 accept
                #iif $open oif $filter udp sport 67 udp dport 68 accept

                #### Alles von open nach filter freischalten
                #iif $open oif $filter ct state new accept

                # Abgelehnte Pakete loggen (sichtbar mit journalctl)
                # begrenzt auf 10 Meldungen pro Sekunde
                limit rate 10/second log prefix " nft-drop"
        }
}
Hinweis zur Reihenfolge
  • Die Regeln werden von oben nach unten abgearbeitet, das erste accept oder drop beendet die Prüfung.
  • established,related steht ganz oben, weil die meisten Pakete zu bestehenden Verbindungen gehören - das spart Rechenzeit.
Hinweis zu ICMP
  • Die ICMP-Regel matcht nur IPv4. IPv6 wird in diesem Szenario nicht betrachtet.
Hinweis zu DNS
  • DNS nutzt normalerweise UDP. Bei großen Antworten (z.B. DNSSEC) weicht es auf TCP aus. Ohne die TCP-Regel schlagen solche Anfragen scheinbar zufällig fehl.
Hinweis zu DHCP
  • Die DHCP-Regeln werden nur gebraucht, wenn Clients auf der gefilterten Seite ihre Adresse von einem Server auf der offenen Seite beziehen.
  • Connection Tracking hilft hier nicht: Der Client fragt per Broadcast an, die Antwort des Servers passt daher zu keiner bekannten Verbindung. Deshalb werden beide Richtungen ohne ct state freigeschaltet.
Hinweis zu VLANs
  • VLAN-getaggte Frames werden durch die Policy verworfen. Sollen getaggte Frames die Bridge passieren, sind eigene Regeln nötig. Das ist nicht Teil dieses Szenarios.
Hinweis zum Log
  • Das führende Leerzeichen in " nft-drop" ist Absicht - es verbessert die Lesbarkeit im Kernel-Log.
  • Die Begrenzung per limit verhindert, dass Broadcasts das Journal fluten. Pakete über dem Limit werden trotzdem verworfen, nur nicht mehr geloggt.

Regel Handling

Laden der Regeln
  • nft -f /etc/nftables.conf
Kontrolle der Regeln
  • nft list ruleset
Löschen der Regeln
  • nft flush ruleset
Regeln beim Booten laden
  • systemctl enable --now nftables
  • Der Dienst lädt beim Start /etc/nftables.conf.

Achtung: Fail-open

  • Eine Bridge ohne Regelwerk leitet alles weiter. Die Firewall ist dann ein einfaches Kabel.
  • Das passiert:
    • nach nft flush ruleset
    • wenn der Dienst nftables nicht aktiviert ist
    • wenn /etc/nftables.conf einen Syntaxfehler hat und nicht geladen wird
  • Nach jeder Änderung daher mit nft list ruleset prüfen, ob das Regelwerk wirklich aktiv ist.
  • Syntax vorher testen, ohne zu laden:
nft -c -f /etc/nftables.conf

Live Log der Regel Verstöße

  • journalctl -f -t kernel -g "nft-drop"

Verbindungen beobachten

  • apt install conntrack
Alle erfassten Verbindungen anzeigen
  • conntrack -L
Neue Verbindungen live verfolgen
  • conntrack -E

Fehlersuche mit Trace

  • Mit nftrace lässt sich der Weg eines Pakets Regel für Regel verfolgen.
  • Eine zusätzliche Chain markiert die interessierenden Pakete, hier ICMP:
nft add chain bridge filter trace '{ type filter hook prerouting priority 0; }'
nft add rule bridge filter trace ip protocol icmp meta nftrace set 1
  • In einem zweiten Terminal mitlesen:
nft monitor trace
  • Die Ausgabe zeigt für jedes markierte Paket jede durchlaufene Regel und das Ergebnis (accept/drop).
  • Zum Entfernen einfach das Regelwerk neu laden:
nft -f /etc/nftables.conf

Übung

  • Regelwerk wie oben laden, alle mit #### markierten Regeln sind auskommentiert.
  • Parallel den Live-Log laufen lassen.
Schritt 1
  • Von einem Client auf der gefilterten Seite das Gateway anpingen. Was passiert, was steht im Log?
  • ICMP-Regel aktivieren, neu laden, erneut testen.
Schritt 2
  • Mit dig eine Namensauflösung testen, dann die DNS-Regeln aktivieren.
Schritt 3
  • Mit curl eine HTTP- und eine HTTPS-Seite abrufen, dann die Regeln für Port 80 und 443 aktivieren.
Schritt 4
  • Mit conntrack -L die entstandenen Verbindungen ansehen.
  • Warum kommt die Antwort des Webservers durch, obwohl es keine Regel von open nach filter gibt?
Schritt 5
  • Die beiden ARP-Regeln auskommentieren und neu laden. Was passiert mit bestehenden und mit neuen Verbindungen?
  • Tipp: ip neigh flush all auf dem Client leert den ARP-Cache.
Schritt 6
  • Den Dienst nftables stoppen bzw. nft flush ruleset ausführen und erneut testen. Was bedeutet das für den Betrieb?

Weiterführende Artikel