From dfafac8de980b4a73dbeab155dc104cd781a879f Mon Sep 17 00:00:00 2001 From: Emma Thorpe Date: Wed, 19 Aug 2026 17:03:15 +0100 Subject: [PATCH] feat(security): swap sudo for the memory-safe sudo-rs security.sudo-rs.enable sets security.sudo.enable = false via mkDefault, so this is a straight swap; the two modules assert against being on together. The fleet only uses the stock policy -- wheel may run anything, with a password -- which sudo-rs implements fully. It does not cover host aliases, LDAP/SSSD sudoers, sudoreplay or most Defaults settings; needing any of those means reverting to security.sudo. The macOS host is unaffected and keeps Apple's sudo with Touch ID. Recovery from a host that will not escalate is documented in the module and in home/README.md: get a root shell that does not go through sudo, then roll back the generation. --- README.md | 2 +- home/README.md | 32 ++++++++++++++++++++++++-------- modules/common-nixos.nix | 16 ++++++++++++++++ 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 47d5a2b..47a6de9 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ module reaches a host: **baseModules** (every NixOS host, via `flake.nix`), | Module | Imported by | What it does / when to use it | | ------------------ | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `common-nixos.nix` | baseModules (all NixOS) | Timezone/locale, store hygiene (auto-optimise, big download buffer, **no** auto-GC), the nix-community binary cache, `nix-ld`, base CLI (`git`, `fastfetch`), and the fleet-wide font stack. | +| `common-nixos.nix` | baseModules (all NixOS) | Timezone/locale, store hygiene (auto-optimise, big download buffer, **no** auto-GC), the nix-community binary cache, `nix-ld`, **sudo-rs** in place of sudo, base CLI (`git`, `fastfetch`), and the fleet-wide font stack. | | `users.nix` | baseModules (all NixOS) | Builds `users.users` from the registry for the host's `hostUsers`; enables zsh; enables Firefox + Thunderbird **only** when `features.swayDesktop.enable` is on. Applies per-user `linger`. | | `features.nix` | baseModules (all NixOS) | Declares the feature-flag options (`features.swayDesktop.enable`, `features.claudeCode.enable`) so any host can read/set them without importing the heavy implementation module, plus the CPU capability fact they derive from (`features.cpu.microarchLevel`) and the assertion that guards it. See "CPU capability gating". | | `workstation.nix` | transitively (via laptop/desktop) | Form-factor-agnostic base for physical graphical hosts: turns on `swayDesktop`, Dvorak console, PipeWire, firewall (default-deny), fstrim, earlyoom, fwupd, thermald (x86), redistributable fw. | diff --git a/home/README.md b/home/README.md index 4ac31e2..ca37142 100644 --- a/home/README.md +++ b/home/README.md @@ -176,6 +176,21 @@ to `KUBECONFIG=prodconfig kubectl …`, per the alias-expansion note above. Completions are kubectl's own (`compdef kubecolor=kubectl`). Escape hatch as ever: `command kubectl`. +### sudo → sudo-rs + +Every NixOS host now uses **sudo-rs**, the memory-safe reimplementation, in +place of `sudo` (`modules/common-nixos.nix`; the macOS host keeps Apple's sudo +with Touch ID). Day to day there is nothing to learn — `sudo`, `sudo -i`, +`sudo -u`, `sudo -l`, `sudoedit` and `visudo` all behave as before against this +fleet's stock "wheel, with a password" policy. What it does **not** implement: +host aliases, LDAP/SSSD sudoers, `sudoreplay`, and most `Defaults` settings. +Needing any of those means reverting to `security.sudo`. + +If a host ever refuses to escalate, get a root shell that does not go through +sudo (`wsl -u root -d NixOS` on the work box; the console or a serial/HDMI login +elsewhere) and roll back with `nixos-rebuild switch --rollback`, or pick the +previous generation from the boot menu. + ## tmux **Auto-start:** opening any interactive terminal — foot, iTerm2, the WSL shell, the @@ -334,11 +349,12 @@ Claude to route new memories there. ## Per-host differences -| | Personal Linux (sway) | macOS | Work WSL (EDaaS) | -| --------------------------- | --------------------- | ----------------- | --------------------------- | -| Auto-tmux | yes (foot/TTY) | yes (iTerm2) | yes (WSL shell) | -| `kubectl` → kubecolor | no (no kubectl) | no | yes (work module) | -| git email | `iam@emmathe.dev` | `iam@emmathe.dev` | `…@citrix.com` (work) | -| ssh config managed | yes | yes | no (keeps corporate config) | -| ssh-agent | yes | launchd | yes (work module) | -| GUI / theming (desktop.nix) | yes | no | no | +| | Personal Linux (sway) | macOS | Work WSL (EDaaS) | +| --------------------------- | --------------------- | --------------------- | --------------------------- | +| Auto-tmux | yes (foot/TTY) | yes (iTerm2) | yes (WSL shell) | +| `kubectl` → kubecolor | no (no kubectl) | no | yes (work module) | +| `sudo` implementation | sudo-rs | Apple sudo + Touch ID | sudo-rs | +| git email | `iam@emmathe.dev` | `iam@emmathe.dev` | `…@citrix.com` (work) | +| ssh config managed | yes | yes | no (keeps corporate config) | +| ssh-agent | yes | launchd | yes (work module) | +| GUI / theming (desktop.nix) | yes | no | no | diff --git a/modules/common-nixos.nix b/modules/common-nixos.nix index e4b0f00..9ba118b 100644 --- a/modules/common-nixos.nix +++ b/modules/common-nixos.nix @@ -25,6 +25,22 @@ # toolchains, language-server downloads) on every NixOS host, not just WSL. programs.nix-ld.enable = true; + # Memory-safe sudo. The two modules assert against being enabled together; + # this one sets `security.sudo.enable = false` via mkDefault, so it is a + # straight swap and not an addition. + # + # Safe here because this fleet only ever uses the stock policy -- wheel may + # run anything, with a password -- which sudo-rs implements completely. It + # does not cover the more exotic sudoers surface (host aliases, LDAP/SSSD + # sudoers, most `Defaults` settings, `sudoreplay`); adding any of those means + # going back to `security.sudo`. + # + # Recovery if a host ever refuses to escalate: get a root shell without sudo + # (`wsl -u root -d NixOS` on the WSL box, the console or a serial/HDMI login + # elsewhere) and roll back -- `nixos-rebuild switch --rollback`, or pick the + # previous generation from the boot menu. + security.sudo-rs.enable = true; + # Minimal system-level CLI available before the home-manager profile loads # (e.g. early boot / rescue). User-level tooling lives in home-manager. environment.systemPackages = with pkgs; [