2

Question

How do I run an arbitrary service as an arbitrary user at boot with a logind session (specifically including all of the goodies under /run/user/uid) created for this user and without having to explicitly log in as this user?

Background

I am in the process of converting a docker-compose deployment for use with rootless podman + systemd services. I have figured out most of the podman stuff but am specifically struggling with getting it to run via systemd.

In my previous deployment I had created a user account for each service and configured the containers to run as this user. This was very handy from a filesystem control and maintenance standpoint and is really the primary property I wish to preserve.

To that end, I found this askubuntu question which gets me the ability to embed the user directly into my systemd job and have it execute as said user. Perfect.

Now comes the wrench: Fedora moved to cgroups v2 which is now handled by systemd and is, in fact, the reason for this effort in the first place. As a result, podman requires the ability to talk to systemd which, in turn, basically requires the login session set up by logind (if I am understanding this link correctly). I am no systemd expert so please correct me on any of this.

I did find another question about waiting for a user session which comes close to what I am after but seems to indicate this isn't possible. My case is different in two primary respects:

  • I do not want to wait for any session (eg. this should run on boot with no interaction).
  • My solution needs to be robust enough to suffer manual intervention bringing the service up and down.

So, as stated above, I am really looking for any way to get a systemd service to run as a particular user with enough of a login environment for the service application to connect to systemd (or, at least, the cgroups v2 portion of it).

Finally, below is a sample systemd unit file for one of the services which works as expected until it needs to connect to systemd. Additionally, the podman invocation works completely when executed manually as my logged in user.

[Unit]
Description=Emby Podman Container

[Service]
User=emby
Group=emby
Restart=on-failure
ExecStartPre=/usr/bin/rm -f /%t/%n-pid /home/emby/%n-cid
ExecStart=/usr/bin/podman run --conmon-pidfile /%t/%n-pid --cidfile /home/emby/%n-cid -d --name=emby --cgroup-manager=systemd -e TZ="$TZ" -p 8096:8096 -p 8920:8920 -v /opt/docker/storage/emby:/config -v /media/media/:/media emby/embyserver
ExecStop=/usr/bin/sh -c "/usr/bin/podman rm -f `cat /home/emby/%n-cid`"
KillMode=none
Type=forking
PIDFile=/%t/%n-pid

[Install]
WantedBy=multi-user.target

1 Answer 1

3

So, after a lot of head scratching I was able to get a workable solution to this which turned out to be simpler, if less than elegant, than I thought. Let's cut to the chase and look at the functional unit file:

[Unit]
Description=Emby Podman Container
[email protected]
[email protected]

[Service]
User=emby
Group=media
Restart=on-failure
ExecStartPre=/usr/bin/rm -f /home/emby/%n-pid /home/emby/%n-cid
ExecStartPre=-/usr/bin/podman rm emby
ExecStart=/usr/bin/podman run --conmon-pidfile /home/emby/%n-pid --cidfile /home/emby/%n-cid \
          --name=emby --rm --cgroup-manager=systemd \
          -e TZ="$TZ" \
          -p 8096:8096 -p 8920:8920 \
          -v /opt/docker/storage/emby:/config \
          -v /media/media/:/media \
          emby/embyserver
ExecStop=/usr/bin/sh -c "/usr/bin/podman rm -f `cat /home/emby/%n-cid`"
KillMode=none
Type=forking
PIDFile=/home/emby/%n-pid

[Install]
WantedBy=multi-user.target

The key insight here is to let systemd manage the user session itself (not that it will let you do anything else). The use of BindsTo and After are essential in this configuration as they will force the user session for the emby user to be fully created before the emby service is actually started. Additionally, this makes it so that the administrator (read: me) won't have to log into every user to enable the session which should help as more services and users are added.

Some other useful notes about the setup:

  • The -d flag has been removed from podman so that stdout can be viewed via journalctl -fu emby _TRANSPORT=stdout. Handy for testing and verification.
  • Per the [email protected] man page, the user service must be instantiated with the UID and not the name (on my system emby == 1012). I haven't found a way to do expansions in any of the non-Exec commands so, for now, this is hardcoded. If anybody knows how to clean this up I would love to hear it.
  • The PID file has been moved into the user's home directory as /run is not word writable (good, thing, too).

Some other approaches I tried which didn't work:

  • Starting the user service directly in ExecPre. This unit runs as the user so it can't start systmd for that user (chicken, meet egg).
  • Automatically logging the user in. Note: this probably could work but there are security implications to a fully logged in user.
  • Changing users via su. The systemd maintainer takes a pretty dim view of su and refuses to fix it. Religious arguments aside, su plain doesn't work.

Additional References:


EDIT:

Of course, as soon as I post this I manage to find the magic search string which leads me to an article that obviates my approach.

In the interest of brevity, the salient points from the article above involve running the service as root and using --uidmap/--gidmap to map the container's root user to the desired system user.

This solution is, however, podman specific so I will leave the above in place for anyone else whose non-root, non-podman processes need access to systemd.

Finally, I think my solution is a hair more secure as, if an attacker compromises the container runtime, the scope is still limited to my unprivileged user. Though, this might be offset by the increased attack surface of another user service running so, perhaps, it is a wash.

2
  • Nice solution. It's a pity that there isn't a simple flag to tell systemd to start a user session as well; for some containers you could even combine this with DynamicUser and not have to worry about a user id at all. Jun 9, 2022 at 5:51
  • Did you try enabling lingering for the user so that systemd starts a session on boot? freedesktop.org/software/systemd/man/… Jun 9, 2022 at 5:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .