summaryrefslogtreecommitdiff
path: root/src/systemd-dynamicuser.thrust
diff options
context:
space:
mode:
authorEthel Morgan <eth@ethulhu.co.uk>2020-07-06 18:23:10 +0100
committerEthel Morgan <eth@ethulhu.co.uk>2020-07-06 18:23:10 +0100
commitb1e6491f77421ae4623391a7f53af7f3e6c13f34 (patch)
treeacc4ce7ae214b92dbf2c269c70e94b68dac1d640 /src/systemd-dynamicuser.thrust
parent04be5845dbaa6f8dec45a80dbe199861608b96f2 (diff)
import website from previous repo
Diffstat (limited to 'src/systemd-dynamicuser.thrust')
-rw-r--r--src/systemd-dynamicuser.thrust161
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'>&gt; 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 %}