Adds two files mirroring the on-host install layout:
infra/fail2ban/filter.d/familienarchiv-auth.conf
infra/fail2ban/jail.d/familienarchiv.conf
Filter parses the JSON access log emitted by Caddy (previous commit) and
matches 401 responses on /api/auth/login. Jail bans the offending IP for
30 min after 10 attempts in a 10-minute window.
Verified the failregex against four sample log lines via fail2ban-regex
in an alpine container:
- 2 brute-force 401 attempts → matched (ban)
- 1 successful login (POST /api/auth/login 200) → not matched
- 1 unrelated GET /login 200 → not matched
Date template "ts":{EPOCH} parses Caddy's Unix-epoch ts field.
The previous review iteration described this jail in DEPLOYMENT.md prose
only; committing it makes the security posture reproducible from a
fresh server build.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
28 lines
1.1 KiB
Plaintext
28 lines
1.1 KiB
Plaintext
# Jail definition for the Familienarchiv login endpoint.
|
|
#
|
|
# Install: ln -sf /opt/familienarchiv/infra/fail2ban/jail.d/familienarchiv.conf \
|
|
# /etc/fail2ban/jail.d/familienarchiv.conf
|
|
# ln -sf /opt/familienarchiv/infra/fail2ban/filter.d/familienarchiv-auth.conf \
|
|
# /etc/fail2ban/filter.d/familienarchiv-auth.conf
|
|
# systemctl reload fail2ban
|
|
#
|
|
# Verify with:
|
|
# fail2ban-client status familienarchiv-auth
|
|
# fail2ban-regex /var/log/caddy/access.log familienarchiv-auth
|
|
#
|
|
# Tuning rationale:
|
|
# - maxretry 10: legitimate users mistyping passwords don't trip the jail
|
|
# - findtime 10m: rolling window that catches automated brute force
|
|
# - bantime 30m: long enough to discourage scripted attacks, short
|
|
# enough that a user who fat-fingered their VPN comes
|
|
# back online within a coffee break
|
|
|
|
[familienarchiv-auth]
|
|
enabled = true
|
|
filter = familienarchiv-auth
|
|
logpath = /var/log/caddy/access.log
|
|
maxretry = 10
|
|
findtime = 10m
|
|
bantime = 30m
|
|
action = iptables-multiport[name=familienarchiv-auth, port="http,https"]
|