Fail2ban sync geändert
This commit is contained in:
1 parent
a663156fc7
commit
0755585d63
2 files changed
+250
-47
No files matched your search
+13
@@ -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
@@ -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`). |
|
||||||
Reference in new issue
Block a user