All posts

Engineering · 8 min read

Why ACL versioning belongs in your network tool, not in Git

Network policy is code, but it is not application code. The failure modes are different, the reviewers are different, and the rollback surface is different. Here is how we built versioning that matches how operators actually work.

I

Ivan Vyshniak

Co-founder

Every team treating network policy seriously eventually files the same ticket: "we need version control for ACLs." The typical answer — "just put it in Git" — is correct in the abstract and wrong in practice. Network policy is code, but it is not application code. The failure modes, the reviewers, and the rollback surface are all different, and that's the whole story.

What's different

Application code fails in CI before it fails in production. Network policy fails the moment it reaches the data plane. There is no test environment that resembles real packets between real devices in real geographies. Policy tests help: they catch "this rule no longer lets the on-call group reach the database." They don't catch "the on-call team's laptops actually live behind a captive portal we forgot about."

Reviewers, too, are different. Application changes are read by engineers who built the system. Network changes are read by IT admins, security engineers, and (eventually) auditors. A diff with three squashed force-pushes is fine in a feature branch and useless in an audit.

What we built instead

Every policy save that changes something creates a new version with the next number. There is no way to edit or delete a stored version, so history only grows. Reverts are additive: restoring an old version saves its body again as a new version, with the comment Restored v<n>. Each save is also recorded in the audit log, so reviewers see who changed what and when without spelunking through Git.

Saves are guarded. A policy can carry its own tests ("group:ops can reach tag:db on 5432", "tag:guest can't reach tag:prod"), and every save runs them first; a save that breaks a test is rejected. A restore goes through the same check, so rolling back can't quietly reintroduce a policy that contradicts tests you've added since.

The operator-facing surface is small on purpose. Most network admins don't want a CLI for this; they want a history list, a diff between any two versions, and a Restore button with a confirmation. That's what the History tab of the access-controls page is.

When Git is still right

This isn't an argument against infrastructure as code. If you keep the policy in a repository and push it with the API (PUT the whole document; the same tests run), you're on a path that works for your organisation's review culture, and the version history in the console still records every push. The point is that the network tool itself shouldn't pretend to be a thinner Git. It should give operators what Git doesn't: tests that run against the real policy before it's live, and restores that are checked and audited like any other change.

Done well, it makes the "just put it in Git" instinct dissolve. Done badly, it adds a second source of truth.

To write your first rule and its tests, see Write your first rule and Roll back a policy.