Files
2026-07-20 11:05:07 +02:00

3.3 KiB

Reference

MQTT topics

Topic Direction Role
fail2ban/<node>/ban node → master ban/notice event published by this node
fail2ban/<node>/heartbeat node → master periodic liveness proof (independent of any ban activity)
fail2ban/<node>/ack node → master acknowledgement after executing a command received from the master
fail2ban/<node>/action master → node command addressed specifically to this node
fail2ban/broadcast/action master → all nodes command broadcast to all subscribed nodes
fail2ban/broadcast/roster master → all nodes list of known nodes + global jail/country counters, periodic

<node> in the topic segment is the mTLS client certificate's CN (enforced by the broker's ACL) — the node's internal identifier (uuid.getnode()) travels in the message body, not in the topic.

Master commands

Command Effect on the receiving node Trigger
SYNC_BAN Full ban (all ports) via a dedicated jail Automatic: the master systematically publishes a SYNC_BAN for every ban it ingests
ESCALATE Permanent ban via a dedicated jail Automatic: the master correlates — an IP independently banned on several distinct nodes within 24h triggers an escalation
BAN_ALLPORTS Full ban (all ports), same mechanism as SYNC_BAN Manual (targeted human decision)
WHITELIST Added to ignoreip on all active jails + unbanned — in-memory, not persistent Manual
RATE_LIMIT Throttle (10 req/s, burst 20) instead of a full block Manual — edge case, likely false positives
NOTIFY_ONLY No network action, just a visible dashboard notification Manual — observation mode
REPORT_ABUSE Report to AbuseIPDB — not broadcast to nodes, submitted directly by the master (one report per IP is enough) Manual, dry-run until ABUSEIPDB_ENABLED/ABUSEIPDB_API_KEY are configured

Manual commands are triggered on the master, by hand:

emitter/.venv/bin/python emitter/manage.py publish_command WHITELIST 203.0.113.5
emitter/.venv/bin/python emitter/manage.py publish_command BAN_ALLPORTS 203.0.113.5
emitter/.venv/bin/python emitter/manage.py publish_command RATE_LIMIT 203.0.113.5
emitter/.venv/bin/python emitter/manage.py publish_command REPORT_ABUSE 203.0.113.5

Geolocation of banned IPs is automatic (asynchronous, on ingestion of each event); to retry the ones left without coordinates (API failure, private IP):

emitter/.venv/bin/python emitter/manage.py retry_geolocation            # all ungeolocated events
emitter/.venv/bin/python emitter/manage.py retry_geolocation --ip <ip>   # a specific IP

Custom fail2ban jails

Jail Role
emitter-admin-auth Dashboard /admin/ lockout (django-axes) → network ban
master-sync Receiving a SYNC_BAN/BAN_ALLPORTS — never triggered by a log, only by manual injection from the master relay
master-ratelimit Receiving a RATE_LIMIT
master-escalate Receiving an ESCALATE — permanent ban

emitter-admin-auth follows a reusable template (generic/fail2ban/jail.d/app-auth.conf.template + generic/fail2ban/filter.d/app-auth.conf) to protect any other application exposed on the same server the same way, not just this dashboard.