Rocky fw nftabels: Unterschied zwischen den Versionen

Aus Xinux Wiki
Zur Navigation springen Zur Suche springen
 
(7 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 11: Zeile 11:
 
! Interface !! Zone !! Wert !! Erläuterung
 
! Interface !! Zone !! Wert !! Erläuterung
 
|-
 
|-
| '''enp0s3''' || wan || 192.168.HS.2XX/24 || Bridge Adapter: br0
+
| '''enp0s3''' || WAN || 192.168.HS.2XX/24 || Bridge Adapter: br0
 
|-
 
|-
 
| '''GW''' || || 10.88.2XX.1 || GATEWAY
 
| '''GW''' || || 10.88.2XX.1 || GATEWAY
Zeile 17: Zeile 17:
 
| '''NS''' || || 192.168.HS.88 || Resolver
 
| '''NS''' || || 192.168.HS.88 || Resolver
 
|-
 
|-
| '''enp0s8''' || dmz || 10.88.2XX.1/24|| Internal Network: DMZ
+
| '''enp0s8''' || DMZ || 10.88.2XX.1/24|| Internal Network: DMZ
 
|-
 
|-
| '''enp0s9''' || lan || 172.26.2XX.1/24 || Internal Network: LAN
+
| '''enp0s9''' || LAN || 172.26.2XX.1/24 || Internal Network: LAN
 
|-
 
|-
 
| '''GW''' || || 192.168.HS.254 || GATEWAY
 
| '''GW''' || || 192.168.HS.254 || GATEWAY
Zeile 42: Zeile 42:
 
! Von !! Nach !! Erlaubt !! Gesperrt
 
! Von !! Nach !! Erlaubt !! Gesperrt
 
|-
 
|-
| lan || wan || alles || —
+
| LAN || WAN || alles || —
 
|-
 
|-
| lan || dmz || alles (SSH für Ansible, DNS, HTTP ...) || —
+
| LAN || DMZ || alles (SSH für Ansible, DNS, HTTP ...) || —
 
|-
 
|-
| dmz || wan || alles || —
+
| DMZ || WAN || alles || —
 
|-
 
|-
| wan || dmz || UDP+TCP/53 nur auf ns, TCP/80+443 nur auf http || alles andere
+
| WAN || DMZ || UDP+TCP/53 nur auf ns, TCP/80+443 nur auf http || alles andere
 
|-
 
|-
| wan || lan || — || alles
+
| WAN || LAN || — || alles
 
|-
 
|-
| dmz || lan || — || alles
+
| DMZ || LAN || — || alles
 
|}
 
|}
  
Zeile 68: Zeile 68:
 
;Die WAN-Verbindung bekommt eine feste IP. Da die Connection bereits existiert, wird sie per mod angepasst.
 
;Die WAN-Verbindung bekommt eine feste IP. Da die Connection bereits existiert, wird sie per mod angepasst.
 
* nmcli con mod enp0s3 ipv4.method manual ipv4.addresses 192.168.HS.2XX/24 ipv4.gateway 192.168.HS.254 ipv4.dns 192.168.HS.88
 
* nmcli con mod enp0s3 ipv4.method manual ipv4.addresses 192.168.HS.2XX/24 ipv4.gateway 192.168.HS.254 ipv4.dns 192.168.HS.88
 +
* nmcli con mod enp0s3 +ipv4.routes "10.88.0.0/16 192.168.HS.88"
 
* nmcli con up enp0s3
 
* nmcli con up enp0s3
  
Zeile 91: Zeile 92:
  
 
== nftables ==
 
== nftables ==
 +
=== Tabellen ===
 +
 +
* Eine Skizze über die Reihenfolge der Hooks.
 +
* Als erstes greift der Prerouting-Hook
 +
* Je nachdem wie geroutet wird greift dann entweder Input- oder Forward-Hook
 +
* Falls ein lokaler Prozess ein Paket sendet, dann greift der Output-Hook
 +
* Als letztes kann man das Paket mit dem Postrouting-Hook beeinflußen
 +
 +
{{#drawio:nft-inet1}}
  
 
=== firewalld deaktivieren ===
 
=== firewalld deaktivieren ===
Zeile 101: Zeile 111:
 
* systemctl enable --now nftables
 
* systemctl enable --now nftables
  
=== Regelwerk (mit Variablen) ===
+
=== Variablen-Datei ===
;Alle 2XX-Werte und der Admin-Host stehen oben als Variablen für einen neuen Standort reicht es, nur diesen Block zu ändern
+
;Alle standortspezifischen Werte stehen getrennt vom Regelwerk in einer eigenen Datei wird per include eingebunden
* vim /etc/sysconfig/nftables.conf
+
* vim /etc/sysconfig/nftables-vars.conf
  
 
<pre>
 
<pre>
#!/usr/sbin/nft -f
+
define WANDEV = enp0s3
 +
define DMZDEV = enp0s8
 +
define LANDEV = enp0s9
  
flush ruleset
+
define WANIP  = 192.168.HS.2XX
 +
define DMZ    = 10.88.2XX.0/24
 +
define LAN    = 172.26.2XX.0/24
  
# --- Variablen ---
+
define NS_IP   = 10.88.2XX.21
define WAN_IF  = enp0s3
+
define HTTP_IP = 10.88.2XX.11
define DMZ_IF   = enp0s8
 
define LAN_IF  = enp0s9
 
  
define NS_IP    = 10.88.2XX.21
+
define HOST = 192.168.HS.TN
define HTTP_IP  = 10.88.2XX.11
 
  
define ADMIN_IP = 192.168.HS.TN
+
# Ziele, die beim Verlassen ueber WANDEV NICHT genattet werden sollen
 
 
# Ziele, die beim Verlassen über WAN_IF NICHT genattet werden sollen
 
 
# (Rest der Schulungs-DMZs und das Trainingsnetz selbst - echte Quell-IP bleibt sichtbar, z.B. fuers SIEM)
 
# (Rest der Schulungs-DMZs und das Trainingsnetz selbst - echte Quell-IP bleibt sichtbar, z.B. fuers SIEM)
 
define NO_NAT_NETS = { 10.88.0.0/16, 192.168.HS.0/24 }
 
define NO_NAT_NETS = { 10.88.0.0/16, 192.168.HS.0/24 }
 +
</pre>
 +
 +
=== Regelwerk ===
 +
;ct state established,related steht als erste Zeile in jeder Chain und deckt den Rueckverkehr ab. Jede Freischaltung fuer neue Verbindungen steht danach explizit als eigene ct state new-Zeile. Was am Ende keiner Regel entspricht, wird geloggt und faellt der policy drop zum Opfer.
 +
* vim /etc/sysconfig/nftables.conf
 +
 +
<pre>
 +
#!/usr/sbin/nft -f
 +
include "/etc/sysconfig/nftables-vars.conf"
 +
flush ruleset
  
 
table inet filter {
 
table inet filter {
  
 
     chain input {
 
     chain input {
         type filter hook input priority 0; policy drop;
+
         type filter hook input priority filter; policy drop;
 
 
        iifname "lo" accept
 
        ct state invalid drop
 
 
 
        icmp type echo-request ct state new,established,related accept
 
        icmpv6 type { echo-request, nd-neighbor-solicit, nd-neighbor-advert } ct state new,established,related accept
 
 
 
        # Rueckverkehr fuer Verbindungen, die die Firewall selbst aufbaut (DNS, dnf-Updates ...)
 
 
         ct state established,related accept
 
         ct state established,related accept
 
+
         ct state new iif "lo" accept
         # SSH zur Firewall selbst: aus dem LAN immer, aus dem WAN nur vom Admin-Host
+
         ct state new iif $LANDEV ip saddr $LAN tcp dport 22 accept
         iifname $LAN_IF tcp dport 22 ct state new,established accept
+
        ct state new iif $WANDEV ip saddr $HOST tcp dport 22 accept
        iifname $WAN_IF ip saddr $ADMIN_IP tcp dport 22 ct state new,established accept
+
        ct state new icmp type echo-request accept
 +
        ct state new iif $LANDEV udp dport 67 accept
 +
        log prefix " --nftables-drop-input-- "
 
     }
 
     }
  
 
     chain forward {
 
     chain forward {
         type filter hook forward priority 0; policy drop;
+
         type filter hook forward priority filter; policy drop;
 
+
         ct state established,related accept
        ct state invalid drop
 
 
 
         icmp type echo-request ct state new,established,related accept
 
  
 
         # lan -> wan und lan -> dmz: alles erlaubt
 
         # lan -> wan und lan -> dmz: alles erlaubt
         iifname $LAN_IF ct state new,established,related accept
+
         ct state new iif $LANDEV accept
  
 
         # dmz -> wan: alles erlaubt
 
         # dmz -> wan: alles erlaubt
         iifname $DMZ_IF oifname $WAN_IF ct state new,established,related accept
+
         ct state new iif $DMZDEV oif $WANDEV accept
  
 
         # wan -> dmz: nur DNS auf ns, HTTP/HTTPS auf http
 
         # wan -> dmz: nur DNS auf ns, HTTP/HTTPS auf http
         iifname $WAN_IF oifname $DMZ_IF ip daddr $NS_IP udp dport 53 ct state new,established,related accept
+
         ct state new iif $WANDEV oif $DMZDEV ip daddr $NS_IP udp dport 53 accept
        iifname $WAN_IF oifname $DMZ_IF ip daddr $NS_IP tcp dport 53 ct state new,established,related accept
+
        ct state new iif $WANDEV oif $DMZDEV ip daddr $NS_IP tcp dport 53 accept
        iifname $WAN_IF oifname $DMZ_IF ip daddr $HTTP_IP tcp dport { 80, 443 } ct state new,established,related accept
+
        ct state new iif $WANDEV oif $DMZDEV ip daddr $HTTP_IP tcp dport { 80, 443 } accept
  
         # wan -> lan und dmz -> lan: keine Regel = drop (Policy greift)
+
         # wan -> lan und dmz -> lan: keine Regel, faellt durch zum log/drop
 +
        log prefix "--nftables-drop-forward--"
 
     }
 
     }
  
 
     chain output {
 
     chain output {
         type filter hook output priority 0; policy accept;
+
         type filter hook output priority filter; policy drop;
 +
        ct state established,related accept
 +
        ct state new accept
 +
        log prefix " --nftables-drop-output-- "
 
     }
 
     }
 
}
 
}
  
 
table inet nat {
 
table inet nat {
 
 
     chain postrouting {
 
     chain postrouting {
 
         type nat hook postrouting priority 100; policy accept;
 
         type nat hook postrouting priority 100; policy accept;
  
 
         # Interne Ziele: keine Maskierung, echte Quell-IP bleibt erhalten
 
         # Interne Ziele: keine Maskierung, echte Quell-IP bleibt erhalten
         ip daddr $NO_NAT_NETS return
+
         ip saddr $DMZ ip daddr $NO_NAT_NETS return
  
         # Alles andere Richtung Internet: maskieren
+
         # Alles andere Richtung Internet: SNAT auf die feste WAN-IP
         oifname $WAN_IF masquerade
+
         ip saddr $DMZ oif $WANDEV snat to $WANIP
 +
        ip saddr $LAN oif $WANDEV snat to $WANIP
 
     }
 
     }
 
}
 
}
Zeile 192: Zeile 206:
 
* nft list table inet filter
 
* nft list table inet filter
 
* nft list table inet nat
 
* nft list table inet nat
 +
* journalctl -k -f | grep nftables-drop
 +
===Conntrack===
 +
;Installation
 +
* dnf install -y conntrack
 +
;Kontrolle
 +
* conntrack -L
  
 
== Kea DHCP4 für das LAN ==
 
== Kea DHCP4 für das LAN ==

Aktuelle Version vom 6. Juli 2026, 13:22 Uhr

Die Firewall

Ziel

Die Firewall trennt drei Netzbereiche voneinander: das Schulungsnetz (WAN), die DMZ und das interne LAN. Sie übernimmt gleichzeitig die Aufgaben eines Routers, eines DHCP-Servers für das LAN und kontrolliert den gesamten Netzverkehr zwischen den Zonen.

Die Filterung erfolgt über nftables mit einer einzigen Regeldatei. Alle standortspezifischen Werte (Interfaces, IPs, Admin-Host) stecken oben in Variablen – für einen neuen Standort reicht es, nur diesen Block anzupassen.

Plan

Interface Zone Wert Erläuterung
enp0s3 WAN 192.168.HS.2XX/24 Bridge Adapter: br0
GW 10.88.2XX.1 GATEWAY
NS 192.168.HS.88 Resolver
enp0s8 DMZ 10.88.2XX.1/24 Internal Network: DMZ
enp0s9 LAN 172.26.2XX.1/24 Internal Network: LAN
GW 192.168.HS.254 GATEWAY
FQDN fw.it2XX.int Fully Qualified Domain Name
SHORT fw Short Name
DOM it2XX.int Domain Name
ROUTE 10.88.0.0/16 192.168.HS.88

Dienste auf der Firewall

nftables
Paketfilterung, Masquerading (ersetzt firewalld)
Kea DHCP4
IP-Vergabe für das LAN (172.26.2XX.0/24)

Regelwerk

Von Nach Erlaubt Gesperrt
LAN WAN alles
LAN DMZ alles (SSH für Ansible, DNS, HTTP ...)
DMZ WAN alles
WAN DMZ UDP+TCP/53 nur auf ns, TCP/80+443 nur auf http alles andere
WAN LAN alles
DMZ LAN alles
lan ist vertrauenswürdig
Aus dem internen Netz darf alles raus – sowohl ins WAN als auch in die DMZ. So kann Ansible von client.it2XX.int per SSH alle DMZ-Maschinen erreichen.
wan → dmz gezielt
Aus dem Internet kommen nur die Dienste rein, die wirklich öffentlich sein sollen – und nur auf die jeweilige Ziel-IP.
dmz → lan gesperrt
LDAP liegt jetzt in der DMZ – kein Grund mehr für Verbindungen aus der DMZ ins LAN.

Umsetzung

Netzwerkkonfiguration

Hostname setzen

  • hostnamectl set-hostname fw.it2XX.int

enp0s3 (WAN)

Die WAN-Verbindung bekommt eine feste IP. Da die Connection bereits existiert, wird sie per mod angepasst.
  • nmcli con mod enp0s3 ipv4.method manual ipv4.addresses 192.168.HS.2XX/24 ipv4.gateway 192.168.HS.254 ipv4.dns 192.168.HS.88
  • nmcli con mod enp0s3 +ipv4.routes "10.88.0.0/16 192.168.HS.88"
  • nmcli con up enp0s3

Tabula Rasa

Rocky legt für neue Interfaces automatisch Connections mit generischen Namen an – diese werden gelöscht
  • nmcli con delete "Wired connection 1"
  • nmcli con delete "Wired connection 2"

enp0s8 (DMZ)

Neue Connection mit explizitem Namen – kein Gateway, kein DNS nötig
  • nmcli con add type ethernet ifname enp0s8 con-name enp0s8 ipv4.method manual ipv4.addresses 10.88.2XX.1/24
  • nmcli con up enp0s8

enp0s9 (LAN)

Das LAN-Interface wird Gateway für alle internen Clients
  • nmcli con add type ethernet ifname enp0s9 con-name enp0s9 ipv4.method manual ipv4.addresses 172.26.2XX.1/24
  • nmcli con up enp0s9

IP-Forwarding aktivieren

Ohne IP-Forwarding leitet der Kernel keine Pakete zwischen den Interfaces weiter – die Firewall wäre kein Router
  • echo "net.ipv4.ip_forward=1" > /etc/sysctl.d/99-forwarding.conf
  • sysctl -p /etc/sysctl.d/99-forwarding.conf

nftables

Tabellen

  • Eine Skizze über die Reihenfolge der Hooks.
  • Als erstes greift der Prerouting-Hook
  • Je nachdem wie geroutet wird greift dann entweder Input- oder Forward-Hook
  • Falls ein lokaler Prozess ein Paket sendet, dann greift der Output-Hook
  • Als letztes kann man das Paket mit dem Postrouting-Hook beeinflußen

firewalld deaktivieren

Bevor nftables übernimmt, muss firewalld komplett raus – sonst kollidieren beide beim Regelaufbau (nftables-Backend vs. firewalld-Backend)
  • systemctl disable --now firewalld
  • dnf remove -y firewalld

Installation

  • dnf install -y nftables
  • systemctl enable --now nftables

Variablen-Datei

Alle standortspezifischen Werte stehen getrennt vom Regelwerk in einer eigenen Datei – wird per include eingebunden
  • vim /etc/sysconfig/nftables-vars.conf
define WANDEV = enp0s3
define DMZDEV = enp0s8
define LANDEV = enp0s9

define WANIP  = 192.168.HS.2XX
define DMZ    = 10.88.2XX.0/24
define LAN    = 172.26.2XX.0/24

define NS_IP   = 10.88.2XX.21
define HTTP_IP = 10.88.2XX.11

define HOST = 192.168.HS.TN

# Ziele, die beim Verlassen ueber WANDEV NICHT genattet werden sollen
# (Rest der Schulungs-DMZs und das Trainingsnetz selbst - echte Quell-IP bleibt sichtbar, z.B. fuers SIEM)
define NO_NAT_NETS = { 10.88.0.0/16, 192.168.HS.0/24 }

Regelwerk

ct state established,related steht als erste Zeile in jeder Chain und deckt den Rueckverkehr ab. Jede Freischaltung fuer neue Verbindungen steht danach explizit als eigene ct state new-Zeile. Was am Ende keiner Regel entspricht, wird geloggt und faellt der policy drop zum Opfer.
  • vim /etc/sysconfig/nftables.conf
#!/usr/sbin/nft -f
include "/etc/sysconfig/nftables-vars.conf"
flush ruleset

table inet filter {

    chain input {
        type filter hook input priority filter; policy drop;
        ct state established,related accept
        ct state new iif "lo" accept
        ct state new iif $LANDEV ip saddr $LAN tcp dport 22 accept
        ct state new iif $WANDEV ip saddr $HOST tcp dport 22 accept
        ct state new icmp type echo-request accept
        ct state new iif $LANDEV udp dport 67 accept
        log prefix " --nftables-drop-input-- "
    }

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

        # lan -> wan und lan -> dmz: alles erlaubt
        ct state new iif $LANDEV accept

        # dmz -> wan: alles erlaubt
        ct state new iif $DMZDEV oif $WANDEV accept

        # wan -> dmz: nur DNS auf ns, HTTP/HTTPS auf http
        ct state new iif $WANDEV oif $DMZDEV ip daddr $NS_IP udp dport 53 accept
        ct state new iif $WANDEV oif $DMZDEV ip daddr $NS_IP tcp dport 53 accept
        ct state new iif $WANDEV oif $DMZDEV ip daddr $HTTP_IP tcp dport { 80, 443 } accept

        # wan -> lan und dmz -> lan: keine Regel, faellt durch zum log/drop
        log prefix "--nftables-drop-forward--"
    }

    chain output {
        type filter hook output priority filter; policy drop;
        ct state established,related accept
        ct state new accept
        log prefix " --nftables-drop-output-- "
    }
}

table inet nat {
    chain postrouting {
        type nat hook postrouting priority 100; policy accept;

        # Interne Ziele: keine Maskierung, echte Quell-IP bleibt erhalten
        ip saddr $DMZ ip daddr $NO_NAT_NETS return

        # Alles andere Richtung Internet: SNAT auf die feste WAN-IP
        ip saddr $DMZ oif $WANDEV snat to $WANIP
        ip saddr $LAN oif $WANDEV snat to $WANIP
    }
}

Laden und aktivieren

Erst syntaktisch prüfen, dann aktivieren – so gibt es keinen Reboot-Ausschluss durch einen Tippfehler
  • nft -c -f /etc/sysconfig/nftables.conf
  • systemctl restart nftables

Kontrolle

  • nft list ruleset
  • nft list table inet filter
  • nft list table inet nat
  • journalctl -k -f | grep nftables-drop

Conntrack

Installation
  • dnf install -y conntrack
Kontrolle
  • conntrack -L

Kea DHCP4 für das LAN

Installation

  • dnf install -y kea

Konfiguration

Kea lauscht nur auf enp0s9 (LAN) und verteilt IPs im Bereich .100–.200.
  • vim /etc/kea/kea-dhcp4.conf
{
  "Dhcp4": {
    "interfaces-config": {
      "interfaces": [ "enp0s9" ]
    },
    "lease-database": {
      "type": "memfile",
      "persist": true,
      "name": "/var/lib/kea/kea-leases4.csv"
    },
    "valid-lifetime": 3600,
    "subnet4": [
      {
        "id": 1,
        "subnet": "172.26.2XX.0/24",
        "pools": [ { "pool": "172.26.2XX.100 - 172.26.2XX.200" } ],
        "option-data": [
          { "name": "routers", "data": "172.26.2XX.1" },
          { "name": "domain-name-servers", "data": "10.88.2XX.21" },
          { "name": "domain-name", "data": "it2XX.int" }
        ]
      }
    ]
  }
}

Start

  • systemctl enable --now kea-dhcp4

Kontrolle

  • ss -lnup | grep 67
  • systemctl status kea-dhcp4
  • journalctl -fu kea-dhcp4
  • cat /var/lib/kea/kea-leases4.csv