Subsections of Linux

Firewall Freischaltung mittels Wesberver Log

Möchte man Besucher für Dienste (Ports) freischalten, kann beispielsweise ein Webserver-Log herangezogen werden und auf Grundlage des HTTP-Status-Codes eine Freischaltung erfolgen. Hierzu ein einfaches Skript als Beispiel, das je nach Bedarf angepasst werden kann.

#!/usr/bin/bash

# Datei zum auslesen der Zugriffe
file="/var/log/nginx/my-host.access.log"

while true; do
    # Datei folgend öffnen, filtern und zeilenweise lesen
    tail -n1 -F "${file}" --retry | grep --line-buffered '"GET / HTTP/1.1" 200'  | while read line;do
        # IP-Adresse aus der Zeile extrahieren (Split nach Leerzeichen)
        ip=${line%% *};
        echo "whitelisting IP [$ip]";
        # Hinzufügen der IP-Adresse in IP-Set myset mit 24 Stunden Timeout
        nft add element inet filter myset { ${line%% *} timeout 24h };
    done
done

Das Skript öffnet hierbei mittels tail das Access-Log und folgt diesem. Logrotates und Verschiebungen werden ebenfalls berücksichtigt und im Anschluss gefolgt. Existiert ein Logfile noch nicht, wird nach dem Anlegen auch dieses erkannt und herangezogen (-F und –retry).
Nach der Pipe wird mittels Grep auf den HTTP-Code 200 geprüft und nur Zeilen mit erfolgreichem Aufruf von / ermittelt. Dies kann auch ein gänzlich anderer Pfad wie zum Beispiel /auth-xyz sein. Je nach persönlichem Empfinden.
Die IP-Adresse wird im Anschluss ermittelt und an nft übergeben. Der Befehl schreibt die IP-Adresse anschließend mit einem Timeout von 24 Stunden in das Set myset.
In NFTables sollte dieses Set vorab existieren und deshalb in der Konfiguration hinterlegt werden! Außerdem muss das Set noch in Firewall-Regeln hinterlegt werden!

table inet filter {

    set myset {
        type ipv4_addr
        flags timeout
    }
    
.....

}

Im Nginx sollte dann auf dem vHost (my-host) zum Beispiel ein Basic Auth aktiviert werden. Benutzer die sich nicht korrekt anmelden werden eine 403 Meldung zurückbekommen, während korrekt Authentifizierte Benutzer einen 200er Code erhalten.
Diese Meldungen erscheinen im Log und werden anschließend verarbeitet.


Firewall-Beispiele mit Firewalld

Warning

Fehlerhafte Konfigurationen können zu Netzwerkstörungen führen!

Docker auf externe Netze beschränken

Zuerst wird ein IPSet angelegt. Dies kann als XML File passieren oder mittels Befehlen:

<?xml version="1.0" encoding="utf-8"?>
<ipset type="hash:ip">
  <entry>10.0.0.0/8</entry>
  <entry>172.16.0.0/12</entry>
  <entry>192.168.0.0/16</entry>
</ipset>
# fügt ein neues IPSET der Konfiguration hinzu
firewall-cmd --permanent --new-ipset=RFC_1819 --type=hash:ip
# private IP-Adressen hinzufügen
firewall-cmd --permanent --ipset=RFC_1819 --add-entry=10.0.0.0/8
firewall-cmd --permanent --ipset=RFC_1819 --add-entry=172.16.0.0/12
firewall-cmd --permanent --ipset=RFC_1819 --add-entry=192.168.0.0/16

# oder entfernen / löschen
firewall-cmd --permanent --ipset=RFC_1819 --remove-entry=10.0.0.0/8
firewall-cmd --permanent --delete-ipset test

Nach der Konfiguration ist das Set noch nicht geladen. Also fügen wir noch die Firewall-Regel (Policy) hinzu.
Grundsätzlich können Rules viele Einstellungen abbilden, aber keine Ziel-Adressen mittels IPSETs, deshalb wird eine Firewalld Policy verwendet:

<?xml version="1.0" encoding="utf-8"?>
<!-- Standardverfahren ist REJECT, kann aber auch DROP gesetzt werden -->
<policy target="REJECT">
  <!-- IPAdressen von Docker werden maskiert (Source NAT) -->
  <masquerade/>
  <!-- falls ein lokaler DNS Resolver verwendet wird, sollte Port 53 erlaubt werden -->
  <rule family="ipv4">
    <destination ipset="RFC_1819"/>
    <port port="53" protocol="udp"/>
    <accept/>
  </rule>
  <rule family="ipv4">
    <destination ipset="RFC_1819"/>
    <port port="53" protocol="tcp"/>
    <accept/>
  </rule>
  <!-- IP-Adressen die nicht im IPSET RFC_1819 sind, werden erlaubt -->
  <rule family="ipv4">
    <destination ipset="RFC_1819" invert="True"/>
    <accept/>
  </rule>
  <!-- aus Zone docker -->
  <ingress-zone name="docker"/>
  <!-- an Zone public oder home -->
  <egress-zone name="public"/>
  <egress-zone name="home"/>
</policy>

Wichtig hierbei ist, dass die Docker Bridge (hier docker0) sich in der Zone docker befindet und das ausgehende Interface in home oder public. Dies dies nicht der Fall, muss die Konfiguration angepasst werden.

Die Zone docker kann angelegt werden:

<?xml version="1.0" encoding="utf-8"?>
<zone target="DROP">
  <interface name="docker0"/>
  <source address="172.17.0.1/16"/>
</zone>

Grundsätzlich werden Verbindungen von diesem Interface verworfen (DROP), wodurch kein Container auf den Docker-Host selbst zugreifen kann.
Sollte dies nicht gewünscht sein, muss die Konfiguration angepasst werden…

Reload
firewall-cmd --reload

Netplan, Systemd Dummy-Interface

Vorwort

Nach einigen Recherchen hat sich herausgestellt, dass Netplan in der aktuellen Version (Stand heute) keine Dummy Interfaces anlegen kann (siehe Link unten). Netplan hat es endlich geschafft und kann Dummy Interfaces \o/

Also gibt es nun 2 Anleitungen für Netplan und Systemd.

Dummy Interfaces vorab anlegen

Die Dummy-Interfaces werden von einem Kernel Modul bereitgestellt, welches im Regelfall erst geladen wird, wenn es notwendig ist.
Durch die Hinzugabe von Parametern lassen sich bereits beim Laden mehrere Schnittstellen anlegen. Diese werden der Menge nach durchnummeriert. Dies ist für die Anleitung absolut nicht notwendig, möchte ich aber mal erwähnt haben (“unnützes” Zusatzwissen)

modprobe dummy numdummies=5

$ ip -o link | grep dummy
44572: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/ether 72:a0:77:02:5e:57 brd ff:ff:ff:ff:ff:ff
44573: dummy1: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/ether 36:dd:a2:0c:81:d0 brd ff:ff:ff:ff:ff:ff
44574: dummy2: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/ether 1e:f3:22:bc:6a:74 brd ff:ff:ff:ff:ff:ff
44575: dummy3: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/ether 56:ef:c3:3b:9a:b9 brd ff:ff:ff:ff:ff:ff
44576: dummy4: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/ether 5a:92:bf:48:9f:82 brd ff:ff:ff:ff:ff:ff

Dummy via Systemd-Networkd

Anlegen der Dummy-Schnittstelle
# File: /etc/systemd/network/99-dummy10.netdev

[NetDev]
Name=dummy10
Kind=dummy
Konfiguration der IP-Adresse(n)

Dieser Schritt ist nicht zwingend nötig, da die Konfiguration der IP-Adresse auch via Netplan erfolgen kann.

# File: /etc/systemd/network/99-dummy10.network

[Match]
Name=dummy10

[Network]
Address=10.10.10.33/24
Laden der Interfaces
systemctl reload systemd-networkd

Dummy via Netplan

Gemäß der offiziellen Doku https://netplan.readthedocs.io/en/stable/netplan/#properties-for-device-type-dummy-devices:

network:
  dummy-devices:
    dummy0:
      addresses:
        - 192.168.0.123/24
    dummy1:
      addresses:
        - 192.168.1.123/24
    ...

Im Anschluss Netplan laden:

netplan apply