Rate limiter für Gitea
Hier halte ich eine Schritt-für-Schritt Anleitung fest, die das Problem von Gitea-Abstürze lösen soll. Die Erfahrung aus meiner Erstanwendung eines Rate Limiters für meinen Blog lassen sich hier einfließen. Somit läuft die Anwendung viel robuster und ist gegen ungerichtete Denial of Service Attacken geschützt.
Schritt 1: Log-Quelle für rate limiter festlegen
Gitea erzeugt natürlich selbst Logs, theoretisch bis herunter auf Zugriffsebene durch externe Clients. Doch schaffte ich es in der Vergangenheit nicht, Giteas Access-Logs aus Docker auszuleiten. Daher geben wir jetzt dem als Reverse Proxy angeflanschten Caddyserver die Anweisung, Logs stellvertretend zu erstellen. In ihnen tauchen dann Zugriffe auf das Webinterface von Gitea auf.
In der Caddyfile
sieht das Log-Modul total unspektakulär aus.
# /caddy/Caddyfile
#[...]
log {
output file /log/gitea/access.log
}
Internen Traffic vom Log ausschließen
Nun schaue ich die Logs mal an und sehe Einträge, die ich gar nicht haben will. So erzeugt act_runner zum Beispiel alle zwei Sekunden einen Fetch Task POST
nach Gitea und alle zehn Sekunden einen GET
Request mit demselben Ziel als Health check. Diese brauchen für mich im Log gar nicht erst auftauchen. Mein erster Gedanke hier war, einfach Anfragen von internen IP-Adressen nicht zu loggen. Da Caddy allerdings als Reverse Proxy fungiert, laufen ausnahmslos alle IP-Adressen “intern”.
Also muss ich act_runner spezifische Logs anders erkennen:
# /caddy/Caddyfile
#[...]
git.schallbert.de {
reverse_proxy * http://gitea:3000
# Enable logging for fail2ban, don't log for runner
log_skip /api/actions*
log {
output file /log/gitea/access.log
}
}
Die log_skip
Direktive weist caddy nun an, keine Logs für Zugriffe auf /api/actions*
mehr anzulegen.
Reverse-Proxy: Remote IPs anzeigen
Dennoch habe ich noch immer ein Problem: Wenn im Log alle externen Anfragen auf einer internen IP-Adresse hereinkommen, wie soll ich “böse” Anfragen dann wegblocken? Eine Websuche zeigt, dass dies für Reverse Proxy in Docker ein üblicher Stolperstein ist. Leider helfen mir viele Lösungen nicht, da sie andere Serversoftware wie nginx verwenden oder andere Services hinter ihren Proxies laufen haben als Gitea.
Doch tatsächlich ist es ganz einfach: Nur eine Zeile muss an der richtigen Stelle in die Caddyfile
eingefügt werden und schon kommen die remote IP-Adressen unverfälscht rein.
# /caddy/Caddyfile
#[...]
git.schallbert.de {
reverse_proxy * http://gitea:3000 {
trusted_proxies 172.16.0.0/12 # Docker-internal netwock traffic runs with these IPs
}
#[...]
Die Direktive trusted_proxies
teilt Caddy mit, dass dem von Docker bereitgestelltem Netzwerk vertraut werden kann. Somit wird die eigentliche Quell-IP angezeigt statt der internen Schnittstelladresse des Containers. Genau das brauche ich, um die Adressen später mit fail2ban analysieren zu können.
Schritt 2: Anwendungsfall bestimmen
Schauen wir uns an, wie viele HTTP 200 ok
Anfragen im Grenzfall zwischen Normalnutzung und “abuse” kommen. Dazu surfe ich auf Gitea herum und klicke einen Haufen Dinge an, wie ich das als Mensch sonst nie in der Geschwindigkeit tun würde. Danach mache ich eine Auswertung der Logs.
Damit haben wir erste Richtwerte für den Rate Limiter.
# rate limiter tests
findtime = 10s
maxretry = 10
bantime = 6h
Schritt 3: Fail2ban konfigurieren
Anschließend konfigurieren wir Filter und Jail-Datei von fail2ban
so, dass sie die oben definierten Logs analysieren.
Filter
Ich verwende hier schlicht denselben Filter für meinen Rate-Limiter aus dem vorherigen Artikel wieder. Uns interessieren nur erfolgreiche Anfragen, die wir innerhalb eines Zeitfensters zählen.
Jail
Ich verwende die Werte aus den rate limiter Tests 1:1 hier in der Jail-Datei weiter. Als Filter verweise ich auf caddy-ratelimit
(Link oben).
# /fail2ban/config/fail2ban/jail.local
# [...]
[gitea-ratelimit]
enabled = true
chain = DOCKER-USER
port = http,https
filter = caddy-ratelimit
logpath = /var/log/caddy2/gitea/access.log
findtime = 10s
maxretry = 10
bantime = 6h
Mit einem Neustart von fail2ban schalte ich den Schutz scharf.
Schritt 4: Rate limiter testen
Hier gehe ich genauso vor wie in meinem Artikel fail2ban with caddy und komme zum selben Ergebnis. Es funktionert!