Skip to main content

Nix and Determinate are a better foundation for keeping your systems secure

Nix and Determinate are a better foundation for keeping your systems secure

If you work in software security or anywhere adjacent to it, the past few months have pretty much felt like one extended incident. Everything from compromised maintainer accounts to poisoned build pipelines to a relentless flood of CVEs has turned the supply chain from one software development concern amongst others into a near-daily cortisol spike. And every time a new vulnerability lands, the same set of questions brusquely imposes itself:

  • Does this affect any of our production systems?
  • How quickly can we patch it (if at all)?
  • What information would we be able to provide to an auditor?

In too many enterprises, these questions are far too difficult to answer. There are some widely used remediation measures, such as scanning container images, but what our industry needs is a solution that attacks the supply chain problem at the root and is fundamentally proactive rather than reactive.

In this post, I’m going to make the case that Nix and the Determinate platform together give you that fundamentally better foundation. Nix gets you a good chunk of the way there by providing the most fundamentally sound build paradigm available amongst all widely used tools. Determinate then rounds out the picture by providing an end-to-end platform experience with Determinate Secure Packages at the center.

The Nix paradigm

Every piece of software in Nix, from a straightforward command-line tool to a production-ready operating system, is built from a “recipe” called a derivation. That recipe exhaustively details everything required to build it, including source code, build steps, compilers, shells, and much more, and it does so not just for the top-level artifact but also for the entire dependency graph for that piece of software. The result is that everything required to build it is just code that you can inspect in a wide variety of ways, rather than something you need to cobble together from various Makefiles or shell scripts after the fact.

So you have a fully inspectable recipe that you now need to actually build. This is where sandboxing enters the picture. The Nix sandbox, in which everything is built, provides no uncontrolled network access and no access to the regular host filesystem. Instead, the sandbox can only “see” inputs declared by the derivation and, generally speaking, it can only access things over the Internet if you specify a cryptographic hash of the contents in advance. And the results of the build end up only in the Nix store (a special type of filesystem) and never in top-level directories like /usr or /bin. The result is a dramatically reduced surface area for entire categories of build-time hijinx.

And finally, because derivations define complete dependency graphs, Nix can’t help but “think” in terms of complete sets of dependencies called closures. Like derivations, closures are totally introspectable, with the practical consequence that when a new CVE drops, you can instantly know whether a deployed piece of software built with Nix is affected by it. The result is that you don’t need to scan or draw inferences or apply heuristics for a service or image or CI environment; you can just “ask” Nix.

Together, these core characteristics—not optional features!—of Nix provide crucial building blocks for a build system that truly rises to meet the demands of the moment.

The Determinate platform

Everything described in the section above is true of any distribution of Nix that you’ll find out there today. Here at Determinate Systems, however, we’ve provided a layer of features on top of this paradigmatic core that extends from provenance all the way to the final decision about whether a piece of software meets your exacting security standards.

Provenance on the Determinate platform, from build to decision
Provenance on the Determinate platform, from build to decision

Record: Determinate Nix captures provenance at build time

It all begins with provenance information that Determinate Nix can record for all of your software. At build time, it attaches metadata to each artifact that answers the “where” questions that upstream Nix leaves open: the machine and system it was built on, the exact build recipe (read: derivation) it came from, and the flake (and revision) it was built from.

Determinate Nix records provenance alongside every artifact it builds
Determinate Nix records provenance alongside every artifact it builds

Provenance is currently an experimental feature, so the machines that build your artifacts need to run Determinate Nix with extra-experimental-features = provenance in their configuration.

Once recorded, you can inspect the provenance data for any artifact, and even check that artifact’s origins before you use it. Here’s what it looks like for Node.js from Determinate Secure Packages:

Show the provenance of a package
nix provenance show \
"https://flakehub.com/f/DeterminateSystems/secure-packages-rolling/=0.1.1088196#nodejs"
Output
/nix/store/3p3ksnnz5bwcbyfi340ws4m4r2bgj032-nodejs-24.21.0
← copied from https://edge.cache.flakehub.com
← built from derivation /nix/store/bizb1ilqgampd4ff8issd6jm8zf7aj5q-nodejs-24.21.0.drv (output out) on 1i2ifj3gejr2q.local for aarch64-darwin
← with derivation metadata
{
"changelog": "https://github.com/nodejs/node/releases/tag/v24.21.0",
"cyclonedx_1_5": {
"vulnerabilities": {}
},
"description": "Event-driven I/O framework for the V8 JavaScript engine",
"homepage": "https://nodejs.org",
"identifiers": {
"possibleCPEs": [],
"purls": []
},
"license": {
"deprecated": false,
"free": true,
"fullName": "MIT License",
"licenseType": "simple",
"redistributable": true,
"shortName": "mit",
"spdxId": "MIT",
"url": "https://spdx.org/licenses/MIT.html"
}
}
← instantiated from flake output git+file:///Users/runner/work/secure-packages-rolling/secure-packages-rolling?rev=8ce52f4b41e945024504c64151efd0781ba431cb&shallow=1#checks.aarch64-darwin.python313-safetensors

If you read from the top down, you see the artifact’s whole history: the cache it came from, the build recipe that produced it and on which machine and system, and which flake output (down to the exact Git revision) it was built from. You can also ask Determinate Nix to verify provenance, which re-derives the build recipe from the recorded source and checks that it matches.

Store: FlakeHub Cache keeps provenance with the artifact

Provenance is most useful when it’s stored in a location that can be accessed at any time. So when you push an artifact to FlakeHub Cache, the cache stores its provenance data along with it, automatically, with no extra steps in your CI pipeline. Anyone who later pulls that artifact from the cache, whether a developer, a CI runner, or a production server, has access to the full record of where it came from, including information about the cache it was downloaded from. And because FlakeHub Cache sits behind FlakeHub’s identity and access controls, that record lives inside the same access-controlled system as the artifacts themselves.

FlakeHub Cache stores provenance with each artifact and serves it to every machine that pulls it
FlakeHub Cache stores provenance with each artifact and serves it to every machine that pulls it

For Determinate Secure Packages, this is also where our own work shows up: every package is built on our audited infrastructure and arrives in your cache with its provenance fully intact, which becomes especially salient when generating SBOMs (more on this right below).

Describe: FlakeBOM turns provenance data into a useful document

A Software Bill of Materials (SBOM) is a document that auditors, regulators, customers, and others increasingly expect to be readily available. Most SBOM tools produce a final document by scanning finished artifacts and inferring what’s inside, which often provides woefully incomplete information.

FlakeBOM, a tool that we offer as part of Determinate Secure Packages, generates SBOMs directly from your Nix flakes, so it starts from Nix’s own dependency graph, which is always fully inspectable. And because FlakeBOM uses Determinate Nix directly, it reads all the available provenance data and folds it into the SBOM. The resulting document tells you how each component was built and how it got to you, enriched with identifiers and vulnerability analysis from Determinate Secure Packages.

FlakeBOM folds provenance and Secure Packages metadata into an SBOM
FlakeBOM folds provenance and Secure Packages metadata into an SBOM

Assess: FlakeAudit delivers the final judgment

You can see an SBOM as a comprehensive report on the provenance of a piece of software. But what an SBOM by definition can’t provide is a proper decision about whether that piece of software conforms to your organization’s policies. This is where FlakeAudit comes in. It enables you to craft policies, of whatever granularity you require, covering these four areas:

  • Licenses: which licenses you accept, written as Software Package Data Exchange (SPDX) expressions.
  • Bans: specific components that you aren’t willing to accept, matched by name, version, Package URL (PURL), or Common Platform Enumeration (CPE) identifier.
  • Sources: which package ecosystems (Cargo, npm, PyPI, and so on) you’re willing to accept components from.
  • Vulnerabilities: the vuln severities you’re willing to accept (and not), plus what to do with each vulnerability depending on whether it’s been triaged, and how.

Every rule you specify resolves to one of three judgments: allow, warn, or deny. If anything in the SBOM resolves to deny, FlakeAudit exits non-zero, which in turn means that the process running it, such as a CI job, fails. This enables you to automate the final yes-or-no for any piece of software, be it at build time, deploy time, or some other crucial juncture.

FlakeAudit applies your policy to every component in the SBOM
FlakeAudit applies your policy to every component in the SBOM

FlakeAudit applies judgments on SBOMs built from Nix’s dependency graph for your software, which means that it carries the provenance that Determinate Nix recorded, and that it’s enriched with the triage that Determinate Secure Packages has already done, so a vulnerability that we’ve determined doesn’t affect a given component doesn’t fail your build.

A better and more complete foundation

The chain of actions described above looks like this:

  1. Record: Determinate Nix captures how every software artifact was built.
  2. Store: FlakeHub Cache keeps provenance information attached to the artifact.
  3. Describe: FlakeBOM folds that provenance information into a final SBOM that auditors, scanners, and others can use.
  4. Assess: FlakeAudit checks the SBOM against your policy and can fail a CI build or other process in the event of policy violations.

Nix isn’t bulletproof, of course. It can’t stop a trusted maintainer from shipping malicious code and it can’t fix a CVE that doesn’t yet have a patch. There’s simply no replacement for well-thought-out policies, trustworthy people, and sound judgment.

But what Nix does give you is a foundation, via derivations, sandboxing, and closures, of a truly fundamental and lasting solution. Meanwhile, the Determinate platform provides transparency from the moment something is built to the moment your policy decides whether something meets your security team’s standards. You can’t get that end to end anywhere else, inside the Nix world or out of it.

If you’re a security engineer assessing whether Nix belongs in your organization, we’d love to talk. You can learn more about Nix, read our deeper technical take on Nix’s core constructs from a security perspective, join our community, or .

Written by

Luc Perkins

Luc is a technical writer, software engineer, and Nix advocate who's always on the lookout for qualitatively better ways of building software. He originally hails from the Pacific Northwest but has recently taken to living abroad.

Contact sales

Provide us with some basic details and we'll follow up with you about , usually within one business day.

We'll only use this to get back to you. See our privacy policy. This site is protected by reCAPTCHA and the Google Privacy Policy (opens in a new tab) and Terms of Service (opens in a new tab) apply.