systemd-sysusers: Provision Linux Service Accounts Declaratively
Provision system users and groups with sysusers.d, checking UID allocation, configuration precedence, and the boundary from human accounts.
Packages and early-boot services often need a dedicated, non-interactive account. systemd-sysusers provides a small declarative mechanism for creating system users and groups from sysusers.d files. It is useful when identity creation belongs to a package or image build, but it is not a general user-management framework and it does not reconcile every property of an account that already exists.
The upstream examples below follow systemd v262. Distribution releases may ship a different version or build configuration, so check the local systemd-sysusers(8) and sysusers.d(5) pages before relying on newer syntax.
Put machine-service identities in the right layer
sysusers.d is appropriate for service identities managed in the local /etc/passwd and /etc/group databases. It bypasses more complex identity sources such as LDAP or NIS; do not use it to create ordinary people accounts on a host whose identity policy is owned by SSSD, LDAP, or another directory service.
Choose names that will not collide with human accounts. systemd recommends a leading underscore for system users and groups. For a local machine-specific definition, create /etc/sysusers.d/acme-worker.conf:
# Type Name ID GECOS
u! _acme-worker - "Acme worker"
g _acme-readers -
m _acme-worker _acme-readers
The u! record requests a fully locked service account; it also creates a same-name primary group when one is absent. - requests automatic UID/GID allocation, which avoids reserving an arbitrary numeric ID but does not guarantee that different independently provisioned machines will choose the same number. If file ownership must line up across hosts, containers, or shared storage, allocate IDs through the environment’s UID/GID policy instead of assuming automatic values will match.
The g line creates an additional group, and m adds the account to it. Keep supplementary membership narrow: it grants access only through the permissions attached to that group, but those permissions may include sensitive data or devices.
Understand file precedence before overriding a package
Packages install definitions under /usr/lib/sysusers.d; local administrator definitions belong in /etc/sysusers.d. A same-named file in /etc overrides the packaged file, while /run has higher precedence than /usr/lib for the same filename. Other files are processed in lexicographic filename order. If multiple files declare the same user or group name, the earliest applicable declaration wins and later duplicate declarations are reported.
This means a file called 00-local.conf can affect resolution order, not merely documentation order. Before adding an override, inspect the vendor file and the local directory. Avoid copying an entire vendor definition into /etc just to change one attribute; the tool is intentionally idempotent and normally leaves an existing user or group alone.
Preview, apply, and verify
On systemd versions that support it, --dry-run parses the rules and reports what would be created without writing account files. Preview the exact local file first:
systemd-sysusers --dry-run /etc/sysusers.d/acme-worker.conf
Review the proposed names and IDs, then apply that file during the normal change or package-installation window:
systemd-sysusers /etc/sysusers.d/acme-worker.conf
getent passwd _acme-worker
getent group _acme-readers
id _acme-worker
Do not treat --root= as a sandbox for an untrusted definition: the upstream manual explicitly says it is not a security feature. For image construction, use the documented image/build workflow and an isolated root you control.
systemd-sysusers creates database entries; it does not create a home directory’s contents, install application files, set ownership on a state tree, or define the service’s runtime sandbox. If a home directory is genuinely required, the home field only records it; pair it with a separately reviewed tmpfiles.d rule or another explicit directory-provisioning step. For ordinary service state, prefer the service manager’s dedicated directory controls where appropriate. Keep account creation, filesystem ownership, and service permissions as separate verifiable steps.
Version and migration boundaries
The u! form is documented as available since systemd v257 and differs from u by locking the account against non-password authentication methods as well. The long --dry-run option is older; the short -n alias is documented as added in v262. Use the long option for portability and test against the actual distribution build. If the account already exists, a successful run does not mean that its UID, shell, home, groups, or lock state were reconciled to your new file. Inspect and migrate existing identities deliberately instead of expecting a declarative file to repair drift.
Related:
- Understanding systemd: Units, Targets, and the Modern Linux Init System
- How to Pass Secrets to systemd Services with the Credentials API
Sources: