diff --git a/docs/WORKAROUNDS.md b/docs/WORKAROUNDS.md index 80af5ad3..042af472 100644 --- a/docs/WORKAROUNDS.md +++ b/docs/WORKAROUNDS.md @@ -50,6 +50,7 @@ A setting that works around a bug or a hardware quirk. | WA-046 | xdg-desktop-portal-wlr pinned to 0.8.2 — `modules/nixos/desktop/xdg.nix` | niri's GNOME ScreenCast path exposes only DMA-BUF with modifiers, which Zoom 7.2.1 rejects; xdg-desktop-portal-wlr 0.8.2 provides the working SHM path, while 0.8.4 regresses Zoom's SelectSources. | Drop once niri's ScreenCast path works with Zoom or xdg-desktop-portal-wlr 0.8.4+ is fixed. | 2026-10-31 | eval assertion, or on a Zoom update | active | | WA-048 | Nixpak GUI fontconfig comes from the host — `hardening/nixpaks/modules/desktop-base.nix` | Nixpak normally generates a standalone `/etc/fonts` and font package list for each sandbox; that bypasses the host `defaultFonts` and made browser chrome, Telegram, QQ and other sandboxed apps choose a different CJK fallback from the host. The wrapper now disables Nixpak fonts and bind-mounts `/etc/static/fonts` at `/etc/fonts`, so sandboxed GUI apps reuse the host font packages and family preferences through the already-mounted `/nix/store`. | Drop once Nixpak can directly reuse the host fontconfig or no longer overrides `/etc/fonts`, then remove the bind and restore the library-supported configuration path | 2026-11-01 | on a nixpak update | active | | WA-049 | none — superseded by pointing `npmRegistryOverrides` at a mirror whose path avoids the join (`outputs/default.nix`) | nixpkgs joins an `npmRegistryOverrides` mirror's path (`/` for a bare host) with the request path, so `fetchNpmDeps` requests `https://registry.npmmirror.com//`, which npmmirror answers with 404 (npmjs tolerates `//`); every npm-deps fetch that misses the binary caches fails. Only `fetchNpmDeps` (fixed-output) gets the patched copy: `npmConfigHook` is a build input of every npm package, so patching the shared `prefetch-npm-deps` would change all their output paths | Drop once nixpkgs' `prefetch-npm-deps/src/util.rs` joins the paths without doubling the slash | 2026-11-03 | on a nixpkgs bump | removed | +| WA-050 | polkit agent-helper sandbox opened for pam_u2f — `modules/nixos/desktop/canokey.nix` | nixpkgs relaxes `polkit-agent-helper@`'s `PrivateDevices`/`ProtectHome` for pam_u2f only when the global `security.pam.u2f.enable` is set; this repo enables U2F per service (sudo, polkit-1) so other PAM services keep the password, and without the override pam_u2f cannot reach `/dev/hidraw*` and polkit silently falls back to the password | Drop once nixpkgs' `polkit.nix` also checks per-service `u2f.enable` | 2026-11-09 | on a nixpkgs bump | active | If the KINGBANK KP260 NVMe freezes on `ai` recur (formerly WA-008, now back at the kernel's APST defaults), restore the parameters commented out in `hosts/idols-ai/hardware-configuration.nix` — diff --git a/docs/nixos-modernization-options.md b/docs/nixos-modernization-options.md index c669cae5..cc4b905b 100644 --- a/docs/nixos-modernization-options.md +++ b/docs/nixos-modernization-options.md @@ -267,6 +267,32 @@ are hard to attribute; no measured problem to solve yet. **Decision:** _pending_ +## A10. oo7, then gopass, behind the Secret portal + +**Current:** gnome-keyring serves the Secret Service and the Secret portal Chromium uses for its v12 +cookie key; its portal can only serve its own daemon. + +**Proposed:** `services.oo7.enable`, whose oo7-portal serves any Secret Service daemon; then replace +oo7-daemon with `gopass secret-service`, so gh's token and Chrome's cookie key need the CanoKey. + +**Pros:** oo7 is a memory-safe, actively developed replacement on its own; with gopass, +hardware-gated secrets from upstream components only. + +**Cons:** migration deletes the gnome-keyring files. On 2026-11-09, oo7 0.6.0 hid gh's token (fixed +in 0.7.0) and gave Chrome a new key, losing its v12 cookies (fixed after 0.7.0 by +[oo7#631](https://github.com/linux-credentials/oo7/pull/631), unreleased). gopass 1.17.4 skips +undecryptable items, so a refused touch would mint a new Chrome key the same way. + +**Reversibility:** low; needs a backup of `~/.local/share/keyrings` under `/persistent`. + +**Trigger to adopt:** nixpkgs ships oo7 newer than 0.7.0 with the portal app-ID fix +([oo7#631](https://github.com/linux-credentials/oo7/pull/631); 0.7.0 fixes only gh). For gopass: a +release after 1.17.4 whose `SearchItems` stops skipping undecryptable items (no upstream issue yet). + +**Recommendation:** **watch**. + +**Decision:** **watch** (2026-11-09) + --- # B. Boot, images, VMs @@ -489,27 +515,28 @@ prevent boot or login. **Recommendation for the group: evaluate in a disposable Fill this in as cards are decided; the plan documents (on the `modernization-plans-wip` tag, see the header) should then be trimmed to **adopt** items only. -| Card | Candidate | Decision | Date | Note | -| --------- | --------------------------- | -------- | ---- | ---- | -| A1 | Tailscale Serve (partial) | | | | -| A2 | systemd-resolved | | | | -| A3 | systemd-networkd | | | | -| A4 | journald upload/remote | | | | -| A5 | zram-generator | | | | -| A6 | nixos-facter | | | | -| A7 | attic | | | | -| A8 | nix-servd + daemon features | | | | -| A9 | sched_ext | | | | -| B1 | limine + Secure Boot | | | | -| B2 | boot.uki | | | | -| B3 | systemd-repart images | | | | -| B4 | initrd repart | | | | -| B5 | sysupdate | | | | -| B6 | measured boot / FIDO2 | | | | -| B7 | systemd-vmspawn | | | | -| C1–C3, C5 | tooling + cleanups | | | | -| D1–D7 | lab-only group | | | | -| E | rejected set | | | | +| Card | Candidate | Decision | Date | Note | +| --------- | --------------------------- | -------- | ---------- | ------------------------------------------------------------------ | +| A1 | Tailscale Serve (partial) | | | | +| A2 | systemd-resolved | | | | +| A3 | systemd-networkd | | | | +| A4 | journald upload/remote | | | | +| A5 | zram-generator | | | | +| A6 | nixos-facter | | | | +| A7 | attic | | | | +| A8 | nix-servd + daemon features | | | | +| A9 | sched_ext | | | | +| A10 | oo7, then gopass | watch | 2026-11-09 | oo7 > 0.7.0 with oo7#631; gopass > 1.17.4 with a `SearchItems` fix | +| B1 | limine + Secure Boot | | | | +| B2 | boot.uki | | | | +| B3 | systemd-repart images | | | | +| B4 | initrd repart | | | | +| B5 | sysupdate | | | | +| B6 | measured boot / FIDO2 | | | | +| B7 | systemd-vmspawn | | | | +| C1–C3, C5 | tooling + cleanups | | | | +| D1–D7 | lab-only group | | | | +| E | rejected set | | | | ## References diff --git a/docs/security-keys.md b/docs/security-keys.md index 3e73396c..45f845a3 100644 --- a/docs/security-keys.md +++ b/docs/security-keys.md @@ -21,13 +21,14 @@ Management and use happen on different devices. | Use | Config | Daily use | Fallback without the key | | ------------ | ---------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- | ----------------------------------------- | | Browsers | [nixpak FIDO2 passthrough](../hardening/nixpaks/default.nix) | FIDO2 PIN and/or touch, as the site asks | site recovery codes, other registered key | -| sudo | [canokey.nix](../modules/nixos/desktop/canokey.nix), registrations in [vars](../vars/default.nix) `canokeyU2fKeys` | touch | password | +| sudo, polkit | [canokey.nix](../modules/nixos/desktop/canokey.nix), registrations in [vars](../vars/default.nix) `canokeyU2fKeys` | touch | password | | sudo via SSH | [ssh-agent-sudo.nix](../modules/nixos/server/ssh-agent-sudo.nix), keys in [vars](../vars/default.nix) `canokeySshKeys` | touch | password | | SSH | [ssh.nix](../home/base/tui/ssh.nix), public keys in [vars](../vars/default.nix) `mainSshAuthorizedKeys` | touch per connection | per-host file keys | | shoukei LUKS | [hardware-configuration.nix](../hosts/12kingdoms-shoukei/hardware-configuration.nix) `crypttabExtraOpts` | FIDO2 PIN + touch | passphrase (prompted after 10 s) | | pass / GPG | [gpg](../home/base/tui/gpg/default.nix) `scdaemonSettings.disable-ccid` | OpenPGP PIN once per plug-in, then touch | off-card subkey backup | -Login (greetd) stays password-based: the password also unlocks GNOME Keyring. +Only sudo and polkit accept a touch. Login (greetd), the lock screen and every other PAM service +stay password-based: the login password also unlocks GNOME Keyring. ## 1. Device setup diff --git a/modules/nixos/desktop/canokey.nix b/modules/nixos/desktop/canokey.nix index 7f3ebc20..a24b306b 100644 --- a/modules/nixos/desktop/canokey.nix +++ b/modules/nixos/desktop/canokey.nix @@ -7,6 +7,7 @@ }: let cfg = config.modules.desktop.canokey; + hasKeys = myvars.canokeyU2fKeys != [ ]; in { options.modules.desktop.canokey = { @@ -20,10 +21,9 @@ in # systemd tags FIDO/CCID devices uaccess (60-fido-id.rules); pcscd covers OpenPGP. services.pcscd.enable = true; - # sudo accepts a key touch instead of the password; without the key it asks - # for the password as before. Login keeps the password, which also unlocks - # GNOME Keyring. sudo is unchanged until myvars.canokeyU2fKeys has an entry - # (registration: docs/security-keys.md). + # sudo and polkit accept a key touch instead of the password; without the + # key they ask for the password as before. Nothing changes until + # myvars.canokeyU2fKeys has an entry (registration: docs/security-keys.md). security.pam.u2f.settings = { authfile = pkgs.writeText "u2f-keys" '' ${myvars.username}:${lib.concatMapStringsSep ":" (lib.removePrefix ":") myvars.canokeyU2fKeys} @@ -32,7 +32,21 @@ in origin = "pam://ryan4yin"; cue = true; }; - security.pam.services.sudo.u2f.enable = myvars.canokeyU2fKeys != [ ]; + security.pam.services = { + sudo.u2f.enable = hasKeys; + polkit-1.u2f.enable = hasKeys; + }; + # WA-050: nixpkgs opens polkit's agent-helper sandbox for pam_u2f only + # when the global security.pam.u2f.enable is set; copied from its + # nixos/modules/security/polkit.nix for the per-service enable above. + systemd.services."polkit-agent-helper@".serviceConfig = lib.mkIf hasKeys { + PrivateDevices = false; + DeviceAllow = [ + "/dev/urandom r" + "char-hidraw rw" + ]; + ProtectHome = "read-only"; + }; # A blink is easy to miss, so touch requests also raise a desktop # notification. The package's service starts with graphical-session.target