What if there was a way to manage users with a self-contained, encrypted image that can only be accessed by the user? Enter systemd-home

/etc/password not good enough for you anymore?

There is several benefits systemd-homed offers:

  • Users and their data live in one self-contained image
  • Integrity of the data is not optional
  • Storage and encryption mechanism are well-defined
  • Your home is mounted for the lifetime of your session
  • The whole image can be moved between devices

Before you say, who cares about portability of your home, fair enough. I consider this an ambiguous design goal which many users may not need. At the same time decoupling users from the system makes everything more resilient. That is my view on it anyway.

A note on security modules

Please don’t take the following as advice or any kind of opinion. Apparently the packaged systemd-homed was not compatible with SELinux on Fedora 38 at the time I was testing it. I can’t make the time to look into it so I switched to permissive mode on my system. In case you are following this blog and the following sections raise errors in the setup steps you may need to do the same or conduct more research to find another solution.

sudo setenforce Permissive
sudo sed -i 's@SELINUX=enforcing@SELINUX=permissive@' /etc/selinux/config

Setup a user homed style

Creating a user via homed is straightforward. Since falling back to non-encrypted storage I choose to specify explicitly that I need btrfs and luks. I’m also using wheel here for my primary user:

sudo homectl create rumo --storage=luks --fs-type=btrfs --luks-extra-mount-options=defcontext=system_u:object_r:user_home_dir_t:s0 -G wheel

Incidentally rumo is the username I use here based on a jackalope character in the world of Zamonia. Be sure to use the name of your choice.

Note: If you want multiple groups use , to separate them.

The image will live in a .home file by default

homectl inspect rumo

What’s nice here is you can see any updates immediately in contrasts to e.g. groups which reflects differences only after logging out all sessions.

Once you are ready to try this new user you can go back to your display manager. Your login screen may not immediately show a new option. In this case Not listed is your friend. Next time the user will also appear in the list.

Migration

This is optional. In case you have a user not managed by systemd with data you want to keep.

sudo rsync --remove-source-files --links --recursive --specials --mkpath /home/olduser .
sudo userdel -r olduser

Consider that this is only safe to do if the filesystem was already encrypted. Otherwise starting from scratch is the better option.

Who am I really?

I mentioned this before. The image has integrity. How so? Check out the file ~/identity:. Go ahead and peek at the JSON with a text editor. Be sure never to edit this file however! This file is signed, and modifying it could get you locked out of your home. Which is good in the sense that nobody should be able to modify your user, privileged admins included.

id
uid=60280(rumo) gid=60280(rumo) groups=60280(rumo),10(wheel) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

As you further become familiar with your new user you will mostly find things just work. However your id is now in a different range. Rather than 1000 and above it is 60000 and above. Not something you should care much about. If you hard-coded the id anywhere now is the time to change it, though.

One more thing you may want to do is enable rootless containers:

# take advantage of the "container range" provided by systemd-homed
sudo usermod --add-subuids 524288-1878523903 --add-subgids 524288-1878523903 $USER
grep $USER /etc/sub{u,g}id
podman system migrate

The range we are choosing here is a particular range reserved for containers by systemd. Anything else at the time of this writing will cause permissions to break and tools within containers to misbehave (Value too large for defined datatype and changing ownership of [...] invalid argument errors from chown).

Remote unlocking

If you want to be able to unlock your user remotely you probably want to extend your /etc/ssh/sshd_config in the following way:

PasswordAuthentication yes
PubkeyAuthentication yes
AuthenticationMethods publickey,password
AuthorizedKeysCommand /usr/bin/userdbctl ssh-authorized-keys %u
AuthorizedKeysCommandUser root

Also be sure to add your SSH key:

homectl update rumo --ssh-authorized-keys=@/home/rumo/.ssh/authorized_keys

Currently you always need to type your user’s password. There is no avoiding it once to be able to decrypt your home. It would be nice if getting into already active sessions worked without the password, though.

Physical access keys

homectl create rumo --storage=fscrypt --fido2-device=auto --fido2-with-client-pin=yes --fido2-with-user-presence=no --recovery-key=yes

This enables a FIDO key as well as a recovery key. Not asking for the presence of the user means touch to unlock is good enough. Also homectl still requires a password in case the key is not available (anymore). Considering that this is usually annoying to setup I am thrilled this is part of the homed spec.

What happened to my admin privileges?

Somehow my system no longer thinks my user is an admin despite being in wheel which prevents elevating privileges in graphical apps. sudo works just fine.

So I came up with this approach, which instead makes mounting a free action. The group is an extra one so users can get it without having other privileges.

    sudo homectl update rumo -G disk,wheel
    cat <<EOF | sudo tee /var/lib/polkit-1/localauthority/50-local.d/77-users-can-mount.pkla > /dev/null
[Mount and manage drives]
Identity=unix-group:admin;unix-group:disk
Action=org.freedesktop.udisks.filesystem-*;org.freedesktop.udisks.drive-ata-smart*;org.freedesktop.udisks2.filesystem-mount-system;org.freedesktop.udisks2.encrypted-unlock-system;org.freedesktop.udisks2.filesystem-fstab;
ResultActive=yes
EOF

Where to go from here?

Enjoy your new home 😜️