I’ve been toying around with disk encryption with Silverblue, and to be honest, if you only care about encrypting the home directory with the same passphrase as your login password, using crypttab to auto-mount the encrypted partition at boot is a little annoying because you need to type the password twice. The other solution is using pam_mount, but because some user services still runs a few seconds after logout, pam_mount will never unmount your encrypted partition on logout. Facing this weird issue, I come up with a workaround so I can still use pam_mount while ensuring the encrypted home directory will always be unmounted after user logout.

Setting Up pam_mount

The Dreaded XML

To setup pam_mount to mount the encrypted home directory at user login, we need to create a pam_mount.conf.xml in /etc/security. I use LUKS-encrypted partition as my home directory, so the relevant config will look like:

<volume
  user="ramot"
  fstype="auto"
  path="/dev/disk/by-uuid/<LUKS_PARTITION_UUID>"
  mountpoint="/var/home"
  options="crypto_name=homedir,allow_discard,defaults,noatime"
/>

<mkmountpoint enable="0" />

If you want to mount multiple BTRFS subvolumes, the config will be a little bit different1. An example of two subvolumes mount looks like:

<volume
  user="ramot"
  fstype="auto"
  path="/dev/disk/by-uuid/<LUKS_PARTITION_UUID>"
  mountpoint="/var/home"
  options="crypto_name=homedir,allow_discard,defaults,noatime,subvol=<HOME_SUBVOL>"
/>

<volume
  user="ramot"
  path="/dev/disk/by-uuid/<OTHER_SUBVOL_PARTITION_UUID>"
  mountpoint="/var/other"
  options="allow_discard,defaults,noatime,subvol=<OTHER_SUBVOL>"
/>

<mkmountpoint enable="0" />

Notice that I disable mkmountpoint directive, because I use SELINUX and I need to ensure that the /var/home directory will always have the correct SELINUX security context. I also set the option crypto_name to homedir since this will help us later in deciding the mapper name for the encrypted partition. You can also enable relatime if you need Linux atime that much.

The PAM Directives

We will set the PAM directives for specifically GDM logins, I don’t care about SSH & shell logins since I only SSH to my machine if my user is already logged in and I rarely use shell login. We will start with the directives for GDM login with password (fingerprint login is a little complicated, we’ll get back to this later), fire up your favorite editor and edit /etc/pam.d/gdm-password to looks like this:

auth     [success=done ignore=ignore default=bad] pam_selinux_permit.so
auth        substack      password-auth
auth        optional      pam_mount.so
auth        optional      pam_gnome_keyring.so
auth        include       postlogin

account     required      pam_nologin.so
account     include       password-auth

password    substack       password-auth
-password   optional       pam_gnome_keyring.so use_authtok

session     required      pam_selinux.so close
session     required      pam_loginuid.so
session     required      pam_selinux.so open
session     optional      pam_keyinit.so force revoke
session     required      pam_namespace.so
session     include       password-auth
session     optional      pam_mount.so
session     optional      pam_gnome_keyring.so auto_start
session     include       postlogin

We need to add pam_mount.so on auth & session module interface, just like in the documentation2. We place it after password-auth directive to enable pam_mountto get the passphrase from the password field in GDM login (since we only want to type the passphrase once).

The Post-logout systemd Hook

Now we need to override a systemd service to make sure the encrypted partition is unmounted after user logout. We start by creating a shell script to check the mountpoints and unmount them, we also need to lock the LUKS encrypted partition after we successfully unmount all the mountpoints. The shell script to do this will looks like this:

#!/bin/bash

HOMEDIR="/var/home"

# Try to unmount...
while /usr/bin/mountpoint -q $HOMEDIR
do
    /usr/bin/umount $HOMEDIR
    /usr/bin/mountpoint -q $HOMEDIR && sleep 5
done

# Notice that we set the crypto_name to 'homedir' on pam_mount.conf.xml 
/usr/sbin/cryptsetup close homedir

# In case the encrypted partition is already closed/locked, always return 0
# https://man.archlinux.org/man/cryptsetup.8.en#RETURN_CODES
if [ $? -eq 4 ]
then
    exit 0
fi

You will need to modify the script a little bit if you mount several subvolumes/partitions with pam_mount. For me, this script is sufficient. Save the script as /usr/local/bin/unmount-homedir and run this command to start editing the systemd service to call the script after successful user logout (assuming your UID is 1000):

sudo systemctl edit user-runtime-dir@1000.service

Then you need to add this directive:

[Service]
ExecStop=/usr/local/bin/unmount-homedir

This will tell user-runtime-dir@1000.service to run /usr/local/bin/unmount-homedir after your user has been logged out. Or you can create /etc/systemd/system/user-runtime-dir@1000.service.d/override.conf with the content as above.

Et voilà! Now everything is set up accordingly.

Bonus: Enable Fingerprint Authentication on Everything Except Login

I told you before that

fingerprint login is a little complicated

and we’ll get back to this. Well, the problem with fingerprint login is the PAM stack won’t be getting the passphrase for the encrypted partition, causing pam_mount to not able to mount the encrypted partition at all. Theoretically, we can work through this by disabling fingerprint login usinf dconf directives, but Fedora is not helping by locking down the /org/gnome/login-screen/enable-fingerprint-authentication key. To solve this, we will need to create our custom authselect profile to unlock this directive, and then set GDM to disable fingerprint on login.

Creating Custom authselect Profile

Run this command to create the custom profile (you can name it everything) with sssd as base:

sudo authselect create-profile sssd-disable-fp-on-login -b sssd --symlink-meta --symlink-nsswitch --symlink-pam

The --symlink-meta, --symlink-nsswitch and --symlink-pam is needed because we only care about dconf locks and not the entire PAM stack and nsswitch.

Removing dconf Locks

Fire up your favorite editor again and edit /etc/authselect/custom/sssd-disable-fp-on-login/dconf-locks. The file will look like this:

/org/gnome/login-screen/enable-smartcard-authentication
/org/gnome/login-screen/enable-fingerprint-authentication
/org/gnome/login-screen/enable-password-authentication
/org/gnome/settings-daemon/peripherals/smartcard/removal-action {include if "with-smartcard-lock-on-removal"}

Now we only need to remove the line containing enable-fingerprint-authentication. Make sure the content of the file is the same as this snippet:

/org/gnome/login-screen/enable-smartcard-authentication
/org/gnome/login-screen/enable-password-authentication
/org/gnome/settings-daemon/peripherals/smartcard/removal-action {include if "with-smartcard-lock-on-removal"}

Adding dconf Directive to Disable Fingerprint Login

Now we need to override dconf configuration for GDM login. Edit /etc/dconf/db/gdm.d/99-fingerprint-no-login to create custom configuration for dconf. The file content should be like this:

[org/gnome/login-screen]
enable-fingerprint-authentication=false

Save the file and then run this command:

sudo dconf update

Now fingerprint will be disabled on GDM login, but enabled elsewhere.