From 410a766bbe0e158b572468d6173dba40bea68bff Mon Sep 17 00:00:00 2001 From: Kyle Isom Date: Tue, 24 Mar 2026 08:03:40 -0700 Subject: [PATCH] M5: documentation, packaging, and verified nix build Rewrite README with tested examples, config reference table, unlock method matrix, NixOS-specific notes on LD_LIBRARY_PATH for cryptsetup token plugins, FIDO2 enrollment instructions, and troubleshooting section. Verify nix build produces working binary with version injection. Co-Authored-By: Claude Opus 4.6 (1M context) --- README.md | 112 +++++++++++++++++++++++++++++++++++++++++++++-------- flake.lock | 27 +++++++++++++ 2 files changed, 123 insertions(+), 16 deletions(-) create mode 100644 flake.lock diff --git a/README.md b/README.md index 7086cbc..96a01b0 100644 --- a/README.md +++ b/README.md @@ -3,47 +3,74 @@ A CLI tool for mounting and unmounting LUKS-encrypted volumes. Latin for "strongbox." -arca talks to udisks2 over D-Bus, so no root privileges are required. It -handles the unlock-then-mount and unmount-then-lock sequences as single -commands. +arca talks to udisks2 over D-Bus for passphrase/keyfile unlock (no root +needed) and falls back to cryptsetup for FIDO2/TPM2 token-based unlock +(requires doas/sudo). It handles the unlock-then-mount and +unmount-then-lock sequences as single commands. ## Usage ``` -arca mount /dev/sda1 # unlock + mount by device path arca mount backup # unlock + mount by config alias +arca mount /dev/sda1 # unlock + mount by device path +arca mount backup -m /mnt/usb # mount at a specific mountpoint arca unmount backup # unmount + lock -arca status # show unlocked LUKS volumes +arca status # show all LUKS volumes and their state +arca init # generate config from detected devices +arca --version # print version ``` +Mount and unmount are idempotent: mounting an already-mounted device +prints the existing mount point; unmounting an already-locked device is +a no-op. + ## Configuration -Optional. Without a config file, arca works with device paths directly. +Optional. Without a config file, arca works with device paths directly +using passphrase unlock. -`~/.config/arca/config.yaml`: +Run `arca init` to auto-generate a config from detected LUKS devices +(excludes the root filesystem). Edit the generated file to set aliases, +methods, and mount points. + +`~/.config/arca/config.yaml` (respects `$XDG_CONFIG_HOME`): ```yaml devices: backup: - uuid: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + uuid: "b8b2f8e3-4cde-4aca-a96e-df9274019f9f" mountpoint: "/mnt/backup" # optional — udisks2 picks if omitted methods: # optional — default: [passphrase] - fido2 - passphrase media: - uuid: "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy" + uuid: "a1b2c3d4-5678-9abc-def0-1234567890ab" methods: - keyfile - passphrase keyfile: "/path/to/media.key" ``` -Aliases let you refer to devices by name and ensure stable identification -via UUID regardless of device path changes. +### Config fields -The `methods` list defines the unlock strategies to try in order. If the -first method fails (e.g., FIDO2 key not present), arca tries the next. -Supported methods: `passphrase`, `keyfile`, `fido2`, `tpm2`. +| Field | Required | Description | +|--------------|----------|--------------------------------------------------------| +| `uuid` | yes | LUKS partition UUID (stable across device path changes) | +| `mountpoint` | no | Where to mount; udisks2 picks if omitted | +| `methods` | no | Ordered unlock strategies; default: `[passphrase]` | +| `keyfile` | no | Path to keyfile (required if `keyfile` is in methods) | + +### Unlock methods + +| Method | Backend | Root required | Notes | +|--------------|------------|---------------|----------------------------------------| +| `passphrase` | udisks2 | no | Prompts on terminal | +| `keyfile` | udisks2 | no | Reads file from `keyfile` config field | +| `fido2` | cryptsetup | yes (doas) | Requires enrolled FIDO2 token | +| `tpm2` | cryptsetup | yes (doas) | Requires enrolled TPM2 key | + +Methods are tried in order. If the first fails (e.g., FIDO2 key not +plugged in), arca tries the next. ## Installation @@ -53,7 +80,7 @@ Supported methods: `passphrase`, `keyfile`, `fido2`, `tpm2`. # flake.nix inputs.arca.url = "git+https://git.wntrmute.dev/kyle/arca"; -# in your NixOS config or home packages +# in your NixOS config environment.systemPackages = [ inputs.arca.packages.${system}.default ]; ``` @@ -66,4 +93,57 @@ go install git.wntrmute.dev/kyle/arca@latest ## Requirements - Linux with udisks2 running (standard on most desktop distributions) -- D-Bus session or system bus access +- D-Bus system bus access +- For FIDO2/TPM2: `cryptsetup`, `doas` or `sudo` +- For FIDO2/TPM2: token must be enrolled via `systemd-cryptenroll` + +## NixOS Notes + +cryptsetup loads token handler plugins (FIDO2, TPM2) via `dlopen`, but +NixOS's glibc only searches the binary's baked-in RUNPATH, which doesn't +include systemd's plugin directory. arca works around this by setting +`LD_LIBRARY_PATH` to the systemd cryptsetup plugin directory when +invoking cryptsetup. + +The plugin directory is discovered automatically from +`/run/current-system/sw/lib/cryptsetup` or by resolving the +`systemd-cryptenroll` binary path. + +Note: cryptsetup's `--external-tokens-path` flag does not work on NixOS +due to the same RUNPATH limitation — the flag is accepted but the +dlopen call still uses the default search path. + +### Enrolling a FIDO2 key + +``` +doas systemd-cryptenroll --fido2-device=auto /dev/sda1 +``` + +This prompts for the existing passphrase, then enrolls the FIDO2 key. +Verify with: + +``` +doas cryptsetup luksDump /dev/sda1 | grep -A3 Token +``` + +## Troubleshooting + +**"cannot connect to udisks2"**: The udisks2 service isn't running. +Check `systemctl status udisks2`. + +**"device not found"**: The device path or alias doesn't match anything +udisks2 knows about. Run `arca status` to list detected devices, or +`arca init` to regenerate the config. + +**"No usable token is available"**: The FIDO2/TPM2 token isn't enrolled +on this LUKS device. Enroll with `systemd-cryptenroll`. Also check that +the token plugin is discoverable (see NixOS Notes above). + +**"Not authorized to perform operation"**: udisks2 polkit authorization +failed. This happens when mounting a device unlocked via cryptsetup +(root-owned mapping). Use `--mountpoint` or set `mountpoint` in config +to use privileged mount instead. + +**FIDO2 key not detected**: Ensure the key is plugged in and +`/dev/hidraw*` devices are accessible. Check `doas systemd-cryptenroll +--fido2-device=list`. diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..b1da6fd --- /dev/null +++ b/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1774244481, + "narHash": "sha256-4XfMXU0DjN83o6HWZoKG9PegCvKvIhNUnRUI19vzTcQ=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "4590696c8693fea477850fe379a01544293ca4e2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +}