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 😜️