mirror of
https://github.com/ryan4yin/nix-config.git
synced 2026-11-13 12:13:36 +01:00
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:
1 parent
2cf3a58028
commit
71fa928254
14 files changed
+320
-58
No files matched your search
@@ -17,6 +17,7 @@ those entry points.
|
||||
|
||||
- [Security](SECURITY.md) — threat model, trust boundaries, implemented controls and audits.
|
||||
- [Backups](BACKUP.md) — backup layers, password model, retention and restore procedure.
|
||||
- [Hardware security keys](security-keys.md) — CanoKey/YubiKey setup, backup keys and recovery.
|
||||
- [Workarounds and known gaps](WORKAROUNDS.md) — pins, temporary workarounds and removal conditions.
|
||||
- [BIOS settings](bios.md) — firmware settings for the physical hosts.
|
||||
- [Wake-on-LAN](wake-on-lan.md) — firmware prerequisites, NixOS setup and wake commands.
|
||||
|
||||
+18
-22
@@ -33,18 +33,19 @@ small, reversible controls and narrow exceptions; benchmark before adopting expe
|
||||
|
||||
## Architecture and trust boundaries
|
||||
|
||||
| Boundary | Current design | Limitation |
|
||||
| --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| Administration | Key-based SSH; root key login retained for Colmena/MicroVM deployment; only keys declared in Nix are honoured, and no password or keyboard-interactive login; remote-builder host keys only reach `nix-daemon` | Deployment credentials are root-equivalent file keys, usable by any same-user process through the desktop SSH agent; one stolen key reaches every host |
|
||||
| Host network | Shared nftables firewall trusts the home LAN, tailnet interface and local Podman bridge; IPv6 link-local is accepted | These are broad trust zones, not service-level least privilege; router exposure and tailnet ACLs require separate verification |
|
||||
| Monitoring | node/smartctl exporters bind the host LAN IPv4 (9100/9633); firewall rules restrict exporter ports 9100, 9835 and 9633 to the monitoring host over IPv4. RAPL counters are exposed only on x86 server hosts, to `node-exporter` through the `rapl` group. | nvidia_gpu_exporter (9835) still binds wildcard; the IPv6 denial for those three ports is in the shared firewall; current running hosts require separate verification. The node_exporter account can measure package energy for local side channels; interactive users, desktops, and guests keep the kernel-default root-only permission. |
|
||||
| VM hosts | shoryu, shushou and youko run guests behind `br0`; ruby/kana are libvirt guests | A bridge is not network isolation; host compromise affects its guests |
|
||||
| k3s | Three control-plane and three worker MicroVMs; Cilium, API VIP and NFS CSI | Cluster-admin, privileged/host-mounted pods and writable NFS data are powerful trust boundaries |
|
||||
| MicroVM storage | Host store shared read-only through virtiofs; guest `/etc`, `/var` and `/home` persisted in separate images | Read-only store does not isolate the host-side virtiofs implementation or protect writable guest state |
|
||||
| Desktop apps | Selected apps use nixpak/bubblewrap; Podman is rootless | Rules and shared directories vary per app; user namespaces are needed for these sandboxes |
|
||||
| Secrets | agenix declarations here, encrypted data in the private nix-secrets repository | Recipients and plaintext file permissions must be reviewed; root on a recipient can read its decrypted secrets |
|
||||
| Supply chain | Locked flake inputs; explicit binary-cache trust keys on NixOS; normal user is not a Nix trusted-user | A trusted cache or imported Nix module can supply code executed as root; a lock file is not a security audit |
|
||||
| Recovery | NixOS generations, btrbk/restic, hourly read-only snapshots of the REST store, and documented backup procedures | A rollback does not undo compromised data or secrets; backup configuration alone does not prove restore works; the offsite immutable copy is still planned |
|
||||
| Boundary | Current design | Limitation |
|
||||
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| Administration | Key-based SSH; root key login retained for Colmena/MicroVM deployment; only keys declared in Nix are honoured, and no password or keyboard-interactive login; remote-builder host keys only reach `nix-daemon` | Deployment credentials are root-equivalent file keys, usable by any same-user process through the desktop SSH agent; one stolen key reaches every host |
|
||||
| Host network | Shared nftables firewall trusts the home LAN, tailnet interface and local Podman bridge; IPv6 link-local is accepted | These are broad trust zones, not service-level least privilege; router exposure and tailnet ACLs require separate verification |
|
||||
| Monitoring | node/smartctl exporters bind the host LAN IPv4 (9100/9633); firewall rules restrict exporter ports 9100, 9835 and 9633 to the monitoring host over IPv4. RAPL counters are exposed only on x86 server hosts, to `node-exporter` through the `rapl` group. | nvidia_gpu_exporter (9835) still binds wildcard; the IPv6 denial for those three ports is in the shared firewall; current running hosts require separate verification. The node_exporter account can measure package energy for local side channels; interactive users, desktops, and guests keep the kernel-default root-only permission. |
|
||||
| VM hosts | shoryu, shushou and youko run guests behind `br0`; ruby/kana are libvirt guests | A bridge is not network isolation; host compromise affects its guests |
|
||||
| k3s | Three control-plane and three worker MicroVMs; Cilium, API VIP and NFS CSI | Cluster-admin, privileged/host-mounted pods and writable NFS data are powerful trust boundaries |
|
||||
| MicroVM storage | Host store shared read-only through virtiofs; guest `/etc`, `/var` and `/home` persisted in separate images | Read-only store does not isolate the host-side virtiofs implementation or protect writable guest state |
|
||||
| Desktop apps | Selected apps use nixpak/bubblewrap; Podman is rootless | Rules and shared directories vary per app; user namespaces are needed for these sandboxes |
|
||||
| Security keys | idols-ai/shoukei use a CanoKey for touch-based sudo (pam_u2f, password fallback), one resident `ed25519-sk` SSH key for GitHub and all hosts, FIDO2 LUKS unlock on shoukei and on-card OpenPGP subkeys; key management happens only in the phone app ([setup](./security-keys.md)) | Touch-only sudo can be triggered by any same-user process; per-host file SSH keys and passphrases stay valid as fallback, so their weaknesses remain until retired |
|
||||
| Secrets | agenix declarations here, encrypted data in the private nix-secrets repository | Recipients and plaintext file permissions must be reviewed; root on a recipient can read its decrypted secrets |
|
||||
| Supply chain | Locked flake inputs; explicit binary-cache trust keys on NixOS; normal user is not a Nix trusted-user | A trusted cache or imported Nix module can supply code executed as root; a lock file is not a security audit |
|
||||
| Recovery | NixOS generations, btrbk/restic, hourly read-only snapshots of the REST store, and documented backup procedures | A rollback does not undo compromised data or secrets; backup configuration alone does not prove restore works; the offsite immutable copy is still planned |
|
||||
|
||||
Sources: [host layout](../hosts/README.md), [k3s deployment](../hosts/k8s/README.md),
|
||||
[firewall](../modules/nixos/base/networking/firewall.nix), [SSH](../modules/nixos/base/ssh.nix),
|
||||
@@ -332,13 +333,9 @@ isolation. Source review and socket metadata—not reads of private credentials
|
||||
Browser media and browserpass are enabled only for Firefox/Chromium/Chrome. Brave Origin and Edge
|
||||
are backup browsers with no media grants. browserpass exposes password-store/GPG data and agent
|
||||
operations.
|
||||
- Firefox/Chromium/Chrome receive FIDO2 security-key passthrough for WebAuthn/passkeys. Host udev
|
||||
rules hard-link only FIDO-tagged hidraw nodes into `/dev/fido-hidraw` and remove them on unplug;
|
||||
the sandbox binds that directory plus read-only `/sys/class/hidraw` and the udev database. The
|
||||
CanoKey KBD and CCID interfaces, other HID devices and raw USB stay outside the sandbox; Brave
|
||||
Origin and Edge receive no FIDO2 passthrough. A compromised browser can use the key's FIDO
|
||||
interface; the key's PIN and touch policy remain the authentication boundary. Hotplug works for
|
||||
host-network Firefox/Chromium; pasta-isolated Chrome needs the key present at launch.
|
||||
- Firefox/Chromium/Chrome receive only a security key's FIDO interface (mechanism and limits in the
|
||||
[hardening README](../hardening/README.md#limits)). A compromised browser can use that interface;
|
||||
the key's PIN and touch policy remain the authentication boundary.
|
||||
- Nixpak supplements Chromium's renderer sandbox, which remains enabled. Zoom/WeChat retain their
|
||||
FHS runtimes inside the outer boundary; inner mounts cannot recover hidden host resources.
|
||||
- Desktop access has limits: GPU drivers remain exposed, PulseAudio permits recording, read-only
|
||||
@@ -355,9 +352,8 @@ isolation. Source review and socket metadata—not reads of private credentials
|
||||
- Policy/build passes for all nine wrappers. Interactive validation passed for Firefox, Chrome,
|
||||
Chromium, Brave Origin, Edge, QQ, Telegram and Zoom; the Chromium smoke test also validates
|
||||
renderer sandboxing, environment clearing, bind scope and profile persistence. WeChat's
|
||||
interactive Wayland check remains pending. FIDO2 browser passthrough passed WebAuthn with the
|
||||
CanoKey in Firefox and Chrome; Chromium and plugging the key in after launch still need
|
||||
validation. See the [runtime validation](../hardening/tests/runtime-validation.md).
|
||||
interactive Wayland check remains pending. See the
|
||||
[runtime validation](../hardening/tests/runtime-validation.md).
|
||||
|
||||
#### Agent-first diagnostics by host role
|
||||
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
# Hardware security keys
|
||||
|
||||
How the CanoKey (or a YubiKey) is set up and used on the desktops: initial setup, adding a backup
|
||||
key, and recovery. Commands here are the single source; the Nix files only point to this page.
|
||||
|
||||
Scope: **idols-ai** and **shoukei** (`modules.desktop.canokey.enable`). frieren only shares the
|
||||
GnuPG `scdaemon` setting; servers never use a key.
|
||||
|
||||
## Principle
|
||||
|
||||
Management and use happen on different devices.
|
||||
|
||||
- **PCs only use the key:** WebAuthn/passkeys, sudo, SSH, LUKS unlock and OpenPGP (pass).
|
||||
- **Management happens only in the phone app** (CanoKey Console on iOS/Android): every PIN change,
|
||||
touch policies, application and factory reset, device settings. The CanoKey Admin PIN is never
|
||||
typed on a PC; the OpenPGP Admin PIN is typed once, for `keytocard`.
|
||||
- Sandboxed browsers see only the FIDO HID interface, never raw USB or CCID, so the WebUSB console
|
||||
is unreachable from them ([hardening](../hardening/README.md)). Unsandboxed software is trusted;
|
||||
if it is malicious, the PC is compromised regardless.
|
||||
|
||||
| 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 |
|
||||
| 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.
|
||||
|
||||
## 1. Device setup
|
||||
|
||||
### 1.1 Replace every default secret first
|
||||
|
||||
Each application has its own secrets: separate values, separate retry counters (3 on released
|
||||
firmware), and blocking one does not affect the others. The defaults are public (from the
|
||||
[CanoKey user guide](https://docs.canokeys.org/userguide/)), so change all of them in the phone app
|
||||
(CanoKey Console) **before using the key for anything**, including applications you do not use: with
|
||||
a default PIN or management key, anyone holding the key can use or rewrite that application.
|
||||
|
||||
| Application | Secret | Default | Protects | Set it to | Typed |
|
||||
| ----------- | ----------------- | ---------------------- | ---------------------------------------------------------- | --------------------------------------------------------------------- | --------------- |
|
||||
| Device | CanoKey Admin PIN | `123456` | settings, per-application and factory reset | random, 12+ characters (6–64); save offline | phone only |
|
||||
| WebAuthn | FIDO2 PIN | unset | passkeys, LUKS unlock, SSH key creation and export | memorable, 8+ characters (4–63); memorize | daily, browsers |
|
||||
| OpenPGP | PIN | `123456` | decrypt (pass), sign, authenticate | memorable, 8+ characters (6–64), not the FIDO2 PIN; memorize | daily, pinentry |
|
||||
| OpenPGP | Admin PIN | `12345678` | key import (`keytocard`), touch policy, unblocking the PIN | random, 12+ characters (8–64); save offline | setup only |
|
||||
| OpenPGP | Reset Code | unset | unblocking the PIN without the Admin PIN | leave unset (the Admin PIN also unblocks), or random and save offline | recovery only |
|
||||
| PIV | PIN / PUK | `123456` / `12345678` | PIV keys / unblocking the PIV PIN | 8 random digits each (maximum 8); do not save | never |
|
||||
| PIV | management key | `0102030405060708` × 3 | writing PIV keys and certificates | the app's random management key button; do not save | never |
|
||||
| OATH | none: no password | — | anyone holding the key can read its TOTP/HOTP codes | — | — |
|
||||
|
||||
Every PIN locks after 3 wrong attempts, so length matters less than not reusing a value. Generate
|
||||
the random values with the phone's password manager; "save offline" means that password manager or
|
||||
paper, never `pass`: `pass` itself is decrypted by this key. The FIDO2 PIN is typed into browsers,
|
||||
the least trusted place, so it must not also unlock pass.
|
||||
|
||||
PIV is unused, so its secrets are random and discarded: PIV is then locked rather than open with
|
||||
public defaults. To use PIV later, reset just the PIV application in the phone app (needs only the
|
||||
CanoKey Admin PIN), which restores the defaults.
|
||||
|
||||
### 1.2 Firmware and settings (phone app)
|
||||
|
||||
Touch policies are enforced **only over USB, not NFC**. OpenPGP and PIV stay reachable over NFC on
|
||||
released firmware, but each NFC tap is a new card session, so their PINs are still required.
|
||||
|
||||
1. Check the firmware version. U2F (sudo) does not work on 3.0.0; 3.0.2 and later are fine. The
|
||||
newest public release is canokey-core [3.0.3](https://github.com/canokeys/canokey-core/tags).
|
||||
2. Settings on released firmware (the user guide lists LED, NDEF and WebUSB login page):
|
||||
|
||||
| Setting | Choice | Why |
|
||||
| ----------------- | -------------------------------------- | ------------------------------------------------------------------------- |
|
||||
| LED | on | an unexpected blink means something requested a touch |
|
||||
| WebUSB login page | off | the console is not used on PCs |
|
||||
| NDEF | off, or read-only if the app offers it | default is enabled; anyone nearby can read it, and rewrite it if writable |
|
||||
|
||||
3. The user guide also documents options for **firmware 3.1.0**, which has no public release yet
|
||||
(only the docs mention it; canokey-core's `dev` branch is unversioned). If the app shows them:
|
||||
|
||||
| Option | Choice | Why |
|
||||
| ------------------------------------------- | --------------------------------------------- | ------------------------------------------ |
|
||||
| OpenPGP / PIV over NFC | off, unless the phone needs OpenPGP | touch is not enforced over NFC |
|
||||
| Password/HOTP keyboard output, PIV switches | off unless used | smaller attack surface |
|
||||
| WebAuthn `alwaysUv` | off | on breaks U2F, which sudo uses |
|
||||
| WebAuthn minimum PIN length | 6–8 | the PIN locks after a few failures |
|
||||
| Long-press reset | off, unless the app documents it as PIN-gated | keeps reset a phone-side management action |
|
||||
|
||||
## 2. Enroll a key
|
||||
|
||||
Only after section 1.1. Do these in order; each step can be rolled back on its own. Only the OpenPGP
|
||||
step is irreversible.
|
||||
|
||||
### Browsers (WebAuthn / passkeys)
|
||||
|
||||
Nothing to enroll on the PC. Register the key on each site, preferably as a passkey. After a first
|
||||
deploy via `switch` without reboot, see the FIDO2 notes in the
|
||||
[hardening README](../hardening/README.md#limits).
|
||||
|
||||
### sudo
|
||||
|
||||
```bash
|
||||
# pamu2fcfg is installed once canokey.nix is deployed; before that:
|
||||
# Long options: some nix versions expand short flags such as -i after --command.
|
||||
nix shell nixpkgs#pam_u2f --command \
|
||||
pamu2fcfg --nouser --origin=pam://ryan4yin # touch the key
|
||||
```
|
||||
|
||||
Add the printed `KeyHandle,PublicKey,es256,+presence` string to `canokeyU2fKeys` in
|
||||
[vars/default.nix](../vars/default.nix) (public data; a leading `:` is accepted) and deploy. sudo
|
||||
then shows "Please touch the device"; without the key it asks for the password. While the list is
|
||||
empty, sudo is unchanged.
|
||||
|
||||
Every host shares the origin `pam://ryan4yin`, so one registration covers idols-ai and shoukei.
|
||||
|
||||
### SSH
|
||||
|
||||
One SSH key, used for GitHub and every host, lives on the key as a resident credential:
|
||||
|
||||
```bash
|
||||
ssh-keygen -t ed25519-sk -O resident -O application=ssh:ryan4yin -C ryan@canokey
|
||||
```
|
||||
|
||||
This writes `~/.ssh/id_ed25519_sk` on the machine that runs it. On each other desktop, export the
|
||||
key handle to ssh's default identity:
|
||||
|
||||
```bash
|
||||
cd ~/.ssh && ssh-keygen -K \
|
||||
&& mv id_ed25519_sk_rk_ryan4yin id_ed25519_sk && mv id_ed25519_sk_rk_ryan4yin.pub id_ed25519_sk.pub
|
||||
```
|
||||
|
||||
How it works, and what the prompts mean:
|
||||
|
||||
- The private key never leaves the CanoKey. `~/.ssh/id_ed25519_sk` holds only the credential ID,
|
||||
application and public key. Every authentication sends the server's challenge to the key, which
|
||||
signs it after a touch; with the key unplugged, ssh skips this identity and tries the next one.
|
||||
- **FIDO2 PIN:** asked only when creating the credential and when exporting it with `-K`, not for
|
||||
each login. Adding `-O verify-required` at creation would require the PIN for every login too.
|
||||
- **Touch:** required for every new connection, including each `git push`/`fetch`. Existing sessions
|
||||
and reused connections need none: LAN hosts multiplex for 30 minutes (`ControlMaster` in
|
||||
[ssh.nix](../home/base/tui/ssh.nix)). A deploy that opens one connection per host needs one touch
|
||||
per host.
|
||||
- **File passphrase:** leave it empty. Reading the file already takes your user session, and
|
||||
software running as you is trusted (see [Principle](#principle)); it could also capture the
|
||||
passphrase the next time you type it. A passphrase would cost one prompt per login, not per
|
||||
connection: `AddKeysToAgent yes` keeps the unlocked handle in the agent, which still asks the key
|
||||
for each signature.
|
||||
|
||||
Add the public key to `mainSshAuthorizedKeys` in [vars/default.nix](../vars/default.nix) and to
|
||||
GitHub. GitHub tries `id_ed25519_sk` before the per-host key; other hosts try it as a default
|
||||
identity. Keys already loaded in `ssh-agent` are offered first, so the per-host keys can still win
|
||||
until they are retired.
|
||||
|
||||
### shoukei LUKS
|
||||
|
||||
Enroll before deploying the crypttab change:
|
||||
|
||||
```bash
|
||||
systemd-cryptenroll --fido2-device=list # as the user: shows the key's hidraw node
|
||||
sudo systemd-cryptenroll --fido2-device=/dev/hidrawN /dev/disk/by-uuid/1c37820e-2501-46e4-bec4-27c28691a5b4
|
||||
sudo systemd-cryptenroll /dev/disk/by-uuid/1c37820e-2501-46e4-bec4-27c28691a5b4 # list slots
|
||||
```
|
||||
|
||||
Name the hidraw node instead of `--fido2-device=auto`: libfido2 is built with PC/SC support, so root
|
||||
also finds the key's FIDO applet through pcscd (`pcsc://slot0`) and `auto` stops with "More than one
|
||||
FIDO device found". Unlocking at boot is unaffected: pcscd does not run in the initrd.
|
||||
|
||||
The default enrollment requires the FIDO2 PIN and a touch; keep it that way, since the key often
|
||||
travels with the laptop. The passphrase slot stays. Reboot to verify.
|
||||
|
||||
### pass (OpenPGP)
|
||||
|
||||
The password store is encrypted to the `[E]` subkey `0xEF824EB73CFD6CC7`; the primary key is
|
||||
offline.
|
||||
|
||||
1. Verify the **off-card backup** of all three subkeys first: `keytocard` replaces the on-disk copy
|
||||
with a stub.
|
||||
2. Move the subkeys: `gpg --edit-key 0xCC88591C033F1924`, then `key 1` → `keytocard` (encryption),
|
||||
and likewise for the signing and authentication subkeys; `save`.
|
||||
3. Require touch for SIG, DEC and AUT in the phone app's OpenPGP page (or on the PC:
|
||||
`gpg --card-edit` → `admin` → `uif 1 on`, `uif 2 on`, `uif 3 on`). Decrypt touch matters most:
|
||||
browserpass gives browsers the GPG agent socket, and without touch a compromised browser could
|
||||
decrypt the whole store silently after the first PIN.
|
||||
4. On other machines that still hold on-disk copies, delete them
|
||||
(`gpg --delete-secret-keys '<subkey-fingerprint>!'`) and run `gpg --card-status` so gpg records
|
||||
stubs for the card.
|
||||
|
||||
`keytocard` is the only step that types the OpenPGP Admin PIN on a PC; change it again in the phone
|
||||
app afterwards.
|
||||
|
||||
## 3. Add a backup key
|
||||
|
||||
A second CanoKey or a YubiKey works the same way; the module name is CanoKey-specific but nothing in
|
||||
it is. On a YubiKey, manage settings with Yubico Authenticator or `ykman`; OpenPGP touch is
|
||||
`ykman openpgp keys set-touch dec on` (and `sig`, `aut`).
|
||||
|
||||
| Use | Backup key step |
|
||||
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Device | Section 1 again |
|
||||
| Browsers | Register it on every site as an additional security key |
|
||||
| sudo | `pamu2fcfg --nouser --origin=pam://ryan4yin` with only the backup plugged in; append to `canokeyU2fKeys` |
|
||||
| SSH | Create a resident key on it with the same command; add its public key to `mainSshAuthorizedKeys` and GitHub. Use it with `ssh-add -K` (loads resident keys into the agent) instead of exporting a file |
|
||||
| shoukei LUKS | Run the same `systemd-cryptenroll --fido2-device=auto` with only the backup plugged in; it takes the next slot |
|
||||
| OpenPGP | Import the subkeys from the backup into a fresh, temporary `GNUPGHOME`, `keytocard` them onto the backup key, then delete that `GNUPGHOME`. The stubs remember the card serial; after swapping cards run `gpg-connect-agent "scd serialno" "learn --force" /bye` |
|
||||
|
||||
## 4. Lost key or reset
|
||||
|
||||
| Situation | Action | Lost |
|
||||
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
|
||||
| Key lost | Remove its `canokeyU2fKeys` entry and SSH public key; `systemd-cryptenroll --wipe-slot=<n>`; remove it on each site | nothing, if a backup key or the passwords remain |
|
||||
| FIDO2 PIN forgotten or locked | Phone app: reset the WebAuthn application (needs the Admin PIN) | all passkeys, the SSH resident key, LUKS and sudo enrollments; redo section 2 |
|
||||
| OpenPGP PIN locked | `gpg --card-edit` → `admin` → `passwd`, unblock with the OpenPGP Admin PIN or Reset Code | nothing |
|
||||
| All OpenPGP PINs and Reset Code lost | Phone app: reset the OpenPGP application | on-card subkeys; re-import from the backup |
|
||||
| Admin PIN forgotten | Exhaust the Admin PIN, then in the app tap Reset and touch the key while the LED blinks, repeating until it stops | all user data; serial and attestation keys stay |
|
||||
|
||||
After any reset, rerun sections 1 and 2 for the affected applications.
|
||||
|
||||
## Enrollment status
|
||||
|
||||
| Key | Firmware | sudo | SSH | shoukei LUKS | OpenPGP | Browsers |
|
||||
| ------------------------ | -------- | ----------------- | ---------------------------------------------------------- | ----------------------------- | -------- | -------------------------------- |
|
||||
| CanoKey Canary (primary) | 3.0.3 | works on idols-ai | key created; public key not yet in `mainSshAuthorizedKeys` | enrolled; unlock not verified | deferred | WebAuthn works in Firefox/Chrome |
|
||||
|
||||
shoukei's first boots with the FIDO2 slot asked for the PIN, then fell back to the passphrase: USB
|
||||
only came up after switch-root, because on linux-asahi 7.2 its dwc3/PHY depend on the Thunderbolt
|
||||
(ACIO) nodes, whose `thunderbolt_apple` and `reset_apple_cio` drivers were missing from the initrd.
|
||||
nixos-apple-silicon added both upstream (`275e570ea8`), and the input now includes it; unlocking
|
||||
with the key is not yet verified. Also not verified: the CanoKey Admin PIN retry count, and how
|
||||
touch is performed when resetting over NFC.
|
||||
|
||||
## References
|
||||
|
||||
- [CanoKey user guide](https://docs.canokeys.org/userguide/): settings, WebAuthn, OpenPGP, PIV
|
||||
- [NixOS wiki: YubiKey](https://wiki.nixos.org/wiki/Yubikey): pam_u2f, `disable-ccid`
|
||||
- [pam-u2f](https://developers.yubico.com/pam-u2f/), `systemd-cryptenroll(1)`, `crypttab(5)`
|
||||
- Comparable NixOS configs: cloud-gouv/securix (`modules/pam/u2f.nix`), kclejeune/system,
|
||||
joshsymonds/nix-config, wimpysworld/nix-config
|
||||
Reference in new issue
Block a user