Ban lists: where Guard and fail2ban ban addresses

A program bans an address (every port, or a protocol's ports) for a
time; the ban list says what it is kept from: the firewall, some hosts
behind it, or everything. Bans drop ahead of every rule, close the
address's connections, group IPv6 by /64, are kept in the database
across restarts and audited. Never banned: the inside, the firewall's
own addresses, the caller, the list's never. bans grant (bans:write:LIST),
hc banlist/bans/ban/unban, Traffic -> Bans, a fail2ban action in contrib/,
and failed logins and refused tokens logged for Guard and fail2ban.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
abrown38andClaude Opus 5.5 committed 2026-10-22 16:29:37 +01:00
1 parent 6f56eefae2
commit 500bfc7bdd
44 files changed
+2541 -39

No files matched your search

+52
View File
@@ -0,0 +1,52 @@
# Housecarl's action for fail2ban: a ban goes into a Housecarl ban list,
# and the list says what the banned address is kept from (the firewall
# itself, some hosts behind it, or everything). See docs/bans.md.
#
# Copy this file to /etc/fail2ban/action.d/housecarl.conf, make a ban
# list and a token for it alone on the firewall:
#
# hc banlist add web --scope hosts --host 10.0.10.57
# hc user add f2b-web --no-password --grant bans:write:web
# hc token create web --user f2b-web # as root on the firewall
#
# put the token in /etc/fail2ban/housecarl.token (mode 0600), and use it
# in a jail:
#
# [sshd]
# enabled = true
# action = housecarl[list=web, url="https://router.lan:8070"]
#
# The jail's port and protocol go along: port = ssh bans only tcp/22;
# fail2ban's default (0:65535) bans every port. IPv6 addresses are banned
# with the list's grouping (a /64 unless set otherwise). Housecarl never
# bans inside networks, its own addresses or the list's "never".
#
# On the firewall itself, the local socket works too, still with the
# token: url = http://localhost, curlopts = --unix-socket
# /run/housecarl/housecarl.sock.
[Definition]
actionstart =
actionstop =
actioncheck =
# A ban renews one already there; a bantime of -1 is the list's longest.
actionban = <_curl> -f -X POST -H "Content-Type: application/json" "<url>/api/v1/banlists/<list>/bans"
-d '{"address": "<ip>", "protocol": "<protocol>", "ports": "<port>", "time": <bantime>, "source": "fail2ban/<name>"}'
# A ban Housecarl already ended (its own time ran out) is no error.
actionunban = <_curl> -X DELETE "<url>/api/v1/banlists/<list>/bans?address=<ip>"
[Init]
# The ban list, and Housecarl's URL (its listen address).
list =
url = https://127.0.0.1:8070
# The API token, in a file only root reads.
tokenfile = /etc/fail2ban/housecarl.token
# More curl options: --cacert /etc/fail2ban/housecarl-ca.pem for a
# private CA, --unix-socket for the local socket.
curlopts =
_curl = curl -sS --max-time 10 <curlopts> -o /dev/null -H "Authorization: Bearer $(cat <tokenfile>)"