From 4b1f7bcb9a8cdf5884ec3b680601f63f4f6892e3 Mon Sep 17 00:00:00 2001 From: Evan Miller Date: Tue, 1 Jul 2025 22:11:16 -0700 Subject: [PATCH] Quadlet - Error when units define User, Group, or DynamicUser in Service group Fixes: #26543 Signed-off-by: Evan Miller --- docs/source/markdown/podman-systemd.unit.5.md | 6 ++++++ pkg/systemd/quadlet/quadlet.go | 11 +++++++++++ test/e2e/quadlet/service-dynamicuser.build | 4 ++++ test/e2e/quadlet/service-dynamicuser.container | 4 ++++ test/e2e/quadlet/service-dynamicuser.image | 4 ++++ test/e2e/quadlet/service-dynamicuser.kube | 4 ++++ test/e2e/quadlet/service-dynamicuser.network | 4 ++++ test/e2e/quadlet/service-dynamicuser.pod | 4 ++++ test/e2e/quadlet/service-dynamicuser.volume | 4 ++++ test/e2e/quadlet/service-group.container | 9 +++++++++ test/e2e/quadlet/service-user.container | 9 +++++++++ test/e2e/quadlet_test.go | 10 ++++++++++ 12 files changed, 73 insertions(+) create mode 100644 test/e2e/quadlet/service-dynamicuser.build create mode 100644 test/e2e/quadlet/service-dynamicuser.container create mode 100644 test/e2e/quadlet/service-dynamicuser.image create mode 100644 test/e2e/quadlet/service-dynamicuser.kube create mode 100644 test/e2e/quadlet/service-dynamicuser.network create mode 100644 test/e2e/quadlet/service-dynamicuser.pod create mode 100644 test/e2e/quadlet/service-dynamicuser.volume create mode 100644 test/e2e/quadlet/service-group.container create mode 100644 test/e2e/quadlet/service-user.container diff --git a/docs/source/markdown/podman-systemd.unit.5.md b/docs/source/markdown/podman-systemd.unit.5.md index 4b39835c0b..3df966740c 100644 --- a/docs/source/markdown/podman-systemd.unit.5.md +++ b/docs/source/markdown/podman-systemd.unit.5.md @@ -78,6 +78,12 @@ session gets started. For unit files placed in subdirectories within /etc/containers/systemd/user/${UID}/ and the other user unit search paths, Quadlet will recursively search and run the unit files present in these subdirectories. +Note that Quadlet units do not support running as a non-root user by defining the +[User, Group](https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#User=), +or [DynamicUser](https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#DynamicUser=) +systemd options. If you want to run a rootless Quadlet, you will need to create the user +and add the unit file to one of the above rootless unit search paths. + Note: When a Quadlet is starting, Podman often pulls or builds one more container images which may take a considerable amount of time. Systemd defaults service start time to 90 seconds, or fails the service. Pre-pulling the image or extending the systemd timeout time for the service using the *TimeoutStartSec* Service option can fix the problem. diff --git a/pkg/systemd/quadlet/quadlet.go b/pkg/systemd/quadlet/quadlet.go index 559a40d614..549c07e69e 100644 --- a/pkg/systemd/quadlet/quadlet.go +++ b/pkg/systemd/quadlet/quadlet.go @@ -186,6 +186,9 @@ const ( KeyYaml = "Yaml" ) +// Unsupported keys in the Service group. Defined here so we can error when they are found +var UnsupportedServiceKeys = [...]string{"User", "Group", "DynamicUser"} + type UnitInfo struct { // The name of the generated systemd service unit ServiceName string @@ -2245,6 +2248,14 @@ func initServiceUnitFile(quadletUnitFile *parser.UnitFile, isUser bool, unitsInf return nil, nil, err } + // These Service keys cannot be used in a Quadlet unit + for _, key := range UnsupportedServiceKeys { + _, hasKey := quadletUnitFile.Lookup(ServiceGroup, key) + if hasKey { + return nil, nil, fmt.Errorf("using key %s in the Service group is not supported", key) + } + } + service := quadletUnitFile.Dup() service.Filename = unitInfo.ServiceFileName() diff --git a/test/e2e/quadlet/service-dynamicuser.build b/test/e2e/quadlet/service-dynamicuser.build new file mode 100644 index 0000000000..68029df5ad --- /dev/null +++ b/test/e2e/quadlet/service-dynamicuser.build @@ -0,0 +1,4 @@ +## assert-failed +## assert-stderr-contains "using key DynamicUser in the Service group is not supported" +[Service] +DynamicUser=foobar diff --git a/test/e2e/quadlet/service-dynamicuser.container b/test/e2e/quadlet/service-dynamicuser.container new file mode 100644 index 0000000000..68029df5ad --- /dev/null +++ b/test/e2e/quadlet/service-dynamicuser.container @@ -0,0 +1,4 @@ +## assert-failed +## assert-stderr-contains "using key DynamicUser in the Service group is not supported" +[Service] +DynamicUser=foobar diff --git a/test/e2e/quadlet/service-dynamicuser.image b/test/e2e/quadlet/service-dynamicuser.image new file mode 100644 index 0000000000..68029df5ad --- /dev/null +++ b/test/e2e/quadlet/service-dynamicuser.image @@ -0,0 +1,4 @@ +## assert-failed +## assert-stderr-contains "using key DynamicUser in the Service group is not supported" +[Service] +DynamicUser=foobar diff --git a/test/e2e/quadlet/service-dynamicuser.kube b/test/e2e/quadlet/service-dynamicuser.kube new file mode 100644 index 0000000000..68029df5ad --- /dev/null +++ b/test/e2e/quadlet/service-dynamicuser.kube @@ -0,0 +1,4 @@ +## assert-failed +## assert-stderr-contains "using key DynamicUser in the Service group is not supported" +[Service] +DynamicUser=foobar diff --git a/test/e2e/quadlet/service-dynamicuser.network b/test/e2e/quadlet/service-dynamicuser.network new file mode 100644 index 0000000000..68029df5ad --- /dev/null +++ b/test/e2e/quadlet/service-dynamicuser.network @@ -0,0 +1,4 @@ +## assert-failed +## assert-stderr-contains "using key DynamicUser in the Service group is not supported" +[Service] +DynamicUser=foobar diff --git a/test/e2e/quadlet/service-dynamicuser.pod b/test/e2e/quadlet/service-dynamicuser.pod new file mode 100644 index 0000000000..68029df5ad --- /dev/null +++ b/test/e2e/quadlet/service-dynamicuser.pod @@ -0,0 +1,4 @@ +## assert-failed +## assert-stderr-contains "using key DynamicUser in the Service group is not supported" +[Service] +DynamicUser=foobar diff --git a/test/e2e/quadlet/service-dynamicuser.volume b/test/e2e/quadlet/service-dynamicuser.volume new file mode 100644 index 0000000000..68029df5ad --- /dev/null +++ b/test/e2e/quadlet/service-dynamicuser.volume @@ -0,0 +1,4 @@ +## assert-failed +## assert-stderr-contains "using key DynamicUser in the Service group is not supported" +[Service] +DynamicUser=foobar diff --git a/test/e2e/quadlet/service-group.container b/test/e2e/quadlet/service-group.container new file mode 100644 index 0000000000..e72954e918 --- /dev/null +++ b/test/e2e/quadlet/service-group.container @@ -0,0 +1,9 @@ +## assert-failed +## assert-stderr-contains "using key Group in the Service group is not supported" +[Container] +# This is fine +Group=1000 + +[Service] +# This isn't +Group=1000 diff --git a/test/e2e/quadlet/service-user.container b/test/e2e/quadlet/service-user.container new file mode 100644 index 0000000000..1f8334e1bc --- /dev/null +++ b/test/e2e/quadlet/service-user.container @@ -0,0 +1,9 @@ +## assert-failed +## assert-stderr-contains "using key User in the Service group is not supported" +[Container] +# This is fine +User=1000 + +[Service] +# This isn't +User=1000 diff --git a/test/e2e/quadlet_test.go b/test/e2e/quadlet_test.go index 5a479f18e0..0c075a4980 100644 --- a/test/e2e/quadlet_test.go +++ b/test/e2e/quadlet_test.go @@ -1126,6 +1126,16 @@ BOGUS=foo Entry("Build - Neither WorkingDirectory nor File Key", "neither-workingdirectory-nor-file.build", "converting \"neither-workingdirectory-nor-file.build\": neither SetWorkingDirectory, nor File key specified"), Entry("Build - No ImageTag Key", "no-imagetag.build", "converting \"no-imagetag.build\": no ImageTag key specified"), Entry("emptyline.container", "emptyline.container", "converting \"emptyline.container\": no Image or Rootfs key specified"), + + Entry("Unsupported Service Key - User", "service-user.container", "converting \"service-user.container\": using key User in the Service group is not supported"), + Entry("Unsupported Service Key - Group", "service-group.container", "converting \"service-group.container\": using key Group in the Service group is not supported"), + Entry("Unsupported Service Key - DynamicUser.build", "service-dynamicuser.build", "converting \"service-dynamicuser.build\": using key DynamicUser in the Service group is not supported"), + Entry("Unsupported Service Key - DynamicUser.container", "service-dynamicuser.container", "converting \"service-dynamicuser.container\": using key DynamicUser in the Service group is not supported"), + Entry("Unsupported Service Key - DynamicUser.image", "service-dynamicuser.image", "converting \"service-dynamicuser.image\": using key DynamicUser in the Service group is not supported"), + Entry("Unsupported Service Key - DynamicUser.kube", "service-dynamicuser.kube", "converting \"service-dynamicuser.kube\": using key DynamicUser in the Service group is not supported"), + Entry("Unsupported Service Key - DynamicUser.network", "service-dynamicuser.network", "converting \"service-dynamicuser.network\": using key DynamicUser in the Service group is not supported"), + Entry("Unsupported Service Key - DynamicUser.pod", "service-dynamicuser.pod", "converting \"service-dynamicuser.pod\": using key DynamicUser in the Service group is not supported"), + Entry("Unsupported Service Key - DynamicUser.volume", "service-dynamicuser.volume", "converting \"service-dynamicuser.volume\": using key DynamicUser in the Service group is not supported"), ) DescribeTable("Running success quadlet with ServiceName test case",