Instrument fail2ban and allow2ban bans - #720
Open
woodhull wants to merge 1 commit into
Open
Conversation
Previously there was no way to know that a ban had been applied. The `blocklist` event fires for every request a blocklist rejects, so a client banned for an hour produces an event per blocked request and none at all on the request that tripped the ban. This is most acute with Allow2Ban, where the request crossing maxretry is still allowed through, so the ban is invisible until the next request. Adds a `ban.rack_attack` event carrying the discriminator, count and the fail2ban settings that produced the ban. Unlike rack#655, this does not write to `request.env`, so the existing `blocklist`/`track` events for the same request are emitted exactly as before -- addressing the backwards compatibility concern raised there. Passing `request:` to the filter is optional and only enriches the payload, so existing filters get ban instrumentation with no changes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
There is currently no way to find out that a ban has been applied.
The
blocklistevent fires for every request a blocklist rejects, so a client banned for an hour produces an event on each of its blocked requests, and none at all on the request that actually tripped the ban. Subscribers can see a stream of rejections, but not the transition into the ban.This is most acute with
Allow2Ban, where the request that crossesmaxretryis deliberately still allowed through. The ban is written but nothing observable happens, so it stays invisible until the next request arrives.Solution
Adds a
ban.rack_attacknotification, emitted once at the moment the ban is written:Relationship to #655
This revives #655 (by @woahdae), which was closed for inactivity rather than on its merits. It follows the direction @santib asked for in review there:
Two differences from #655:
No
request.envmutation. The ban is instrumented through a separateRack::Attack.instrument_ban(payload)rather than by annotating the request, so theblocklist/trackevent for that same request is emitted exactly as before. Instrument fail2ban #655 needed||=inCheck#matched_by?, which was the breaking change flagged in review. The existing "notifies when the request is blocked" acceptance test passes unmodified here, which is what pinned that behavior down.request:is optional. In Instrument fail2ban #655 the whole event was gated behind passingrequest:to the filter, so nobody got ban instrumentation without changing their filters first. Here the event always fires andrequest:merely enriches the payload. Thediscriminatoris usually enough to identify who was banned, so existing filters get this for free.The deprecated catch-all
rack.attackevent is intentionally not emitted for bans, to avoid adding events to subscribers that never asked for them.Compatibility
Fail2Ban.fail!/Allow2Ban.fail!take a new trailing optional argument. Both areprotected, and the argument is optional, so external subclasses that override or call them keep working.161 runs, 330 assertions, 0 failures), rubocop clean.Docs
README gains a "Knowing when a ban is applied" section under Blocking, plus a TOC entry.