Shavee
Shavee is a program to automatically decrypt and mount ZFS datasets using Yubikey HMAC as 2FA or any File on USB/SFTP/HTTPS drive, with support for PAM to auto mount home directories on login.
Supported Methods
1. Yubikey
Yubikeys are secure authentication USB devices we can use as a strong second factor. Yubikeys come pre-programmed with a HMAC key on Slot 2 which can be used to derive the final encryption key along with your password.
Important: The programmed HMAC secret in the Yubikey CANNOT be extracted once programmed in. If you want to use multiple keys on the same dataset (e.g. backup keys), you must program the same fresh HMAC secrets on all those keys.
Yubikey mode is set with the -y flag. In this mode the program looks for a Yubikey on login and uses its HMAC mode along with your password to derive the final encryption key. The Yubikey HMAC Slot can be set with the -s flag (defaults to Slot 2).
2. File / HTTP(S) / SFTP
In this mode the program looks for a file (any file) and uses it along with your password to derive the final encryption key. File mode is set using the -f <path> option. The file can be local, HTTPS, or SFTP:
# HTTPS
shavee -f https://foo.org/secret.png
# SFTP (custom port)
shavee -f sftp://user@foo.org/mnt/secretfile -P 4242
# Local file (e.g. USB drive)
shavee -f /mnt/usb/secret.png
The -P option sets the port for both HTTP and SFTP. The idea is to keep the file on a USB storage device or a network location you control, present during login to derive the final encryption key. You can use any pre-existing file, or create one:
dd if=/dev/urandom of=./secretfile bs=4096 count=4096
Note: Since the file becomes part of your encryption key and its security cannot be guaranteed as with a Yubikey, you are responsible for keeping it secure.
3. Password Only
If no second factor is specified, the program uses only the password as a single factor.
Build and Install
- Install Rust
- Clone the repo:
git clone https://github.com/ashuio/shavee.git
cd shavee
- Build:
cargo build --release
- Install the binary:
sudo cp target/release/shavee /usr/bin
- Install the PAM module:
sudo cp target/release/libshavee_pam.so /usr/lib/security/
Modes
- Shavee PAM Module — Unlocks home directory on login
- Shavee Binary — Admin function for dataset management
Flags / Options
| Flag | Description |
|---|---|
-y | Use Yubikey for 2FA |
-f | Use any file as 2FA (takes filepath, HTTP(S), or SFTP location) |
-P | Set port for HTTP and SFTP requests (uppercase P) |
-s | Set Yubikey HMAC Slot (1 or 2) |
-c | Create/Change key of ZFS dataset with derived encryption key |
-z | Unlock and mount the given dataset with the derived key (takes ZFS dataset path; auto-appends username in PAM mode) |
The -y (Yubikey mode) and -f (File mode) flags are interchangeable. It is recommended to re-run the key change command for your datasets after version updates.
Configure ZFS Datasets
If using with PAM: your dataset password should be the same as your user account password for it to work automatically. Remember to update your encryption key if you update your password.
Change/Update encryption key
Encryption must already be enabled and the key loaded to change the key of an existing dataset:
shavee -c <zfs dataset path>
# e.g. shavee -y -c zroot/data/home/hunter
Create a new dataset
sudo shavee -c <Desired dataset>
# e.g. sudo shavee -f /mnt/usb/secretfile -c zroot/data/home/hunter
Unlock and mount any ZFS partition
shavee -y -z zroot/data/home/hunter/secrets
Use in Scripts
Pipe the password directly into shavee:
echo "hunter2" | shavee -y -z zroot/data/home/hunter/secrets
Use a USB Drive for Second Factor
Use the -f option to substitute a Yubikey with any USB drive. To auto-mount the USB at boot so shavee can find the required keyfile on login, use udev. Create /etc/udev/rules.d/99-usb-automount.rules:
ACTION=="add", SUBSYSTEMS=="usb", SUBSYSTEM=="block", ENV{ID_FS_UUID}=="<UUID of partition>", RUN{program}+="/usr/bin/systemd-mount --no-block --automount=yes --collect $devnode <Desired Mount point>"
Example:
ACTION=="add", SUBSYSTEMS=="usb", SUBSYSTEM=="block", ENV{ID_FS_UUID}=="ADB0-DA9C", RUN{program}+="/usr/bin/systemd-mount --no-block --automount=yes --collect $devnode /media/usb"
Get the UUID with:
udevadm info --query=all --name=<Target disk> | grep ID_FS_UUID=
# e.g. udevadm info --query=all --name=/dev/sdb1 | grep ID_FS_UUID=
Reload udev rules:
udevadm control --reload-rules
PAM Auto-Unlock Encrypted Home on Login
Shavee comes with a PAM module to execute during the login process. Add the following line to your desired PAM login method file (e.g. /etc/pam.d/sddm for graphical logins, /etc/pam.d/login for CLI logins):
auth optional libshavee_pam.so -y -z <base home dir>
Example:
auth optional libshavee_pam.so -y -z zroot/data/home
Where zroot/data/home mounts to /home.
Dual Home Directories in ZFS
Since ZFS mounts datasets over pre-existing directories and we defined our module in PAM as optional, we still get authenticated with just the password even if the dataset is NOT decrypted (e.g. because the Yubikey was not inserted).
We can use this to essentially have two home directories:
- First — Your normal encrypted home directory, unlocked and mounted when your Yubikey is present at login.
- Second — A fallback directory already present, loaded on decryption failure (i.e. when no Yubikey is inserted during login).
Let me know if interested — I could write up a more detailed guide.