#1076837 Debian's use of systemd-sysusers makes consistent policy hard

#1076837#5
Date:
2024-07-24 02:12:19 UTC
From:
To:
Let me start by saying, the pain felt in #1029785 is relevant here.
The problem is somewhat different, but the basic set of conditions is
the same.  Sysadmins need to have control over the ranges that users
are created in in their environments, and the last several releases of
Debian have been making that more and more frustrating to accomplish.

When package policy dictated that everybody was to use adduser, this
wasn't an issue.  Admins configured login.defs, adduser followed the
rules present there, and having a working uid/gid allocation policy
was doable.  Then systemd came along.  In Debian 9, it wasn't a huge
problem yet, systemd-sysusers was barely used, certainly nothing vital
used it.  In Debian 10 its behavior of doing top down id allocation
become much more noticable as on first boot systemd-sysusers would
ensure configured users existed (a freshly dbootstrapped system would
usually see a this take effect) and it started clobbering uids
traditionally out of bounds by our local policies.  Annoying, but easy
to work around, we configured a /etc/sysusers.d policy that protected
our local ranges and things were good again; it was a little precious
having to keep both login.defs and our sysusers.d policy in sync, but
it's entirely doable.  Users created on boot by systemd-sysusers would
now follow the same policy that adduser follows.  (My local policy
dictates that uid/gid 600-999 are reserved, so my new sysusers.d
policy was simply "r - 100-599" which worked fine.)  Now here we are
with Debian 12, at some point debhelper grew a dh_installsysusers
which uses the postinst-sysusers autoscript and generates postinst
hooks; those postinst hooks make things significantly more
frustrating, and packages in Debian 12 are using them more than they
did in 11.

The problem is that the hooks call systemd-sysusers with a config file
argument.  When systemd-sysusers is invoked that way, it (to quote
from the manual):

   ... just the configuration specified by the command
   line arguments is executed.

The effect of this is that system users get created by debian packages
using dh_installsysusers in a way that completely ignores policy
established in /etc/sysusers.d *unless* that policy is established in
files that override every single sysusers.d config also shipped in a
package.  To use a concrete example, systemd-timesyncd used adduser in
its postinst script in Debian 11, and uses systemd-sysusers as of
Debian 12.  To protect my systems against this package creating its
system user in my reserved range I now have to create a
/etc/sysusers.d/systemd-timesync.conf file before installing the
package ... and I have to do this for _every_package_ that used
dh_installsysusers.  It's not immediately clear to me if calling
systemd-sysusers without explicit configs is going to be safe in the
context of a postinst script (only because I haven't spent a lot of
time thinking about it), but what is clear is that debhelper's
approach to using systemd-sysusers is making it difficult for
sysadmins to actually have and enforce a policy of what uid/gid ranges
are safe to use.

So now admins have to fight this system, one package at a time, which
is incredibly awkward, and really does not strike me as the intended
usage pattern of sysusers.d.

#1076837#10
Date:
2025-01-11 10:02:46 UTC
From:
To:
Hi Luca,

Can you review this one and comment? I am happy to change the debhelper
snippet, but I would need guidance on what to change to avoid breakage.

Best regards,
Niels

#1076837#15
Date:
2025-01-12 02:02:16 UTC
From:
To:
Hi Niels,

Please close+wontfix. Today the 1-999 range is reserved for the vendor
usage, at build time. Special local cases have the range
1879048192-4294967294 available to choose from, that doesn't clash
with the 'human' user id range, which should hopefully be enough for
dozens of years. It is not the 1980s anymore, and the uid range does
not stop at 65k. This is documented in detail at
https://systemd.io/UIDS-GIDS/ Yes, this is not how "things used to
work", and that's ok, stuff can change.
Thanks.

#1076837#20
Date:
2025-01-12 18:18:54 UTC
From:
To:
Luca Boccassi wrote:
...
ever intended to let sysadmins *override* systemd and/or the vendor's
UID/GID policy?  The only valid use for it is defining ranges left
undefined by the upstream policies?

Now, Debian, as said vendor, has documented it's policy:
https://www.debian.org/doc/debian-policy/ch-opersys.html#users-and-groups

100-999 (system) are dynamic, 65536-4294967293 (user) are dynamic,
4294967294 is reserved for some NFS implementations.  According to
https://systemd.io/UIDS-GIDS/ 1879048192-4294967294 contains two
ranges:

 1879048192…2147483647	Unused
 2147483648…4294967294	HIC SVNT LEONES

and goes on to warn against using 2147483648-4294967294 for entirely
convincing reasons.

Assuming, for the moment, I was able to completely change my local
policies because I had a homogeneous network with no operating systems
that had a conflicting static UID/GID allocation policy, and any
sec=sys NFS I had in play was all v4 with working nfsidmap upcalls
(which is an unrealistic assumption to be making, but let's dream),
and I had the time and resources to do an exhaustive UID/GID migration
of all my existing application users ... I *still* couldn't trust
systemd upstream to not allocate a new range inside of
1879048192-2147483647 in the future, so the likelihood that I would
use that range for anything is slim, barring systemd upstream setting
aside a dedicated range for local policy, and promising not to alter
that deal in the future.

My use case for the 600-999 local policy reservation is for system IDs
(applications not humans) defined in the local passwd db.  (Humans
have their IDs defined by a LDAP directory, a pretty common setup.) In
the interest of compatibility with the tools I'm using to make that
setup reliable and secure, I'd be more likely to override a bottom
chunk of the 1000-59999 range for my application users, because it
allows usage of libpam-ldapd's pam_ldap.so minimum_uid= argument, and
nslcd's nss_min_uid option.  I only point this out because systemd's
docs state that 1000-60000 are for "Regular users" while Debian's
policy states that 1000-59999 is for dynamically allocate user
accounts.  There's no mention that either of these ranges must only be
for humans, which I think is wise.