Fleet Bans
One agent blocking an address is an observation. Forty agents blocking the same address is a different kind of fact — and the second one is invisible to any agent looking only at its own traffic.
Fleet bans close that gap. Each agent reports what it decided to block, the platform corroborates across the deployment, and every agent pulls back the aggregated result.
A fleet ban does not install a block. The set is consulted, the outcome counted and logged, and traffic is unaffected.
That is deliberate. Acting on what other machines concluded is a large step, and it should be justified by the false-positive rate that advisory mode exists to measure. Run it, read the numbers, then decide.
Two halves of one loop
| Direction | Config | Scope | |
|---|---|---|---|
| Ban ledger | Upload — what this agent decided to block | platform.ban_ledger | fleet_bans:write |
| Fleet bans | Download — what the fleet corroborated | platform.fleet_bans | fleet_bans:read |
They are separate stores with opposite provenance, and kept separate on purpose. The ledger holds first-party evidence — decisions this agent made from its own events. The fleet set holds bans this agent has no local evidence for. Merging them is how a fleet ban gets re-reported upward as fresh evidence and corroboration becomes an echo of itself.
What a fleet ban carries
| Field | |
|---|---|
agents | Distinct agents that reported banning this address |
agent_count_total | Live agents in the workspace — the denominator |
confidence | Platform confidence, 0–100 |
score | Platform score, 0–99, directly comparable to a threat-MMDB score |
first_banned_unix | When the fleet first banned this address |
expires_unix | When the ban lapses; absent means no expiry |
layers | Bitmask of the enforcing layers that reported it |
agent_count_total is the field that makes the rest readable. agents: 3 is unanimity in
a three-agent fleet and noise in a three-thousand-agent one. Any threshold you write should be
a ratio, not a count.
The layer bitmask records what kind of agreement it is — access_rules, smart_firewall,
ids, waf, threat_intel, captcha, rate_limit. Three agents agreeing via three
different layers is stronger corroboration than three agreeing via the same one, which is
usually the same rule firing three times.
The platform is not trusted
Both local safety predicates are re-applied to everything the platform serves, and anything failing either is dropped regardless of what arrived:
| Predicate | Drops |
|---|---|
| Ban-safe | Anything not unambiguously global-unicast. Fails closed. |
| Never-ban | Your own infrastructure — HOME_NET, load-balancer VIPs, node IPs |
The never-ban check is the one that matters most in practice. A public load balancer VIP is global-unicast, so the first predicate would permit it; banning it blackholes every client behind it.
The asymmetry is intentional: the agent is permissive about what it uploads — an unsafe ban is worth reporting so the fleet can see it — and strict about what it accepts.
Rejections are counted separately as rejected_unsafe, rejected_protected and
rejected_malformed, so a set that is arriving but being discarded is visible rather than
looking like an empty fleet. A malformed record is skipped and counted rather than failing the
whole payload.
Configuration
platform:
ban_ledger:
enabled: true
interval_secs: 60
fleet_bans:
enabled: true
refresh_secs: 60
advisory: true
advisory_dedup_secs: 300
Both inherit platform.base_url, so neither normally states a URL.
interval_secs governs how fast a ban propagates, not how much traffic this generates: a
tick whose snapshot has not changed sends nothing at all, and a forced resend happens only
every twelfth suppressed tick. refresh_secs is a cheap version check — the artifact is
downloaded only when the version changes.
Both default to 60 seconds so the loop is symmetric rather than having a slow leg. Raise
refresh_secs if a large fleet makes the version endpoint hot.
Limits worth knowing
- Advisory means advisory. Consulted, counted, logged. No traffic is affected until someone decides otherwise on the evidence.
- An unloaded set is not an empty one. A miss before the first set has been published means we do not know yet, not not banned. Advisory mode can ignore the difference; anything enforcing must not.
- Corroboration is not proof. Agents in one deployment often run one policy, so agreement can mean the same rule fired everywhere rather than independent confirmation. Read the layer mask before treating a count as consensus.
- It needs both scopes.
fleet_bans:writeto contribute,fleet_bans:readto receive. An agent with only read is a passenger.
Use cases
- Measure before enforcing — run advisory for a period and read the false-positive rate against your own traffic.
- Spread a detection across a fleet — one agent seeing a scanner means every agent knows about it within about a minute.
- Corroborate a marginal signal — a source your local threshold nearly caught is easier to judge when forty other agents already did.
- Spot a bad rule — a sudden spike in reported bans across one layer is usually a rule, not an attack.
See also
- Access Rules and Smart Firewall — layers that report bans
- Threat Detection — the platform-wide feed, distinct from your own fleet's decisions
- Security Event Export — the local record of what this agent blocked
- Configuration — the full
platform.ban_ledgerandplatform.fleet_bansblocks