initial commit

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Matthias Johnson 2026-02-27 15:09:25 -07:00
commit 75891c3271
129 changed files with 8046 additions and 0 deletions

View file

@ -0,0 +1,3 @@
[Definition]
# matches 401 responses using remote_ip extracted from X-Real-IP by Caddy in JSON access logs
failregex = .*"remote_ip":"<HOST>".*"status":401.*

View file

@ -0,0 +1,3 @@
[Definition]
# admin.php is intentionally specific; broader /admin would match legitimate paths (e.g. /admin-api)
failregex = .*"remote_ip":"<HOST>".*"uri":"\/(wp-admin|wp-login|phpmyadmin|xmlrpc|\.env|\.git|cgi-bin|admin\.php|setup\.php|eval-stdin).*".*

View file

@ -0,0 +1,8 @@
[Definition]
# Postfix SASL auth failures: warning: unknown[IP]: SASL ... authentication failed
failregex = ^.*warning: .*\[<HOST>\]: SASL .* authentication failed.*$
# Dovecot auth failures: auth failed ... rip=IP
^.*dovecot: (?:imap|pop3)-login: .*\(auth failed.*rip=<HOST>,.*$
ignoreregex =

View file

@ -0,0 +1,4 @@
[Definition]
# Matches both web login failures and SSH auth failures
failregex = ^.*Failed authentication attempt from <HOST>(:\d+)?$
^.*Failed login for user '[^']*' from <HOST>$

View file

@ -0,0 +1,16 @@
[caddy-scanners]
enabled = true
journalmatch = CONTAINER_NAME=caddy
filter = caddy-scanners
maxretry = 3
findtime = 10m
bantime = 24h
# high maxretry/short bantime: Grafana auth can be slow; strict limits cause false positives
[caddy-auth]
enabled = true
journalmatch = CONTAINER_NAME=caddy
filter = caddy-auth
maxretry = 40
findtime = 10m
bantime = 1h

View file

@ -0,0 +1,8 @@
[forgejo]
enabled = true
backend = systemd
journalmatch = CONTAINER_NAME=forgejo
filter = forgejo-auth
maxretry = 5
findtime = 10m
bantime = 24h

View file

@ -0,0 +1,9 @@
[mailserver]
enabled = true
backend = systemd
journalmatch = CONTAINER_NAME=mailserver
filter = docker-mailserver
maxretry = 5
findtime = 10m
bantime = 24h

View file

@ -0,0 +1,5 @@
- name: Reload fail2ban
service:
name: fail2ban
state: reloaded

View file

@ -0,0 +1,36 @@
- name: Ensure fail2ban directories exist
file:
path: "/etc/fail2ban/{{ item }}"
state: directory
mode: '0755'
loop:
- ""
- jail.d
- filter.d
- name: Remove obsolete grafana fail2ban configs
file:
path: "/etc/fail2ban/{{ item }}"
state: absent
loop:
- jail.d/grafana.conf
- filter.d/grafana-auth.conf
notify: Reload fail2ban
- name: Deploy fail2ban jail.local
template:
src: jail.local.j2
dest: /etc/fail2ban/jail.local
mode: '0644'
notify: Reload fail2ban
- name: Copy fail2ban jail and filter configs
copy:
src: "{{ item }}"
dest: "/etc/fail2ban/{{ item | regex_replace('^.*/files/', '') }}"
mode: '0644'
with_fileglob:
- "{{ role_path }}/files/jail.d/*"
- "{{ role_path }}/files/filter.d/*"
notify: Reload fail2ban

View file

@ -0,0 +1,8 @@
[DEFAULT]
backend = systemd
bantime = 24h
findtime = 10m
maxretry = 5
{% if fail2ban_ignoreip | default([]) | length > 0 %}
ignoreip = 127.0.0.1/8 ::1 {{ fail2ban_ignoreip | default([]) | join(' ') }}
{% endif %}