ZFS ZFS for encrypted home directory decrypted at login?

I'd like to set up a FreeBSD installation with only my home directory encrypted. I've fiddled with GELI, and I'd like the machine to be one I can reboot remotely, so typing a password in at boot is a non-starter.

I'm aware that it's possible to do an encrypted user directory that is automatically decrypted at login using PEFS and its PAM module (e.g., https://forums.freebsd.org/threads/pefs-encrypted-directory.67204/), and I think this would work for me in general, though I'm a little wary of the various failure modes with being able to write to the directory while it's still encrypted.

For that reason and general interest in using fewer subsystems simultaneously, I'm wondering if there's a way to do something similar using ZFS native encryption, since I'm intending use root-on-ZFS. I know ZFS can encrypt individual datasets (Klara Systems seems to have a nice tutorial on the basics), and it's clear that I could make my home directory live in such a dataset. But I haven't been able to find any information on doing decryption at login, only manually decrypting via entering the key or just having an encryption key in a file such that it gets decrypted as soon as the system is booted (and for that matter, leaving the key on an unencrypted dataset). Has anyone successfully done this before, or does anyone know where to start?
 
What you propose will be hard to achieve, because login(1) expect to be able to read the user's home directory.
You should look at other ways to achieve your goal. For example, a way to ssh to the machine after reboot, input the decryption key and then the encrypted filesystems on the machine wll be unlocked.
 
Hm, so presumably this is part of what the PEFS PAM module does, is decrypt the directory using the user password before any login files are read... now I'm wondering (as a side project, not for daily use) how much work it would be to adapt the PEFS PAM module to unlock a ZFS dataset... maybe I'll just use PEFS for now and experiment with that on the side
 
I'm aware that it's possible to do an encrypted user directory that is automatically decrypted at login using PEFS and its PAM module
...
I'm wondering if there's a way to do something similar using ZFS native encryption, since I'm intending use root-on-ZFS.

Check out Oracle Solaris Blog - User home directory encryption with ZFS and


In 13.+ is
Code:
 % ls -l /usr/lib/pam_zfs_key.so*
lrwxr-xr-x  1 root  wheel     16 Oct  2 04:46 /usr/lib/pam_zfs_key.so -> pam_zfs_key.so.6
-r--r--r--  1 root  wheel  17384 Oct  2 04:46 /usr/lib/pam_zfs_key.so.6

There might be some issues though, see the reviews description.
 
UPDATE

For testing follow

(Users pool home dataset edited)
Code:
Test Plan

/etc/pam.d/login:

auth           optional        pam_zfs_key.so homes=your-pool-name/usr/home
session        optional        pam_zfs_key.so homes=your-pool-name/usr/home

/etc/pam.d/passwd:

password    optional    pam_zfs_key.so homes=your-pool-name/usr/home

zfs create -o encryption=on -o keyformat=passphrase your-pool-name/usr/home/ztest
pw user add -n ztest -m
passwd ztest # set same as the passphrase given to zfs create
zfs unmount your-pool-name/usr/home/ztest && zfs unload-key your-pool-name/usr/home/ztest

Execute 'zfs unmount -u your-pool-name/usr/home/ztest' instead, it's shorter. (T-Daemon)

login # login as ztest, type password
mount # check that the home dir is mounted now

Working:
  • User logging in loads the encryption key, decrypts home directory.
  • Changing user password changes dataset password.

Not working:
  • When user logs out, the dataset remains decrypted, the encryption key must be unloaded manually: zfs unmount -u zroot/usr/home/<user> (or system poweroff/rebooted). This issue is mentioned in the reviews, see EBUSY
  • When user loges in, the password prompt presents itself twice.
  • When changing the user password, it must entered four times.
 
With the above configuration from post #5 a ssh remote login won't load the encryption key. The user will log in a empty directory. Looks like /etc/pam.d/sshd needs some setting, I'm not sure which.
 
Okay, status update:
  • Setup as outlined above worked without a hitch. I've verified root cannot see the contents of the directory at boot!
  • I haven't figured out how to get SSH working yet (slightly lower priority than other setup tasks and, you know, actual work)
  • Out of the box, slim doesn't work for graphical login; it's doesn't ask for a second password or pass the main password through to unlock the directory; instead login just fails (because my .xinitrc is on an encrypted unmounted volume). My current work-around for this is to quickly log in and out on the console, which leaves the volume mounted, then log in via slim.
  • This has interactions with the linuxulator subsystem. Typical setup (e.g., following https://www.micski.dk/2022/01/19/how-to-install-spotify-on-freebsd/) results in home directories being mounted under /home inside the linux filesystem. With this setup, the linux subsystem does not see the mounted user home directory, which means that linux binaries run through the linuxulator do not have access to my home directory! I haven't dug into this too much so far, but it appears the linux subsystem sees the default non-volume version of my home directory that root would see before I log in. Aside from being generally slightly weird, concretely this means I can't access any files using Linux software. For example, Spotify doesn't launch because it looks in /home/csgordon (under Linux) for a .Xauthority file and can't find one (because it's not seeing my mounted volume that contains the actual .Xauthority file). I suspect I just need to find some trick for mounting this properly and then everything will work. Restarting the linux service after I'm logged in doesn't fix this, so it's not quite trivial even if I'm optimistic there will be an easy fix.
 
Okay, I've figured out a solution to the linux compat quirk:
Code:
mount -t nullfs /usr/home/csgordon /compat/ubuntu/home/csgordon
(per https://infotoast.org/site/index.ph...nt-a-directory-to-another-location-linux-bsd/) mounts whatever appears in my *actual* (encrypted) homedirectory into the linux compat filesystem. This is at least enough that graphical Linux programs find my .Xauthority, and enough for me to run Linux installers in my actual home directory (e.g., installers for Linux software that installs to a hidden directory within your home directory)
 
Is there a solution to the ssh login meantime?
A direct ssh login, decrypting the users home dataset is not possible.

According to a PR comment, OpenSSH developers are to blame.

However, the problem can be overcome by creating a user1 on the host, with permissions (sudo, doas) to decrypt and mount user2's home dataset. To unlock and mount dataset from a remote client, first "ssh -t user1@host sudo|doas command argument", then "ssh user2@host.

Besides ssh, another flaw is the ZFS encrypted home datasets remains decrypted when the user logs out. The home dataset belonging to the logged out user cannot be unmounted and the key cannot be unloaded by the same user. This must be done by another user.

Speaking of which, the same comment from the PR contains a proper PAM configuration for console logins to unlock the encrypted user home dataset.

/etc/pam.d/system
Code:
auth       optional    pam_zfs_key.so    try_first_pass  homes=zroot/home
session    optional    pam_zfs_key.so    homes=zroot/home
 
Last edited:
Home encryption and automatic unlock on login is a very important feature for laptops.
Full encryption requires a password at boot, which is only tolerable for ever running servers, imho.
So Home encryption to the rescue. When you open the laptop a finger print or face scan should log you in and unlock the home directory.
 
A direct ssh login, decrypting the users home dataset is not possible.

According to a PR comment, OpenSSH developers are to blame.

However, the problem can be overcome by creating a user1 on the host, with permissions (sudo, doas) to decrypt and mount user2's home dataset. To unlock and mount dataset from a remote client, first "ssh -t user1@host sudo|doas command argument", then "ssh user2@host.

Besides ssh, another flaw is the ZFS encrypted home datasets remains decrypted when the user logs out. The home dataset belonging to the logged out user cannot be unmounted and the key cannot be unloaded by the same user. This must be done by another user.

Speaking of which, the same comment from the PR contains a proper PAM configuration for console logins to unlock the encrypted user home dataset.

/etc/pam.d/system
Code:
auth       optional    pam_zfs_key.so    try_first_pass  homes=zroot/home
session    optional    pam_zfs_key.so    homes=zroot/home
Gemini suggests this:
for /etc/pam.d/system
Code:
password    sufficient  pam_zfs_key.so homes=your-pool-name/usr/home
password    required    pam_unix.so

Reason (for Gemini) being:
In short, sufficient provides a better guarantee that the ZFS passphrase update is properly attempted and that its outcome is factored into the overall success of the password change, reducing the risk of a desynchronized password/passphrase.
 
Or is it possible to automate the reboot -r technique? i.e. after login to the outer installation the entered password should be used to unlock the inner Geli encryption?
For me this bug i.e. not unmounting on logoff is actually O.K. I can logout of my server and ZFS is still accessible to other processes running there.
If somebody steals my server, the power goes poof and with it the key in RAM.
On my desktop I just reboot before I let my granny use it. Or turn it off for the sake of my electricity bill.
 
O.K. I did some testing.
On my FreeBSD 14.3-RELEASE-p1
it looks like this:


/etc.pam.d/system

Code:
auth    required    pam_unix.so        no_warn try_first_pass    nullok
auth    optional    pam_zfs_key.so            try_first_pass  homes=zroot/home

session    optional    pam_zfs_key.so    homes=zroot/home

Probably not a good idea to add pam_zfs_key.so to

/etc/pam.d/passwd
for reasons below (broken passwd)

Code:
password    optional    pam_zfs_key.so homes=zroot/home
password    required    pam_unix.so    no_warn try_first_pass nullok

This works fine with adduser and on login (lightdm-gtk-greeter works too).
On login it asks for password once and logs you in, mounting home properly.

passwd actually works as intended. Only difference is that when you change password for your_user as root, it will first ask for Old Passphrase. Which you can ignore (Enter) if the user does not have Encrypted ZFS dataset. If your_user does have Encrypted home, your_user will need to change his zfs key passphrase later on to match his login password.

For ssh to work you need:

/usr/local/etc/doas.conf

Code:
permit nopass your_user as root cmd zfs args mount -l zroot/home/your_user

And to mount home after ssh login:
Code:
doas zfs mount -l zroot/home/your_user

Problem is when you want to change password under user, since his home is mounted therefore cannot change zfs_key and passwd under root pam would (try to) set zfs_key for root home instead.
And there is an issue with the pam_zfs_key.so module's behavior in the password stack. For some reason, it is causing the passwd command to prompt for the old password even when run by root, which is not its intended function (it should prompt for New Password straight away for root).

Therefore I suggest omitting changes in
/etc/pam.d/passwd and running this sequence for changing user's password:
Code:
logout your_user
login as root
zfs unmount zroot/home/your_user
passwd your_user
zfs change-key -o keyformat=passphrase zroot/home/your_user
login your_user
 
For some reason, it is causing the passwd command to prompt for the old password even when run by root, which is not its intended function (it should prompt for New Password straight away for root).
It is actually very good reason....root can't simply read your encrypted files.
 
Back
Top