Fail2ban sync geändert
This commit is contained in:
1 parent
a663156fc7
commit
0755585d63
2 files changed
+250
-47
No files matched your search
+237
-47
@@ -18,7 +18,7 @@ Das eigentliche Blocking erfolgt auf Layer 3/4:
|
||||
|
||||
* **IP-Adresse** wird geblockt.
|
||||
* **Protokollunabhängig.**
|
||||
* **Umsetzung:** Via `nftables` (Kernel).
|
||||
* **Umsetzung:** Via `iptables`/`ipset` (Kernel).
|
||||
|
||||
Dieser Prozess erfolgt optimal auf dem Proxy (**proxyserver**), da:
|
||||
* Dies der erste Eintrittspunkt in das Netzwerk ist.
|
||||
@@ -32,8 +32,12 @@ Wenn das Blocking ausschließlich auf dem Backend erfolgt:
|
||||
1. Paket trifft auf dem Proxy ein.
|
||||
2. Proxy akzeptiert die Verbindung.
|
||||
3. Proxy leitet den Request an das Backend weiter.
|
||||
4. Backend erkennt den Angriff.
|
||||
5. Backend blockt die IP lokal.
|
||||
4. Backend erkennt den Angriff (die Client-IP steht zwar in der Log,
|
||||
aber der eigentliche Verbindungspeer des Backends ist der Proxy).
|
||||
5. Ein lokaler Block auf dem Backend ist wirkungslos: In der Firewall des
|
||||
Backends ist die Client-IP nie der Quelladresse – der gesamte Traffic
|
||||
kommt von der Proxy-IP. Würde man stattdessen die Proxy-IP bannen,
|
||||
wären **alle** Clients gleichzeitig blockiert.
|
||||
|
||||
**Daraus resultierende Probleme:**
|
||||
* Der Proxy verarbeitet weiterhin Requests des Angreifers.
|
||||
@@ -55,7 +59,7 @@ Wenn das Blocking ausschließlich auf dem Backend erfolgt:
|
||||
2. Proxy leitet diesen initial weiter.
|
||||
3. Backend erkennt den Angriff via Fail2Ban.
|
||||
4. Backend meldet die IP an den Proxy.
|
||||
5. Proxy trägt die IP in `nftables` ein.
|
||||
5. Proxy trägt die IP in die Firewall ein.
|
||||
6. Alle weiteren Pakete werden bereits am Proxy verworfen.
|
||||
|
||||
### Effekt
|
||||
@@ -89,60 +93,246 @@ Blocking auf dem Backend ist funktional, aber ineffizient. Blocking auf dem Prox
|
||||
**Die Lösung:** Erkennung auf Layer 7 (Backend) und Durchsetzung auf Layer 3 (Proxy).
|
||||
|
||||
---
|
||||
# Fail2Ban: Proxy Forwarding Configuration (Client)
|
||||
|
||||
Diese Dokumentation beschreibt die Konfiguration des Backend-Clients (**clientserver**), um erkannte Angriffe auf Layer 7 an den Proxy (**proxyserver**) weiterzureichen, damit diese dort auf Layer 3 blockiert werden können.
|
||||
# Fail2Ban: Proxy Forwarding via rsyslog (Client → Proxy)
|
||||
|
||||
## 1. Voraussetzungen
|
||||
Diese Dokumentation beschreibt die aktuelle Implementation (Stand: Okt 2026).
|
||||
Die frühere Lösung – pro Ban eine SSH-Verbindung vom Client zum Proxy mit
|
||||
`fail2ban-client set recidive banip <ip>` – wurde verworfen:
|
||||
|
||||
* **SSH-Zugriff:** Vom Client (clientserver) zum Proxy muss eine Verbindung bestehen.
|
||||
* **SSH-Key Authentifizierung:** Muss passwortlos (Key-basiert) eingerichtet sein.
|
||||
* **SSH-Port:** Muss in der SSH-Config des Root-Users hinterlegt sein.
|
||||
* **Fail2Ban:** Muss auf beiden Systemen installiert und aktiv sein.
|
||||
* **SSH-Storms beim fail2ban-Neustart:** Beim Restart feuern alle Jails ihre
|
||||
„Restore Ban“-Listen nach → dutzende SSH-Sessionen in wenigen Sekunden.
|
||||
* **Lockout-Risiko:** Der Proxy bannt die IP auf *allen* Ports (inkl. 22) →
|
||||
der SSH-Transport blockiert sich selbst.
|
||||
* **Skalierung:** Bei mehreren Backend-VMs summiert sich der SSH-Aufwand.
|
||||
|
||||
## 2. SSH Konfiguration
|
||||
Konfiguration für den schnellen, passwortlosen Zugriff auf den Proxy.
|
||||
Die neue Lösung nutzt **keinen SSH-Zugriff mehr**: Ban-/Unban-Ereignisse
|
||||
werden aus dem fail2ban-Log per **rsyslog (UDP 514)** an den Proxy gesendet,
|
||||
wo ein einzelnes Jail die Regeln in die Firewall schreibt.
|
||||
|
||||
**Datei:** `/root/.ssh/config`
|
||||
```ssh
|
||||
Host proxy
|
||||
HostName proxy.myserver.com
|
||||
User root
|
||||
Port 22
|
||||
IdentityFile /root/.ssh/clientserverproxy
|
||||
IdentitiesOnly yes
|
||||
## 1. Architektur
|
||||
|
||||
```
|
||||
clientserver (L7 – Erkennung) proxyserver (L3 – Enforcement)
|
||||
───────────────────────────── ──────────────────────────────
|
||||
fail2ban-Jails (Apache, sshd, ...)
|
||||
→ /var/log/fail2ban.log
|
||||
→ rsyslog imfile
|
||||
→ UDP 514 ──────────────────────────────────► rsyslog imudp
|
||||
→ /var/log/f2bexport.log
|
||||
→ fail2ban-Jail „remote-bans“
|
||||
→ iptables/ipset DROP (allports)
|
||||
|
||||
Unban-Zeilen:
|
||||
f2b-unban.sh (systemd-Service, tail auf
|
||||
/var/log/f2bexport.log)
|
||||
→ fail2ban-client set remote-bans unbanip <ip>
|
||||
```
|
||||
|
||||
Merkmale:
|
||||
* **Kein SSH**, keine Verbindung pro Ban – nur Log-Forwarding.
|
||||
* **Ein einziges Jail** auf dem Proxy, egal wieviele Jails/VMs dahinter liegen.
|
||||
* `banaction = …-allports` → der Proxy selbst ist auf allen Ports geschützt
|
||||
(inkl. SSH), ohne dass normale Nutzer tangiert werden.
|
||||
* **Unban-Ereignisse** werden gespiegelt, die Ban-Liste bleibt synchron.
|
||||
|
||||
---
|
||||
|
||||
# Fail2Ban: Proxy-Setup (Zentraler Bann über Reverse Proxy)
|
||||
## 2. Backend (clientserver / Apache)
|
||||
|
||||
## Ziel
|
||||
Implementierung einer zentralen IP-Blockierung am Reverse Proxy, während die Angriffserkennung dezentral auf den Backend-Systemen erfolgt.
|
||||
### 2.1 mod_remoteip (echte Client-IP in den Logs)
|
||||
Ohne mod_remoteip loggt Apache die Proxy-IP als Requester → fail2ban würde
|
||||
die Proxy-IP bannen → der Proxy bannt sich selbst (alle Upstreams down →
|
||||
504/502). Deshalb muss Apache die Client-IP aus `X-Forwarded-For` nehmen:
|
||||
|
||||
### Architektur
|
||||
* **Backend (Client):** Erkennt Angriffe mittels Fail2Ban-Filtern (L7).
|
||||
* **Proxy (Enforcement):** Setzt Firewall-Regeln via `nftables` um (L3).
|
||||
* **Kommunikation:** Erfolgt über den Befehl `fail2ban-client set recidive banip <ip>`.
|
||||
**Datei:** `/etc/apache2/conf-available/remoteip.conf` (siehe `remoteip.conf`
|
||||
in diesem Repo)
|
||||
```apache
|
||||
RemoteIPHeader X-Forwarded-For
|
||||
|
||||
---
|
||||
# Vertrauen zu Proxy (Public IPv6 & internes IPv4)
|
||||
RemoteIPInternalProxy 2a01:4f8:130:516e::160
|
||||
RemoteIPInternalProxy 10.8.1.1
|
||||
|
||||
## Problemstellung
|
||||
Beim Einsatz eines Reverse Proxys ergeben sich folgende Hürden:
|
||||
* **Logs:** Enthalten zwar die Client-IP (via `X-Forwarded-For`), aber...
|
||||
* **Firewall:** Die Backend-Firewall sieht nur die IP des Proxys.
|
||||
|
||||
**Ergebnis:** Fail2Ban erkennt den Angriff zwar korrekt, ein lokaler Block auf dem Backend bleibt jedoch wirkungslos, da der Traffic weiterhin über den Proxy fließen kann.
|
||||
|
||||
---
|
||||
|
||||
## Lösung
|
||||
Konsequente Trennung von **Detection** (Backend) und **Enforcement** (Proxy).
|
||||
|
||||
---
|
||||
|
||||
## Proxy-Konfiguration
|
||||
|
||||
### 1. Installation
|
||||
# HTTPS-Status für PHP (verhindert Redirect-Loops)
|
||||
SetEnvIf X-Forwarded-Proto "https" HTTPS=on
|
||||
```
|
||||
```bash
|
||||
apt install fail2ban
|
||||
a2enmod remoteip
|
||||
a2enconf remoteip
|
||||
systemctl restart apache2
|
||||
```
|
||||
**Check:** In der Apache-Accesslog muss die echte Client-IP stehen, nicht
|
||||
die Proxy-IP.
|
||||
|
||||
### 2.2 fail2ban
|
||||
* Normale Jails, **keine Custom-Actions** nötig.
|
||||
* Die `NOTICE … Ban <ip>` / `NOTICE … Unban <ip>`-Zeilen in
|
||||
`/var/log/fail2ban.log` sind die einzige Schnittstelle zum Proxy.
|
||||
* Alte „forward“-Actions (SSH-basiert) entfernen oder auf `/bin/true`
|
||||
entschärfen.
|
||||
|
||||
### 2.3 rsyslog-Forwarding
|
||||
**Datei:** `/etc/rsyslog.d/40-to-proxy.conf`
|
||||
```
|
||||
module(load="imfile")
|
||||
input(type="imfile" File="/var/log/fail2ban.log" Tag="f2bexport")
|
||||
|
||||
if $programname == "f2bexport" then {
|
||||
action(type="omfwd" target="2a01:4f8:130:516e::160" port="514" protocol="udp")
|
||||
stop
|
||||
}
|
||||
```
|
||||
```bash
|
||||
systemctl restart rsyslog
|
||||
```
|
||||
**Hinweis:** Beim ersten Start liest `imfile` die Datei komplett von Anfang →
|
||||
die gesamte Ban-Historie wird einmalig gesendet → der Proxy baut damit sofort
|
||||
den vollständigen Spiegel der aktuellen Ban-Liste auf.
|
||||
|
||||
---
|
||||
|
||||
## 3. Proxy (proxyserver)
|
||||
|
||||
### 3.1 rsyslog-Empfang
|
||||
**Datei:** `/etc/rsyslog.d/40-f2bexport.conf`
|
||||
```
|
||||
module(load="imudp")
|
||||
input(type="imudp" port="514")
|
||||
|
||||
if $programname == "f2bexport" then {
|
||||
action(type="omfile" file="/var/log/f2bexport.log")
|
||||
stop
|
||||
}
|
||||
```
|
||||
```bash
|
||||
systemctl restart rsyslog
|
||||
```
|
||||
Test: Vom Client `logger -n <proxy-ip> -P 514 -t fail2ban "TEST"` → Zeile muss
|
||||
in `/var/log/f2bexport.log` landen.
|
||||
|
||||
### 3.2 Firewall (Proxmox)
|
||||
UDP 514 (v4 + v6) von der Client-VM zum Proxy erlauben.
|
||||
|
||||
### 3.3 fail2ban-Jail „remote-bans“
|
||||
|
||||
> **Achtung (fail2ban ≥ 1.0):** Die Host-Gruppe im Regex heißt
|
||||
> `fid` bzw. man verwendet den Platzhalter `<HOST>`.
|
||||
> `(?P<ip>…)` wird in 1.0.x abgelehnt („No failure-id group“).
|
||||
|
||||
**Filter:** `/etc/fail2ban/filter.d/remote-bans.conf`
|
||||
```
|
||||
[Definition]
|
||||
failregex = ^.*fail2ban\.actions\s+\[\d+\]:\s+NOTICE\s+\[[^\]]+\] (?:Restore )?Ban <HOST>\s*$
|
||||
ignoreregex = ^.*fail2ban\.actions\s+\[\d+\]:\s+NOTICE\s+\[[^\]]+\] Unban <HOST>\s*$
|
||||
```
|
||||
* `failregex` erfasst `Ban` **und** `Restore Ban` (Neustart des Client).
|
||||
* Unban-Zeilen werden vom Jail ignoriert (fail2ban hat kein `unbanregex`);
|
||||
das eigentliche Unbanning erledigt der Watcher aus Abschnitt 4.
|
||||
|
||||
**Jail:** `/etc/fail2ban/jail.d/remote-bans.local`
|
||||
```
|
||||
[remote-bans]
|
||||
enabled = true
|
||||
backend = polling
|
||||
logpath = /var/log/f2bexport.log
|
||||
maxretry = 1
|
||||
findtime = 86400
|
||||
bantime = 604800
|
||||
banaction = iptables-ipset-proto6-allports
|
||||
ignoreip = 127.0.0.1/8 ::1 10.8.0.0/16 46.4.5.60 2a01:4f8:130:516e::160 2a01:4f8:130:516e::55 88.133.6.20 2a05:fa40:17a:4b00::/64
|
||||
```
|
||||
* `bantime` = das **Maximum** der Bantimes der Client-Jails (7 Tage).
|
||||
Früheres Unbanning auf dem Client kommt per Unban-Zeile trotzdem an.
|
||||
* `ignoreip` **muss** mindestens enthalten: die eigene Proxy-IP (v4+v6),
|
||||
die Client-/Proxy-IPs im internen Netz und die Admin-IPs –
|
||||
sonst bannt sich der Proxy selbst und alle Upstream-Verbindungen
|
||||
brechen ab (Symptom: 504/502 auf allen proxiedomains).
|
||||
|
||||
---
|
||||
|
||||
## 4. Unban-Watcher (Proxy)
|
||||
|
||||
fail2ban kennt kein `unbanregex` → ein kleines systemd-Service tailt das
|
||||
Export-Log und unbant via `fail2ban-client`:
|
||||
|
||||
**`/usr/local/bin/f2b-unban.sh`:**
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
set -u
|
||||
LOG=/var/log/f2bexport.log
|
||||
touch "$LOG"
|
||||
tail -n0 -F "$LOG" | while IFS= read -r line; do
|
||||
[[ "$line" == *"Unban "* ]] || continue
|
||||
ip="${line##*Unban }"
|
||||
ip="${ip%%[[:space:]]*}"
|
||||
[[ -n "$ip" ]] || continue
|
||||
echo "unban: $ip"
|
||||
fail2ban-client set remote-bans unbanip "$ip" 2>/dev/null || true
|
||||
done
|
||||
```
|
||||
```bash
|
||||
chmod +x /usr/local/bin/f2b-unban.sh
|
||||
```
|
||||
|
||||
**`/etc/systemd/system/f2b-unban.service`:**
|
||||
```
|
||||
[Unit]
|
||||
Description=fail2ban remote unban watcher
|
||||
After=network.target fail2ban.service
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/local/bin/f2b-unban.sh
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
```bash
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now f2b-unban
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Funktionstest
|
||||
|
||||
```bash
|
||||
# Client:
|
||||
fail2ban-client set sshd banip 1.2.3.4
|
||||
|
||||
# Proxy (nach wenigen Sekunden):
|
||||
fail2ban-client status remote-bans # → 1.2.3.4 in der Banned-Liste
|
||||
|
||||
# Client:
|
||||
fail2ban-client set sshd unbanip 1.2.3.4
|
||||
|
||||
# Proxy:
|
||||
fail2ban-client status remote-bans # → IP wieder weg
|
||||
journalctl -u f2b-unban --no-pager | tail # → "unban: 1.2.3.4"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Skalierung auf weitere VMs
|
||||
|
||||
Pro zusätzlicher Backend-VM:
|
||||
1. Backend: `mod_remoteip` (2.1) + rsyslog-Forward (2.3, Ziel = Proxy-IP).
|
||||
2. Proxy: **nichts** – das bestehende `remote-bans`-Jail sammelt alle
|
||||
Ban-/Unban-Zeilen aller Clients in `/var/log/f2bexport.log`.
|
||||
|
||||
Ein Jail, ein Log, ein Watcher – egal wieviele VMs melden.
|
||||
|
||||
---
|
||||
|
||||
## 7. Fehlerbilder / Lessons Learned
|
||||
|
||||
| Symptom | Ursache |
|
||||
| :--- | :--- |
|
||||
| 504/502 auf **allen** Proxiedomains | Proxy hat sich selbst gebannt (eigene IP in `remote-bans`, allports) → Upstream-Timeouts. Abhilfe: Proxy-IP in `ignoreip`. |
|
||||
| SSH zum Proxy abgestürzt nach fail2ban-Start | Alter Mechanismus: „Restore Ban“-SSH-Storm + allports-Ban des SSH-Transports. Wird durch die rsyslog-Lösung beseitigt. |
|
||||
| `No failure-id group in '…'` | fail2ban ≥ 1.0: `(?P<ip>)` ungültig → `<HOST>` (bzw. `(?P<fid>…)`). |
|
||||
| `interpolation key 'jailname' not valid` | fail2ban 1.0.2 erlaubt in Actions nicht alle Platzhalter (u. a. kein `jailname`). |
|
||||
| Jail findet 0 Treffer, `fail2ban-regex` matcht | Jail liest ab Dateiende (nur neue Zeilen); `fail2ban-regex` testet die ganze Datei. |
|
||||
| Bans erscheinen nicht | UDP 514 blockiert (PVE-Firewall) oder `programname`-Filter passt nicht (`f2bexport` vs. `fail2ban`). |
|
||||
Reference in new issue
Block a user