Fail2ban sync geändert

This commit is contained in:
root committed 2026-10-20 15:28:16 +02:00
1 parent a663156fc7
commit 0755585d63
2 files changed
+250 -47

No files matched your search

+13
View File
@@ -77,6 +77,19 @@ a2enconf remoteip
systemctl restart apache2 systemctl restart apache2
``` ```
### 3.2 Fail2Ban-Forwarding (Client → Proxy)
Die zentrale Ban-Weiterleitung vom Client an den Proxy ist in **README-Fail2ban.md**
dokumentiert (rsyslog UDP 514, ein einziges `remote-bans`-Jail auf dem Proxy, **kein SSH**).
Zusätzlich zu 3.1 (mod_remoteip) muss auf dem Client laufen:
* rsyslog-Forwarding von `/var/log/fail2ban.log` an den Proxy (UDP 514, `imfile`),
* fail2ban mit normalen Jails (keine Custom-Actions).
Auf dem Proxy: rsyslog-Empfang (`imudp`) nach `/var/log/f2bexport.log`,
fail2ban-Jail `remote-bans` (allports-Ban, `ignoreip` inkl. eigener Proxy-IP!) und
der Unban-Watcher (`f2b-unban.service`).
--- ---
## 4. ISPConfig Integration (Apache Direktiven Beispiel Gitea) ## 4. ISPConfig Integration (Apache Direktiven Beispiel Gitea)
+237 -47
View File
@@ -18,7 +18,7 @@ Das eigentliche Blocking erfolgt auf Layer 3/4:
* **IP-Adresse** wird geblockt. * **IP-Adresse** wird geblockt.
* **Protokollunabhängig.** * **Protokollunabhängig.**
* **Umsetzung:** Via `nftables` (Kernel). * **Umsetzung:** Via `iptables`/`ipset` (Kernel).
Dieser Prozess erfolgt optimal auf dem Proxy (**proxyserver**), da: Dieser Prozess erfolgt optimal auf dem Proxy (**proxyserver**), da:
* Dies der erste Eintrittspunkt in das Netzwerk ist. * 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. 1. Paket trifft auf dem Proxy ein.
2. Proxy akzeptiert die Verbindung. 2. Proxy akzeptiert die Verbindung.
3. Proxy leitet den Request an das Backend weiter. 3. Proxy leitet den Request an das Backend weiter.
4. Backend erkennt den Angriff. 4. Backend erkennt den Angriff (die Client-IP steht zwar in der Log,
5. Backend blockt die IP lokal. 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:** **Daraus resultierende Probleme:**
* Der Proxy verarbeitet weiterhin Requests des Angreifers. * 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. 2. Proxy leitet diesen initial weiter.
3. Backend erkennt den Angriff via Fail2Ban. 3. Backend erkennt den Angriff via Fail2Ban.
4. Backend meldet die IP an den Proxy. 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. 6. Alle weiteren Pakete werden bereits am Proxy verworfen.
### Effekt ### 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). **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-Storms beim fail2ban-Neustart:** Beim Restart feuern alle Jails ihre
* **SSH-Key Authentifizierung:** Muss passwortlos (Key-basiert) eingerichtet sein. „Restore Ban“-Listen nach → dutzende SSH-Sessionen in wenigen Sekunden.
* **SSH-Port:** Muss in der SSH-Config des Root-Users hinterlegt sein. * **Lockout-Risiko:** Der Proxy bannt die IP auf *allen* Ports (inkl. 22) →
* **Fail2Ban:** Muss auf beiden Systemen installiert und aktiv sein. der SSH-Transport blockiert sich selbst.
* **Skalierung:** Bei mehreren Backend-VMs summiert sich der SSH-Aufwand.
## 2. SSH Konfiguration Die neue Lösung nutzt **keinen SSH-Zugriff mehr**: Ban-/Unban-Ereignisse
Konfiguration für den schnellen, passwortlosen Zugriff auf den Proxy. 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` ## 1. Architektur
```ssh
Host proxy
HostName proxy.myserver.com
User root
Port 22
IdentityFile /root/.ssh/clientserverproxy
IdentitiesOnly yes
```
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 ### 2.1 mod_remoteip (echte Client-IP in den Logs)
Implementierung einer zentralen IP-Blockierung am Reverse Proxy, während die Angriffserkennung dezentral auf den Backend-Systemen erfolgt. 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 **Datei:** `/etc/apache2/conf-available/remoteip.conf` (siehe `remoteip.conf`
* **Backend (Client):** Erkennt Angriffe mittels Fail2Ban-Filtern (L7). in diesem Repo)
* **Proxy (Enforcement):** Setzt Firewall-Regeln via `nftables` um (L3). ```apache
* **Kommunikation:** Erfolgt über den Befehl `fail2ban-client set recidive banip <ip>`. RemoteIPHeader X-Forwarded-For
--- # Vertrauen zu Proxy (Public IPv6 & internes IPv4)
RemoteIPInternalProxy 2a01:4f8:130:516e::160
RemoteIPInternalProxy 10.8.1.1
## Problemstellung # HTTPS-Status für PHP (verhindert Redirect-Loops)
Beim Einsatz eines Reverse Proxys ergeben sich folgende Hürden: SetEnvIf X-Forwarded-Proto "https" HTTPS=on
* **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
```bash ```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`). |