feat(canokey): sudo, SSH, LUKS and OpenPGP setup for daily use (#516)

Use the CanoKey for daily authentication on idols-ai and shoukei, with
the existing passwords, passphrases and per-host SSH keys as fallback.

- sudo: pam_u2f with a shared origin (pam://ryan4yin) and a Nix-store
  authfile built from myvars.canokeyU2fKeys; the primary key is
  registered and touch-to-sudo works on idols-ai.
- SSH: one resident ed25519-sk key (application=ssh:ryan4yin) exported
  to ~/.ssh/id_ed25519_sk; GitHub tries it before the per-host key.
- shoukei LUKS: fido2-device=auto with token-timeout=10s. Update
  nixos-apple-silicon (linux-asahi 7.2.14), whose initrd adds
  thunderbolt_apple and reset_apple_cio so USB-C comes up before unlock.
- GPG: scdaemon disable-ccid so it uses pcscd.
- docs/security-keys.md: setup, PINs, enrollment, backup key and
  recovery; deduplicate the FIDO notes left by #515.

Assisted-by: Claude Code (claude-opus-5-5)
This commit is contained in:
ryan4yin | 二花 authored and GitHub committed 2026-11-04 01:50:21 -06:00
1 parent 2cf3a58028
commit 71fa928254
14 files changed
+320 -58

No files matched your search

+19 -13
View File
@@ -2,6 +2,7 @@
pkgs,
config,
lib,
myvars,
...
}:
let
@@ -12,26 +13,31 @@ in
enable = lib.mkEnableOption "CanoKey hardware security key support";
};
# CanoKey docs: https://docs.canokeys.org/userguide/
#
# Principle: management and use happen on different devices. Linux PCs only
# use the key (WebAuthn/passkeys, OpenPGP, SSH). CanoKey Console management
# (Admin PIN, application/factory reset, device settings) happens only in the
# phone app (https://docs.canokeys.org/userguide/admin/), so the Admin PIN is
# never typed on a PC.
#
# Sandboxed browsers back this up: they see only the FIDO HID interface
# (hardening/nixpaks), not raw USB or CCID, so the WebUSB console cannot reach
# the key, and the vendor's WebUSB udev rule (MODE 0666 on the raw USB node)
# is deliberately not installed. Unsandboxed software is trusted; if it is
# malicious, the PC is compromised regardless.
# Usage policy, setup, backup keys and recovery: docs/security-keys.md.
# PCs only use the key and the phone app manages it, so the vendor's WebUSB
# udev rule (MODE 0666 on the raw USB node) is deliberately not installed.
config = lib.mkIf cfg.enable {
# 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).
security.pam.u2f.settings = {
authfile = pkgs.writeText "u2f-keys" ''
${myvars.username}:${lib.concatMapStringsSep ":" (lib.removePrefix ":") myvars.canokeyU2fKeys}
'';
# Shared by all hosts, so one registration works on idols-ai and shoukei.
origin = "pam://ryan4yin";
cue = true;
};
security.pam.services.sudo.u2f.enable = myvars.canokeyU2fKeys != [ ];
environment.systemPackages = with pkgs; [
ccid
pcsc-tools
pam_u2f # pamu2fcfg
];
};
}