Turning Complex Problems Into Confident Technology
A Windows service for one firewall rule
Security and secrets · Production · Inside the Workshop
The problem
A key vault and a database are locked to a list of permitted IP addresses. A home broadband connection does not have a permanent one. So every time the address changed, the tooling stopped working, and the fix was to run a script that added the new address.
That script was the whole system for a while, and it worked, in the sense that it did the right thing when it was run.
Why a script was the wrong shape
Because it needed a person to notice. The failure it prevents does not announce itself as a firewall problem — it announces itself as a connection timeout in the middle of something else, and the diagnosis costs more than the fix every single time.
There was also a quieter cost. Because running the script was mildly annoying, the standing temptation was to widen the rule instead, permanently, and stop having the problem. Every manual security control has that pressure on it, and it only ever pushes in one direction.
What I chose, and why
A Windows service that watches for the address changing and updates both rule sets itself.
- It runs as LocalSystem, so it survives sign-out and reboots rather than depending on someone being logged in.
- Its credential is protected with DPAPI (Windows' built-in encryption, tied to the machine or user account) rather than sitting in a config file. A service whose job is to maintain a security boundary should not undermine it by storing a secret in plaintext beside itself.
- Address changes are debounced. A network interface coming up produces a burst of events, not one, and each event otherwise becomes an API call to two services.
The bug worth naming
The first debounce had a race: a change arriving while an update was already in flight could be swallowed, leaving the rules holding an address that was no longer current. The service would report itself healthy and the connection would fail anyway, which is the worst combination — the monitoring says fine, the thing does not work.
The event-driven path also had no test coverage, which is how the race survived the first review. The timer path was tested because it is easy to test; the event path was the one that mattered.
Was it worth it?
For a single developer machine, honestly, it is close. The service is more code than the script, and code that runs unattended with permission to modify firewall rules deserves more care than a script you watch.
What tipped it was the alternative. The realistic alternative was not "keep running the script"; it was "widen the rule and forget about it", because that is what actually happens to manual controls over a long enough period. Judged against that, a small service that keeps a narrow rule accurate is clearly the better trade.
What I would do differently
I would have written the event path's tests first. The race was in the only part of the system that was hard to test, which is not a coincidence — that is where races live, and "hard to test" should have read as "test this first" rather than as "test this later".
Related
If this is your problem too
Security controls that depend on someone remembering are worth finding during a diagnosis, because they tend to have been quietly widened already. Related reading: maintainability.