feat(canokey): accept a key touch in polkit prompts (#522)

Assisted-by: DeepSeek Harness (claude-opus-5-5)
This commit is contained in:
ryan4yin | 二花 authored and GitHub committed 2026-11-09 08:13:30 -06:00
1 parent ad3923df98
commit abda12c00a
4 files changed
+71 -28

No files matched your search

+1
View File
@@ -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-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-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//<pkg>`, 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-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//<pkg>`, 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 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` — defaults), restore the parameters commented out in `hosts/idols-ai/hardware-configuration.nix` —
+48 -21
View File
@@ -267,6 +267,32 @@ are hard to attribute; no measured problem to solve yet.
**Decision:** _pending_ **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 # 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 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. header) should then be trimmed to **adopt** items only.
| Card | Candidate | Decision | Date | Note | | Card | Candidate | Decision | Date | Note |
| --------- | --------------------------- | -------- | ---- | ---- | | --------- | --------------------------- | -------- | ---------- | ------------------------------------------------------------------ |
| A1 | Tailscale Serve (partial) | | | | | A1 | Tailscale Serve (partial) | | | |
| A2 | systemd-resolved | | | | | A2 | systemd-resolved | | | |
| A3 | systemd-networkd | | | | | A3 | systemd-networkd | | | |
| A4 | journald upload/remote | | | | | A4 | journald upload/remote | | | |
| A5 | zram-generator | | | | | A5 | zram-generator | | | |
| A6 | nixos-facter | | | | | A6 | nixos-facter | | | |
| A7 | attic | | | | | A7 | attic | | | |
| A8 | nix-servd + daemon features | | | | | A8 | nix-servd + daemon features | | | |
| A9 | sched_ext | | | | | A9 | sched_ext | | | |
| B1 | limine + Secure Boot | | | | | A10 | oo7, then gopass | watch | 2026-11-09 | oo7 > 0.7.0 with oo7#631; gopass > 1.17.4 with a `SearchItems` fix |
| B2 | boot.uki | | | | | B1 | limine + Secure Boot | | | |
| B3 | systemd-repart images | | | | | B2 | boot.uki | | | |
| B4 | initrd repart | | | | | B3 | systemd-repart images | | | |
| B5 | sysupdate | | | | | B4 | initrd repart | | | |
| B6 | measured boot / FIDO2 | | | | | B5 | sysupdate | | | |
| B7 | systemd-vmspawn | | | | | B6 | measured boot / FIDO2 | | | |
| C1–C3, C5 | tooling + cleanups | | | | | B7 | systemd-vmspawn | | | |
| D1–D7 | lab-only group | | | | | C1–C3, C5 | tooling + cleanups | | | |
| E | rejected set | | | | | D1–D7 | lab-only group | | | |
| E | rejected set | | | |
## References ## References
+3 -2
View File
@@ -21,13 +21,14 @@ Management and use happen on different devices.
| Use | Config | Daily use | Fallback without the key | | 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 | | 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 | | 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 | | 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) | | 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 | | 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 ## 1. Device setup
+19 -5
View File
@@ -7,6 +7,7 @@
}: }:
let let
cfg = config.modules.desktop.canokey; cfg = config.modules.desktop.canokey;
hasKeys = myvars.canokeyU2fKeys != [ ];
in in
{ {
options.modules.desktop.canokey = { options.modules.desktop.canokey = {
@@ -20,10 +21,9 @@ in
# systemd tags FIDO/CCID devices uaccess (60-fido-id.rules); pcscd covers OpenPGP. # systemd tags FIDO/CCID devices uaccess (60-fido-id.rules); pcscd covers OpenPGP.
services.pcscd.enable = true; services.pcscd.enable = true;
# sudo accepts a key touch instead of the password; without the key it asks # sudo and polkit accept a key touch instead of the password; without the
# for the password as before. Login keeps the password, which also unlocks # key they ask for the password as before. Nothing changes until
# GNOME Keyring. sudo is unchanged until myvars.canokeyU2fKeys has an entry # myvars.canokeyU2fKeys has an entry (registration: docs/security-keys.md).
# (registration: docs/security-keys.md).
security.pam.u2f.settings = { security.pam.u2f.settings = {
authfile = pkgs.writeText "u2f-keys" '' authfile = pkgs.writeText "u2f-keys" ''
${myvars.username}:${lib.concatMapStringsSep ":" (lib.removePrefix ":") myvars.canokeyU2fKeys} ${myvars.username}:${lib.concatMapStringsSep ":" (lib.removePrefix ":") myvars.canokeyU2fKeys}
@@ -32,7 +32,21 @@ in
origin = "pam://ryan4yin"; origin = "pam://ryan4yin";
cue = true; 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 # A blink is easy to miss, so touch requests also raise a desktop
# notification. The package's service starts with graphical-session.target # notification. The package's service starts with graphical-session.target