The Architecture Canontruth · evidence · projection
Case Study

CapBan

case-capban · canon/case-studies/capban/unit.md

Chapter 3 — CapBan: Security as Architecture

"CapBan exists because the old way of doing this job was a script wrapped around a system. The new way is the system."

Laws most engaged: III (Security Is a Property), II (Constraint Management).

CapBan is an event-driven intrusion-prevention engine, and it is the clearest specimen in the series of Law III — Security Is a Property, Not a Feature — because it exists specifically to replace a design in which security was a feature with one in which security is the architecture. Where CapDB showed truth done right at the engine, CapBan shows security done right at the engine, and the contrast between what it replaced and what it is makes the law unusually visible.

The bolt-on it replaces

The pattern CapBan replaces — Fail2ban's tail → regex → ban — is security as a script wrapped around a system that knows nothing about it. It tails a log file, runs regexes against the lines, and shells out to modify the firewall. It works, and it is also the architecture of a supplement: brittle parsing, sequential and slow, no correlation across attack types, no way to express a real policy, and a security action (changing firewall rules) reached by interpolating into a shell. Security is something this approach does, externally, to a system that was not built for it.

Volume I, Chapter 3 used exactly this contrast to introduce Law III, and seeing CapBan whole sharpens it. The Fail2ban model is not insecure because it lacks security features; it is insecure because security is not in its structure. The parsing is injectable, the enforcement is a shell-out, the logic is implied by which regex matched. No amount of additional features fixes a structure in which security is a wrapper.

The re-architecture: security in the structure

CapBan does the same job — detect attacks, ban sources — but makes security what the system is. The work becomes a typed pipeline: Event → normalized Identity → Policy → Decision → Enforcement → Audit, and each stage embodies a security property by construction rather than by addition:

flowchart LR
    E["Event<br/>(typed at the boundary)"]
    I["Normalized<br/>Identity"]
    POL["Policy<br/>allowlist → denylist → score"]
    D["Decision<br/>carries its evidence"]
    EN["Enforcement<br/>single confined seam<br/>idempotent · validated · no shell"]
    A["Audit<br/>structured JSON → SIEM"]
    NFT[("nftables / k8s<br/>(only reachable here)")]
    E --> I --> POL --> D --> EN --> A
    EN -->|"idempotent apply"| NFT

boundary; malformed input cannot become malformed internal state. The brittle, injectable parsing of the old model is replaced by a structural guarantee. (This is also Law III's safe by default at the data layer, and a use of Rust's type system to make illegal states unrepresentable.)

allowlist, then denylist, then scoring — rather than implied by a matching regex. Security logic is part of the architecture, not an accident of configuration.

the Enforcer trait, where it is made idempotent and validated, with no shell interpolation. The rest of the engine is structurally incapable of touching the firewall.

  • Typed events instead of regex parsing. Input is normalized into a strongly typed Event at the
  • Policy as a first-class stage. Detection is governed rules with an explicit evaluation order —
  • Enforcement confined to one seam. The dangerous capability — changing firewall rules — lives behind

The difference from Fail2ban is not a longer feature list. It is that CapBan's security is in its shape: type the inputs, govern with explicit policy, confine the danger. Strip any individual hardening and the structure still types its inputs, still governs, still confines. That is what it means for security to be a property (Law III) rather than a feature.

Confining the dangerous capability

The Enforcer seam deserves emphasis, because it is Law III's "confine the dangerous" done precisely. All external effect — the only genuinely dangerous thing CapBan does — is concentrated in one place, behind a trait, made idempotent and validated. This is the same discipline as AISDR's connector firewall (Volume II, Chapter 6) and CapDB's authorizer (Chapter 2): dangerous capability belongs in the smallest, most scrutinized seam, never spread through the system. A bug or compromise elsewhere in CapBan cannot manipulate the firewall, because elsewhere in CapBan cannot reach it.

CapBan then carries the confinement down to the operating system, where security-as-architecture is most often abandoned. Its enforcement runs under tight capability isolation: a single Linux capability (CAP_NET_ADMIN) and no more, NoNewPrivileges, a locked-down filesystem (ProtectSystem=strict, ProtectHome, explicit ReadWritePaths), as a dedicated unprivileged user. The process that manipulates the firewall cannot gain more privilege, cannot write outside its narrow paths, cannot become root. This is least privilege by construction (Law III): not "we trust this process to behave," but "this process is structurally unable to misbehave beyond a tiny blast radius."

Constraint as enabling structure

CapBan is also, as Volume I, Chapter 2 detailed, a study in Law II — constraint as the material that makes the engine possible. At its center is a single generic type: CapBanEngine<S, E>, generic over a Store trait and an Enforcer trait. The engine is forbidden from knowing whether its storage is in-memory or persistent, and whether its enforcement is a no-op, a Linux firewall, or a Kubernetes network policy. It can speak only the narrow vocabulary the traits define.

That refusal-to-know is a constraint, and it is enabling. Because the engine cannot reach past the traits, it is testable in isolation (a NoopEnforcer and a MemoryStore exercise the logic with no firewall and no disk); new backends cost the core nothing (implement a trait, do not modify the engine); and the security boundary stays localized (the dangerous work lives behind the Enforcer seam). The constraint is the feature — exactly Law II's claim that commitment creates capability. And the constraints compose with the security properties: confining enforcement to a trait is simultaneously a Law II design constraint and a Law III security boundary. In a well-built system the laws are not separate; the same trait boundary serves both.

Why the contrast matters

CapBan is small enough to hold whole, which is what makes it the ideal specimen for Law III. You can see, with nothing hidden, that there is no place for an unconfined capability to lurk: the inputs are typed at the boundary, the policy is explicit, the enforcement is behind one validated seam, the process is capability- isolated. And you can compare it directly to what it replaced — a design where every one of those properties was absent, where security was a script wrapped around a system. The two do the same job. One is secure because of its structure; the other has security features and an insecure structure. That contrast, held whole in one mind, is Law III's argument in its most legible form.

The next chapter turns to the other half of CapBan — the disposable state it holds, and the deterministic way it recovers — where Law I's Acceleration Plane and Law VII's graceful degradation are equally visible all the way down.

Incoming References

Law 5
Projection 4