blog.johlem.net

NixOS as a Security Posture: Why Declarative and Reproducible Is a Control

NixOS is usually pitched on reproducibility and developer ergonomics — the same config builds the same system, rollbacks are trivial, dependencies are pinned. Those are real benefits, but they undersell what the declarative model means for security specifically. A system whose entire configuration is described in version-controlled code, rebuildable to an identical state, with atomic upgrades and rollbacks, has security properties that imperatively-managed systems struggle to match. Declarative-and-reproducible is not just a convenience. It is a control.

This is about reading NixOS through a security lens — what the declarative model buys you as posture, and where it does not magically solve things.

Configuration drift is a security problem, and NixOS eliminates a class of it

On an imperatively-managed system, the running state and the documented state diverge over time. Someone makes a change to fix something and does not document it. A package is installed manually during an incident. A config is edited in place and forgotten. This drift is a security problem: you increasingly do not know what is actually running, which means you cannot reason about your attack surface, your patch state, or what changed before an incident.

NixOS attacks this at the root. The system’s configuration is the declarative description — the running state is built from the config, not edited alongside it. There is no “documented state vs. actual state” gap of the usual kind, because the config is the source of truth that produces the system. What is running is what is described, because what is described is what gets built.

For security this is significant: you can reason about the system from its configuration, because the configuration is authoritative. Your attack surface, your installed software, your service configuration — all described in one place, in version control, inspectable without logging into the box and discovering what someone did six months ago. The thing you must understand to secure a system — its actual state — is, by construction, the thing written down.

Version-controlled system state is an audit and forensics asset

Because the entire configuration lives in version control, you get properties that are security-relevant beyond drift:

Change history with attribution. Every change to the system’s configuration is a commit — who, when, and ideally why. This is an audit trail of system state changes that imperative management simply does not produce by default. For a regulated context where you must demonstrate change control, the version history is the evidence. The accountability that compliance frameworks demand is a byproduct of how the system is managed.

Forensic baseline. When investigating whether a system was tampered with, you have a declarative description of what it should be. Divergence between the declared configuration and the running reality is itself a signal — a strong one. The reproducible baseline is a known-good reference to compare against, which is exactly what forensics wants and rarely has.

Reviewable change. A configuration change can be reviewed before it is applied — the same code-review discipline that improves software and detections, applied to system state. A security-relevant change (opening a port, adding a service, changing a permission) is visible in a diff and can be caught in review rather than discovered in an incident.

Atomic upgrades and rollback as resilience

The atomic-upgrade and rollback model has a direct operational-resilience reading:

Atomic changes reduce the broken-intermediate-state risk. An upgrade either succeeds into a new known state or does not take effect — you do not get stranded in a half-applied state that is neither the old working config nor the new one. For security-critical systems, eliminating the partially-broken state eliminates a class of windows where a system is in an undefined, possibly-vulnerable condition mid-change.

Rollback is a recovery primitive. If a change introduces a problem — including a security problem — rolling back to the previous known-good generation is fast and reliable. This is operational resilience in the DORA sense: the ability to recover to a known state is a capability the regulation cares about, and NixOS provides it as a native primitive rather than a process you have to construct and test.

Reproducibility aids recovery. Rebuilding a system to a known state from its declarative config is a recovery capability — if a system is compromised or lost, you can reconstruct a known-good version from the configuration rather than from tribal memory and hope. The disaster-recovery story is cleaner when the system is a build artifact of versioned code.

Where NixOS does not save you

Declarative-and-reproducible is a real control, and honesty requires its limits:

It describes state; it does not make state secure. NixOS guarantees the system matches its config. If the config describes an insecure system — open ports, weak settings, vulnerable packages — NixOS faithfully builds insecurity, reproducibly. The model is a powerful means of applying and maintaining a secure configuration; it does not supply the security of the configuration itself. Garbage in, reproducible garbage out.

Pinned dependencies need maintenance. Reproducibility through pinning means you control exactly what versions run — which also means you are responsible for updating them. A pinned-and-forgotten dependency is a pinned-and-forgotten vulnerability. The control requires the discipline of actually maintaining the pins, or reproducibility becomes a way to reliably run stale, vulnerable software.

The learning curve is real. NixOS’s model is genuinely different, and the cost of that difference is real ramp-up time. A team that adopts it without absorbing the model can produce configurations that are reproducible but wrong, with false confidence from the reproducibility. The control is only as good as the understanding behind the config.

It is not a runtime defence. NixOS shapes how a system is built and maintained. It is not detection, not response, not a runtime control against an active attacker. It complements those; it does not replace them. A reproducible system still needs monitoring and defence on top.

The takeaway

NixOS read as a security posture is about one core property: the system’s entire state is described in version-controlled, reviewable, rebuildable code — which turns configuration into something you can reason about, audit, review, and recover, rather than something that drifts into an unknown state you discover during an incident. Drift elimination, change attribution, a forensic baseline, atomic rollback as a recovery primitive — these are security and resilience controls that fall out of the declarative model.

But the model applies and maintains a posture; it does not supply one. It will reproduce insecurity as faithfully as security, and it demands the maintenance discipline that pinning implies. The reframe to carry: declarative-and-reproducible is a control because it makes system state knowable, auditable, and recoverable — now you still have to make sure the state it reproduces is the secure one. NixOS gives you the means to hold a posture rigorously. The posture itself is still your job.


An independent piece by johlem.net — IT security, Luxembourg. Declarative infrastructure for security work.