Running LMS as a secure, rootless podman container, managed by systemd #108
ipilcher
started this conversation in
Show and tell
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I've been working on running LMS as a rootless podman container, managed by systemd, with as many hardening options as possible turned on. I thought that I'd share what I've come up with.
Obviously, some of this is specific to my system, but it should be readily adaptable. Hopefully this is of some use to someone.
Notes
The cool way to run a systemd-managed podman container is to use a Quadlet. However, Quadlets do not support setting
User=orGroup=in the[Service]section. Instead, one is expected to run the Quadlet as a user service, managed by a systemd user instance. This works OK for normal users, but it would be an administrative nightmare when the user is a service account with their shell set to/bin/nologin.Thus, I just use a "normal" service that runs podman.
Despite this, rootless podman requires that the user session exist. Thus, the references to
user@992.servicein the[Unit]section. (992 is the UID of thepodman-lmsuser.)ExecStartPre=/usr/bin/podman system migratecauses podman to re-read/etc/subuidand/etc/subgid. I use very specific mapped UIDs and GIDs (rather than just blindly assigning 65537 of them to each service account), so if/when I need to map an additional UID/GID, I need podman to pick up the expanded ranges from those files.The
--volumeoptions should be relatively self-explanatory. Note that I am using priviate SELinux contexts (Z) for the/configand/playlistdirectories, and I've told podman to not touch the the SELinux context of the/musicdirectory. On my host,/srv/media/mp3is labeled aspublic_content_t, and I've set thecontainer_read_public_contentSELinux boolean. (See Allow containers to access shared public content containers/container-selinux#422.)--tmpfs /tmp:rw,size=64k,mode=1777is required, because I usefuse-overlayfs. (More on that below.)/lms/gdresize.plcontains code to remove this socket (if it didn't get cleaned up properly) before it creates it, but it seems thatfuse-overlayfsdoesn't handle this correctly, sogdresize.plfails withUnable to open socket: Address already in use at /lms/gdresized.pl line 109.Putting
/tmpontmpfssolves the issue.The
ExecStopPost=...line is needed, because systemd (running asinit_tdoesn't have permission to removecontainer_runtime_tmpfs_tfiles, so it will fail to clean up podman's lock file.RestrictSUIDSGID=yeswas a real challenge to get working. It prevents the systemd service from creating files with the SUID or SGID bits set. The Debian base image, upon which the LMS image is based, contains a number of files with these bits set. With the systemd option set, podman can't even pull the LMS image. (Even if the LMS image were to remove these bits, the layered nature of container images means that podman still couldn't pull it.)I solve this by using the
force_maskandmount_programoptions in my storage configuration (~/.config/containers/storage.conf) to usefuse-overlayfsrather than the kernel's built-in overlay support.When this option is set, the metadata of files within image layers are not set directly in the host filesystem. Instead, default ownership and permissions are used, and the metadata from the image layer is stored in the extended attributes of the file. For example, the
/usr/bin/chagefile within the LMS container looks like this.But from the host, it looks like this.
The kernel overlay file system does not have the capability of using extended attributes to store this metadata. Thus the user-space (FUSE) overlay filesystem is a requirement for the
force_maskstorage option.Beta Was this translation helpful? Give feedback.
All reactions