diff options
author | Ethel Morgan <eth@ethulhu.co.uk> | 2020-07-06 18:23:10 +0100 |
---|---|---|
committer | Ethel Morgan <eth@ethulhu.co.uk> | 2020-07-06 18:23:10 +0100 |
commit | b1e6491f77421ae4623391a7f53af7f3e6c13f34 (patch) | |
tree | acc4ce7ae214b92dbf2c269c70e94b68dac1d640 /src/systemd-dynamicuser.thrust | |
parent | 04be5845dbaa6f8dec45a80dbe199861608b96f2 (diff) |
import website from previous repo
Diffstat (limited to 'src/systemd-dynamicuser.thrust')
-rw-r--r-- | src/systemd-dynamicuser.thrust | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/src/systemd-dynamicuser.thrust b/src/systemd-dynamicuser.thrust new file mode 100644 index 0000000..758f3ce --- /dev/null +++ b/src/systemd-dynamicuser.thrust @@ -0,0 +1,161 @@ +--- +title: systemd Dynamic Users +date: 2020-04-09 +--- +{% extends 'templates/base.html' %} +{% block body %} + <nav> + <a href='/projects'>> projects</a> + </nav> + + <header> + <h1>{{ title }}</h1> + </header> + + <article> + {% markdown %} + The Linux init system [systemd](https://en.wikipedia.org/wiki/Systemd) has its controversies, but it also has some pretty neat features, my favorite of which is _Dynamic Users_. + Lennart Poettering's blog has a [full rundown of the ins and outs](http://0pointer.net/blog/dynamic-users-with-systemd.html), but I'll summarize the key points below, and document a few tricks. + + <details markdown='1'> + <summary>contents…</summary> + <div markdown='block'> + + [TOC] + + </div> + </details> + + ## Users and groups and Name Service Switch, oh my! + + On Linux, when you create a user it is usually added to `/etc/passwd`, and groups it is in are added to `/etc/groups`. + However, these databases and others can actually come from multiple sources, controlled by the [Name Service Switch](https://en.wikipedia.org/wiki/Name_Service_Switch), and on modern Linux one of those sources is systemd. + + When configured to, systemd will create a user for the lifetime of a Unit to run that Unit. + The user is never added to `/etc/passwd`, but exists only at runtime, and when the Unit finishes the user goes away. + Although they are very locked down by default, this user is a full Linux user, and can be added to groups, write to disk, or be given capabilities. + In particular, systemd provides a system for _State Directories_, which will be writable by the created user, persist after the Unit finishes, and will be fixed-up the next time the Unit runs to be writeable by the next dynamically created user, which can be used to store service data, or to simulate a home directory. + + ## Simple services + + A very useful result of Dynamic Users is to simplify the packaging and running of services. + Instead of having to create a user to run a service when it is installed and remove it later when the service is uninstalled, the service package only needs to install a service file as the user is created at runtime. + For example, below is the configuration for a web service of mine: + + ```sh + $ cat /lib/systemd/system/log.eth.moe + [Unit] + Description=Backend server for https://log.eth.moe + + [Service] + # Create a user at runtime. + # It will have a random name. + DynamicUser=yes + + # Set the user's primary group to www-data. + Group=www-data + + # Create a temporary runtime directory at /run/log-eth-moe/. + RuntimeDirectory=log-eth-moe + + # Create a persistent state directory at /var/lib/log-eth-moe/. + StateDirectory=log-eth-moe + + ExecStart=/usr/bin/log.eth.moe -socket /run/log-eth-moe/listen.sock -dir /var/lib/log-eth-moe/ + + [Install] + WantedBy=multi-user.target + ``` + + It's also generally useful any time you want a non-human user to run something. + For example, below is [my configuration](https://github.com/ethulhu/kodi-systemd-service/) for running the [Kodi media center](https://kodi.tv/) on a Raspberry Pi: + + ```sh + $ cat /lib/systemd/system/kodi.service + [Unit] + Description=Kodi Media Center + After=systemd-user-sessions.service network.target sound.target + + [Service] + # Create a user at runtime. + DynamicUser=yes + + # Call that user "kodi". + User=kodi + + # Add it to useful groups for a media center. + # Note that these are all supplementary groups, + # and the dynamic user has no primary group. + SupplementaryGroups=audio + SupplementaryGroups=input + SupplementaryGroups=plugdev + SupplementaryGroups=video + + # Create a persistent state directory at /var/lib/kodi. + StateDirectory=kodi + + # Set the home directory of the dynamic user to /var/lib/kodi. + Environment=HOME=/var/lib/kodi + + ExecStart=/usr/bin/kodi-standalone + + [Install] + WantedBy=multi-user.target + ``` + + ## Sandboxed Steam? + + [Steam](https://store.steampowered.com/) is great, but it also requires running other people's code, so it's best to sandbox it a little. + While [some people](https://blog.jessfraz.com/post/docker-containers-on-the-desktop/) might go to the lengths of [running Steam in Docker](http://blog.drwahl.me/steam-running-in-docker-lxc/), I use systemd to achieve similar ends. + + The steps of this approach are: + + - Create a group to share your display with. + For myself, `eth`, I created `eth-x11`. + - Allow members of that group to access your display. + - Run Steam as a member of that group, directed to use your display. + + ### Implementation + + After creating your group, grant that group permission to use your display, substituting `eth-x11` for your group: + + ```sh + $ xhost +si:localgroup:eth-x11 + ``` + + This will need to be done every X11 session, and should probably be added to your `.xinitrc` or `.xsession`. + + Then create a script to run Steam under `systemd-run`: + + - Run the command with a TTY so that Steam's log messages are output to your terminal for debugging. + - Create a user at runtime. + - Set the _primary_ group of the user to be `eth-x11`. + The `xhost` command above requires it to be the primary group. + - Add the user to the groups `audio`, `input`, and `video`. + - Create a `StateDirectory` called `steam`, which `systemd` will put at `/var/lib/steam/`. + - Set the `$DISPLAY` to be the current X11 display. + - Set the `$HOME` of the running process to `/var/lib/steam/`. + + ```sh + $ cat /usr/local/bin/steam + #!/bin/sh + + set -eux + + systemd-run \ + --pty \ + --property=DynamicUser=yes \ + --property=Group=eth-x11 \ + --property=SupplementaryGroups=audio \ + --property=SupplementaryGroups=input \ + --property=SupplementaryGroups=video \ + --property=StateDirectory=steam \ + --property=Environment=DISPLAY=${DISPLAY} \ + --property=Environment=HOME=/var/lib/steam \ + /usr/games/steam + ``` + + Unfortunately, to use `systemd-run` you must either be root or authenticate yourself to systemd, but the experience can be improved with `sudoers` or setuid on the script. + {% endmarkdown %} + </article> +{% endblock %} |