braid enroll
Enrolls a binary keyfile into LUKS slot 1 on all pool disks. Used to set up USB auto-unlock: plug in a USB drive with the keyfile, and braid unlock --key-file can open the pool without typing a passphrase.
When to use it
- Setting up unattended unlock via USB keyfile.
- After adding a new disk to the pool (enroll the keyfile on it too).
Basic example
Generate a new keyfile on a USB drive and enroll it on all pool disks:
sudo braid enroll /mnt/usb --generate
/mnt/usb must already exist and be mounted. This creates /mnt/usb/braid.key (4096 bytes of random data) and adds it to LUKS slot 1 on every disk in the pool. You’ll be prompted for the pool passphrase.
Common variations
Enroll an existing keyfile (already at /mnt/usb/braid.key):
sudo braid enroll /mnt/usb
Non-interactive (passphrase from stdin):
echo -n 'my-passphrase' | sudo braid enroll /mnt/usb --generate --passphrase-stdin
Passphrase from a file:
sudo braid enroll /mnt/usb --generate --passphrase-file /root/passphrase.txt
Dry run (preview what would happen):
sudo braid enroll /mnt/usb --generate --dry-run
Flags
| Flag | Effect |
|---|---|
--generate | Create a new 4096-byte random keyfile before enrolling; the target directory must already be a mount point |
--passphrase-stdin | Read passphrase from stdin instead of TTY prompt |
--passphrase-file <path> | Read passphrase from a file instead of TTY prompt (conflicts with --passphrase-stdin) |
--dry-run | Show what would happen without making changes |
What happens under the hood
- Checks for a pending operation journal (refuses if one exists).
- With
--generate: Validates that the target directory exists, is a directory, is already a mount point, and does not already containbraid.key(if a prior--generaterun was interrupted, drop--generateand re-run to finish enrolling the existing keyfile; otherwise remove it manually first). - Without
--generate: Validates thatDIR/braid.keyalready exists and is a regular file. - Scans pool membership for present LUKS disks. Absent or non-LUKS disks are skipped with a message. If a present disk’s live LUKS UUID does not match the UUID recorded in
pool.json– the disk was swapped, cloned, or reformatted – enrollment aborts before any passphrase prompt or slot change; detach the foreign disk and reattach the original, or runbraid replaceif the swap was intentional. - Verifies the passphrase against every present pool disk before any keyfile probe.
- Without
--generate: Probes the keyfile against each disk. If it authenticates, reports “already enrolled” and skips that disk for the rest of enrollment. A rejected probe means the disk still needs enrollment; any other probe failure (e.g. device busy) aborts immediately rather than treating the disk as un-enrolled. - For each disk still needing enrollment, checks LUKS slot 1: proceeds if free; refuses with an error if occupied by an unknown key (you must remove it first with
cryptsetup luksKillSlot). - With
--generate: Only after all preflight checks pass, generates the random keyfile. - Enrolls the keyfile into LUKS slot 1 on each disk.
- Creates a LUKS header backup for each modified disk.
See Pending LUKS header backups – copy each .luksheader off-system and delete the local copy.
Safety checks
- Refuses if a pending operation journal (
pending-op.json) exists – runbraid recoverto reconcile. - Refuses if another braid operation is in progress (pool lock
/run/braid-pool.lockis held) – retry once it finishes. - Refuses if a present disk’s live LUKS UUID no longer matches its
pool.jsonrecord – the disk was swapped, cloned, or reformatted; detach the foreign disk and reattach the original, or runbraid replaceif the swap was intentional. This UUID check is repeated at the mutation boundary, after the passphrase is read and before any keyfile is enrolled, so a disk swapped during the passphrase prompt is still caught before slot 1 is touched. - With
--generate, refuses unless the target directory is already a mount point. - Passphrase is verified before any mutations.
- Slot 1 conflicts are detected before the keyfile is generated, so you never end up with an orphan keyfile.
- With
--generate, refuses ifbraid.keyalready exists at the target path; if a prior--generaterun was interrupted, drop--generateand re-run to finish enrolling the existing keyfile. - Without
--generate, refuses if the keyfile doesn’t exist. - Idempotent: if the keyfile is already enrolled on a disk, that disk is skipped.
Related commands
- unlock – use
--key-fileto unlock with the enrolled keyfile