From 44482d0c9fd6044117052583daaa746829902a95 Mon Sep 17 00:00:00 2001 From: File Magic Date: Fri, 14 Aug 2026 23:08:43 -0400 Subject: [PATCH] flake.nix [security]: remove NUR and audit package supply chain --- README.md | 6 + docs/security-audit.md | 265 +++++++++++++++++++++++++++++++++++++++++ flake.lock | 45 +------ flake.nix | 15 --- modules/firefox.nix | 12 -- 5 files changed, 272 insertions(+), 71 deletions(-) create mode 100644 docs/security-audit.md diff --git a/README.md b/README.md index bcea8d3..38dc09b 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,12 @@ nix flake check This evaluates and builds both NixOS configurations. Add `--no-build` to skip building (eval-only). +The repository avoids NUR because its community-maintained packages receive a +different level of review and provenance assurance than the pinned nixpkgs +packages used here. This reduces supply-chain and malware risk. Firefox +policies and profile settings remain managed in `modules/firefox.nix`; the +NUR-only packaged add-ons are not installed by the declarative profile. + ## Applying ```sh diff --git a/docs/security-audit.md b/docs/security-audit.md new file mode 100644 index 0000000..0df0566 --- /dev/null +++ b/docs/security-audit.md @@ -0,0 +1,265 @@ +# Nix Configuration Security Audit + +Audit date: 2026-08-14 + +Scope: Nix and NixOS configuration under this repository. The audit did not +open or inspect any `wireguard.nix` file because those files contain private +keys. Findings below are based on configuration review, not on a live host +inspection. + +Remediation status: configuration changes from the follow-up pass are marked +below. The installer test image still has a root SSH test-key exception because +`tests/iso-test.sh` requires it; the installed laptop no longer authorizes that +key for root. + +## Findings + +### 1. NUR community package supply-chain risk (Medium) + +**Status:** Mitigated by removing the NUR input, overlay, and NUR-only Firefox +add-on packages. + +**Why it matters:** NUR packages are community-maintained and do not receive +the same centralized review, reproducibility expectations, or provenance +assurance as the nixpkgs packages selected by this repository. Avoiding them +reduces exposure to unvetted package changes and potential supply-chain or +malware risks. This is a risk-management decision, not a claim that NUR itself +is malicious. + +**Verification:** `nix flake check --no-build` passes and no NUR references +remain in the flake, lock file, or Nix modules. + +### 2. Insecure Electron package is explicitly allowed (High) + +**Status:** Fixed by removing both insecure-package exceptions from `flake.nix`. + +**Location:** `flake.nix:82-85` and `flake.nix:111-114` + +**What:** Both desktop configurations previously set +`permittedInsecurePackages` to `["electron-39.8.10"]`. + +**Why it matters:** This bypasses nixpkgs' insecure-package rejection. Any +application using that Electron runtime inherits known upstream security risk, +and the exception applies to the whole system evaluation rather than one +carefully isolated package. + +**Recommended action:** Keep the exception absent and identify any package +evaluation failure that appears after future input updates before reintroducing +an explicit, time-bounded exception. + +### 3. Root SSH access is baked into the laptop and installer (High) + +**Status:** Partially fixed. Root SSH is disabled on the installed laptop. The +live installer retains its test-only root key until the ISO test harness is +migrated to non-root access. + +**Locations:** `13-inch-thin-cannon/configuration.nix:196-198` and +`13-inch-thin-cannon/installer.nix:85-95` + +**What:** The same tracked public test key was authorized for root SSH access on +the installed laptop and the live installer. The installed laptop now sets +`PermitRootLogin = "no"` and no longer configures a root key; the installer +still uses the key for its SSH-based test harness. + +**Why it matters:** Anyone who obtains the corresponding private test key gets +root access to both environments. The installer is especially sensitive: it +boots a privileged root environment and can rewrite the target disk. A key +named and stored as a test key is also easy to leave shared or insufficiently +rotated. + +**Recommended action:** Keep the installed-host root restriction. Migrate +`tests/iso-test.sh` to console or non-root test access, then remove the +installer's root key as well. + +### 4. Wi-Fi password is configured in a Nix expression (High if replaced) + +**Status:** Fixed. The profile now uses NetworkManager's agent-owned password +flag and does not place a password in the flake. + +**Location:** `13-inch-thin-cannon/configuration.nix:74-80` + +**What:** The NetworkManager profile previously contained a literal `password` +attribute. It now sets `password-flags = 1`, so NetworkManager prompts for the +credential instead. + +**Why it matters:** Values embedded in Nix configuration can be copied into +the world-readable Nix store and may also be present in build logs or system +closures. Replacing the placeholder with a real 802.1X password would expose +that password to users who can read the store or configuration generations. + +**Recommended action:** Keep using NetworkManager's agent-owned credential +storage. Never commit the real value or interpolate it into a derivation. + +### 5. LUKS and TPM hardening options are currently no-ops (High) + +**Status:** Partially fixed. `hardened.luks.enable` now asserts that an initrd +LUKS device exists, and the unused `hardened.luks.tpm` option was removed. TPM +enrollment itself remains a separate follow-up. + +**Locations:** `modules/luks.nix:8-14`, `harden/configuration.nix:30-37`, and +`13-inch-thin-cannon/configuration.nix:200-205` + +**What:** These options previously suggested that enabling them enforced LUKS +and TPM-backed unlocking without doing so. The LUKS option now has an initrd +assertion; TPM enrollment is no longer exposed as a non-functional option. + +**Why it matters:** This creates a false security guarantee for callers of the +shared module. The current hosts happen to define LUKS through their disko +layouts, but changing a layout or adding a host can silently produce an +unencrypted system while the hardening option remains enabled. + +**Recommended action:** Keep the LUKS assertion and test the generated +`fileSystems`, initrd crypt configuration, and unlock policy for every host. +Implement TPM enrollment separately before enabling it on physical hardware. + +### 6. Main laptop does not enable the shared kernel/AppArmor hardening (Medium) + +**Status:** Fixed. The laptop now enables both shared AppArmor and kernel +hardening settings. + +**Locations:** `13-inch-thin-cannon/configuration.nix:200-206` and +`modules/hardened.nix:8-25` + +**What:** The laptop previously left `hardened.kernel.hardened` and +`hardened.apparmor.enable` unset. Both are now enabled alongside Secure Boot, +LUKS, and impermanence. + +**Why it matters:** Secure Boot protects boot-chain integrity, but it does not +replace runtime isolation. This host also enables libvirt, USB redirection, +desktop applications, and a webcam module, so runtime attack surface is +material. + +**Recommended action:** Verify the generated AppArmor profiles and service +behavior on the physical laptop; enabling the framework alone is not a +complete policy. + +### 7. TPM-backed agenix is not enabled on the laptop (Medium) + +**Status:** Partially fixed. The user-home identity fallback was removed from +the configured identity list. TPM-backed agenix remains disabled until a TPM +identity is enrolled and tested on the physical host. + +**Locations:** `modules/secrets.nix:7-20` and +`13-inch-thin-cannon/configuration.nix:200-205` + +**What:** The shared secret declarations now use only the host SSH key. The +laptop does not enable `hardened.agenix`, so TPM-backed decryption is not yet +configured by the shared hardening module. + +**Why it matters:** A host SSH key is still a high-value decryption identity, +and it does not provide TPM-bound protection against offline disk theft. + +**Recommended action:** Enroll and test a TPM identity before enabling +TPM-backed agenix. Until then, keep the host SSH key protected and verify its +permissions and persistence; never place private identities in the repository +or Nix store. + +### 8. Disk discard is enabled for the encrypted laptop volume (Low) + +**Status:** Fixed by removing `allowDiscards` from the LUKS layout. + +**Location:** `13-inch-thin-cannon/disko.nix:22-29` + +**What:** LUKS was previously configured with `allowDiscards = true`. + +**Why it matters:** Discards can reveal information about filesystem block +usage and timing to a storage device or a party observing its behavior. This +is usually an availability/performance tradeoff, not a remote vulnerability, +but it weakens the metadata-hiding properties expected from encrypted storage. + +**Recommended action:** Keep discards disabled unless SSD space reclamation is +explicitly required and the information leak is accepted. + +### 9. Kubernetes artifacts are downloaded without integrity verification (High) + +**Status:** Open. + +**Locations:** `kubernetes/ansible/playbooks/tasks/cilium.yml` and +`kubernetes/ansible/playbooks/tasks/rook-ceph.yml`. + +**What:** The deployment downloads the Cilium Helm archive and Rook manifests +from `helm.cilium.io` and `raw.githubusercontent.com` at deployment time. The +URLs contain version strings, but the downloads are not checked against SHA-256 +digests, signatures, or repository-committed copies. + +**Why it matters:** A compromised upstream account, repository release, CDN, +DNS path, or control machine could supply modified YAML or a modified Helm +chart. Kubernetes manifests run with cluster-admin-level effects, and Helm +charts can install privileged workloads. + +**Recommended action:** Vendor the exact chart/manifests or pin and verify +checksums before applying them. Prefer signed release artifacts and verify +their signatures in the deployment workflow. Treat a version tag as a selector, +not as an integrity guarantee. + +### 10. Container image is tag-pinned but not digest-pinned (High) + +**Status:** Open. + +**Location:** `kubernetes/ansible/playbooks/tasks/rook-ceph.yml:146`. + +**What:** Ceph is configured as `quay.io/ceph/ceph:v19.2.0`, which identifies a +version tag but not an immutable image manifest digest. + +**Why it matters:** Registry tags can be moved. A later deployment or node + image pull could receive different bytes under the same tag, bypassing the + intended review and reproducibility boundary for a privileged storage + component. + +**Recommended action:** Pin the image to `quay.io/ceph/ceph@sha256:`, + record how the digest was verified against the intended release, and repeat + the same policy for every externally pulled Kubernetes image. + +### 11. Moving flake references rely on lock-file discipline (Medium) + +**Status:** Partially mitigated. The committed lock files pin content by + revision and nar hash, but nested flake declarations still use moving + channels or refs such as `nixos-unstable`, `latest`, and `master`. + +**Locations:** `flake.nix`, `harden/flake.nix`, and `kubernetes/flake.nix`. + +**Why it matters:** A normal evaluation uses the lock file, but an unlocked + checkout, an intentional lock update, or an unreviewed generated lock-file + change can pull new upstream code into the build. This is a supply-chain + review boundary, especially for bootloader, disk, secret-management, and + Kubernetes components. + +**Recommended action:** Keep lock files committed, review every lock-file diff, + avoid `latest` in source declarations, and update one dependency at a time + with `nix flake check --no-build` followed by the full relevant end-to-end + test before deployment. + +## Items Requiring Verification + +- The installer enables SSH in `installer.nix:85-91` but does not define an + explicit firewall policy. Verify from a booted ISO that SSH is unreachable + unless the intended network and key controls are present. +- `networking.firewall.checkReversePath = "loose"` is required by the + WireGuard policy-routing design (`configuration.nix:118-124`) but weakens + reverse-path anti-spoofing. Keep the nftables input policy restrictive and + verify that spoofed or unsolicited inbound traffic is rejected. +- Both desktop hosts enable libvirt and SPICE USB redirection. This is a + deliberate local virtualization feature, but it expands the privileged + device and VM attack surface. Review whether USB redirection is needed on + every host and limit access to trusted local users. +- The repository uses `nixos-unstable` in `flake.nix:5`. The lock file pins the + current inputs, but the `nix flake update` shell alias updates them without a + review gate. Review lock-file changes before deploying system generations. + +## Positive Controls Observed + +- The laptop uses full-disk LUKS in its disko layout and has Secure Boot via + Lanzaboote enabled. +- The laptop's WireGuard kill-switch drops ordinary output when `wg0` is down; + its policy-routing exception is documented in the configuration. +- Password authentication is disabled for the configured SSH services, and the + root password is locked in `modules/user.nix` when that module is enabled. +- The laptop's root filesystem is rolled back with impermanence, while selected + state and SSH host keys are intentionally persisted. + +## Useful Links + +- [NixOS package security options](https://nixos.org/manual/nixos/stable/#sec-pkgs-configuration) - insecure package handling and exceptions +- [NixOS SSH option reference](https://search.nixos.org/options?show=services.openssh.settings) - OpenSSH service settings +- [NixOS impermanence guidance](https://github.com/nix-community/impermanence) - persistence and rollback model +- [systemd-cryptenroll](https://www.freedesktop.org/software/systemd/man/latest/systemd-cryptenroll.html) - TPM-backed LUKS enrollment diff --git a/flake.lock b/flake.lock index 7be0fd7..8150965 100644 --- a/flake.lock +++ b/flake.lock @@ -97,27 +97,6 @@ "type": "github" } }, - "flake-parts": { - "inputs": { - "nixpkgs-lib": [ - "nur", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1733312601, - "narHash": "sha256-4pDvzqnegAfRkPwO3wmwBhVi/Sye1mzps0zHWYnP88c=", - "owner": "hercules-ci", - "repo": "flake-parts", - "rev": "205b12d8b7cd4802fbcb8e8ef6a0f1408781a4f9", - "type": "github" - }, - "original": { - "owner": "hercules-ci", - "repo": "flake-parts", - "type": "github" - } - }, "home-manager": { "inputs": { "nixpkgs": [ @@ -242,27 +221,6 @@ "type": "github" } }, - "nur": { - "inputs": { - "flake-parts": "flake-parts", - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1785384388, - "narHash": "sha256-Fl2U8uoxriULn4bn5tK4ZJgwk0Q6zDQWD+BdnZYs5AI=", - "owner": "nix-community", - "repo": "NUR", - "rev": "fbfd40b0bb60a5ab64aa1c58eb8944d885cd30ad", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "NUR", - "type": "github" - } - }, "pre-commit": { "inputs": { "flake-compat": "flake-compat", @@ -292,8 +250,7 @@ "home-manager": "home-manager_2", "impermanence": "impermanence", "lanzaboote": "lanzaboote", - "nixpkgs": "nixpkgs", - "nur": "nur" + "nixpkgs": "nixpkgs" } }, "rust-overlay": { diff --git a/flake.nix b/flake.nix index 3a71629..e3e6af7 100644 --- a/flake.nix +++ b/flake.nix @@ -7,10 +7,6 @@ url = "github:nix-community/home-manager"; inputs.nixpkgs.follows = "nixpkgs"; }; - nur = { - url = "github:nix-community/NUR"; - inputs.nixpkgs.follows = "nixpkgs"; - }; agenix = { url = "github:ryantm/agenix"; inputs.nixpkgs.follows = "nixpkgs"; @@ -33,18 +29,11 @@ self, nixpkgs, home-manager, - nur, agenix, ... } @ inputs: let lib = nixpkgs.lib; system = "x86_64-linux"; - nurOverlay = final: prev: { - nur = import nur { - nurpkgs = import nixpkgs {system = final.system;}; - pkgs = final; - }; - }; in { checks."${system}" = { thick-black-cannon = self.nixosConfigurations.thick-black-cannon.config.system.build.toplevel; @@ -78,10 +67,8 @@ "/share/applications" "/share/xdg-desktop-portal" ]; - nixpkgs.overlays = [nurOverlay]; nixpkgs.config = { allowUnfree = true; - permittedInsecurePackages = ["electron-39.8.10"]; }; } ]; @@ -107,10 +94,8 @@ "/share/applications" "/share/xdg-desktop-portal" ]; - nixpkgs.overlays = [nurOverlay]; nixpkgs.config = { allowUnfree = true; - permittedInsecurePackages = ["electron-39.8.10"]; }; } ]; diff --git a/modules/firefox.nix b/modules/firefox.nix index 8e13794..de76d1d 100644 --- a/modules/firefox.nix +++ b/modules/firefox.nix @@ -41,18 +41,6 @@ name = "default"; isDefault = true; - extensions = with pkgs.nur.repos.rycee.firefox-addons; { - packages = [ - ublock-origin - bitwarden - vimium - istilldontcareaboutcookies - darkreader - sponsorblock - return-youtube-dislikes - ]; - }; - search = { force = true; default = "ddg"; -- 2.51.2