Networks

A firewall you can read out loud

The best measure of a ruleset is whether a new engineer can read it aloud in a meeting and have everyone agree on what it does.

We inherited a firewall configuration last spring that had been appended to since 2011. Nine hundred lines. Four authors, three of whom had left. A comment on line 412 that read # temporary — remove after migration.

Nobody could say what it did. Not because they were careless, but because the configuration had stopped being a description of policy and become a sediment.

The test

A good ruleset passes one test: a competent engineer who has never seen it can read it out loud in a meeting, and everyone in the room agrees on what it does. That is a higher bar than “it works”, and almost every long-lived configuration fails it.

The OpenBSD packet filter is built for that bar. It has macros, so the names in the rules are your names. It has tables, so a set of addresses is a noun. It has anchors, so a section can be reasoned about on its own. And the syntax reads close enough to English that the reading-aloud test is literal rather than metaphorical:

web_servers = "{ 10.44.0.10, 10.44.0.11 }"
table <admins> persist file "/etc/pf/admins"

block all
pass in on egress proto tcp to $web_servers port { 80 443 }
pass in on wg0 proto tcp from <admins> to any port 22

Five lines. Nobody needs a vendor course, and nobody needs to guess about evaluation order, because in pf the last matching rule wins and quick says so explicitly when you want otherwise.

Rules are code

The second half of the fix is procedural rather than technical. The ruleset lives in the same repository as everything else, it changes through pull requests, and it is reviewed by a human who has to approve the diff.

That single change kills the whole category of “temporary” rules from 2011. A rule with no author and no rationale does not survive review, and a diff makes the difference between what you meant and what you typed visible before it reaches production rather than during an audit.

What it came to

Nine hundred lines became a hundred and forty. Roughly two hundred of the originals were genuinely dead — hosts that no longer existed, ports for a service decommissioned in 2017. Most of the remainder collapsed into tables and macros, because the same eight addresses had been written out longhand in thirty-one places.

The new engineer read it on their first morning. That was the deliverable.

Nästa steg

Tell us what you are running.
We will tell you what it should be.

A first conversation costs nothing and takes forty minutes. You will leave it with an honest opinion about your stack — including, occasionally, that you should change nothing at all.