Home / Alt manpages / systemd-sysusers(8)

  • systemd-sysusers(8)
  • Admin command
  • linux

Declare a Locked-Down Service Account with systemd-sysusers

You will create a repeatable sysusers.d definition for a service account, preview the resulting user and group allocation, apply it, and verify the account without editing /etc/passwd by hand. The examples are for systemd 255, installed here as Debian package systemd 255.4-1ubuntu8.17.

Allow about fifteen minutes. You need a shell and a package that provides systemd-sysusers. Reading and previewing configuration is normally unprivileged. Writing a system configuration and allocating an account require elevated privileges. This guide creates a system account, not a normal human login, and deliberately gives it no usable login shell.

Checkpoint

If you already have a configuration file, start at step 3. If you are only checking a vendor file, step 2 is enough.

1. Confirm the installed implementation

Check the binary and package version before relying on an option. This matters because features such as --dry-run and --inline were added in different systemd releases:

$ command -v systemd-sysusers
/usr/bin/systemd-sysusers
$ systemd-sysusers --version
systemd 255 (255.4-1ubuntu8.17)

The command is also the implementation behind systemd-sysusers.service. It reads declarative files from /etc/sysusers.d, /run/sysusers.d and /usr/lib/sysusers.d. The local administrator's /etc files have higher priority than files with the same name in the other directories.

2. Inspect existing definitions before adding one

With no configuration-file argument, systemd-sysusers considers all discovered definitions. Use --cat-config to see the files and their comments without applying them:

$ systemd-sysusers --cat-config --no-pager | sed -n '1,30p'
# /usr/lib/sysusers.d/basic.conf
# generated from /usr/share/base-passwd/{passwd,group}.master
g adm        4     -
g tty        5     -
g disk       6     -

Your list will differ. Use --tldr instead when comments and blank lines are distracting. Do not assume a name is unused because its vendor file is hard to find: verify with getent passwd NAME and getent group NAME before choosing an account name.

Names may contain letters, digits, underscores and hyphens, but cannot start with a digit or hyphen and are limited to 31 characters. A leading underscore makes a collision with an administrator-created human account less likely, so this guide uses _reporter.

3. Write one small configuration file

Put local administrator configuration in /etc/sysusers.d. The file name should identify the package or service and end in .conf. The following definition requests an automatically allocated UID and GID, a descriptive GECOS field, and the default non-login shell:

$ sudo install -d -m 0755 /etc/sysusers.d
$ sudo sh -c 'printf "%s\n" "u _reporter - \"Report worker\" - /usr/sbin/nologin" > /etc/sysusers.d/report-worker.conf'
$ sudo chmod 0644 /etc/sysusers.d/report-worker.conf
$ sudo sed -n '1,5p' /etc/sysusers.d/report-worker.conf
u _reporter - "Report worker" - /usr/sbin/nologin

A u line creates the user and a matching primary group if they do not exist. A hyphen in the ID field requests automatic allocation from systemd's pool. The explicit shell keeps the intent visible; if the shell column is omitted, systemd normally uses /usr/sbin/nologin for a non-root account anyway. The home-directory hyphen means no useful home directory is requested.

Do not put a password in this file. A u account is created disabled, and service accounts should not be made interactive merely to make a test convenient.

4. Preview the change

Run the exact file through --dry-run before applying it. The command processes the configuration but does not write account databases:

$ systemd-sysusers --dry-run /etc/sysusers.d/report-worker.conf
Creating group '_reporter' with GID 981.
Creating user '_reporter' (Report worker) with UID 981 and GID 981.
Would write /etc/group...
Would write /etc/gshadow...
Would write /etc/passwd...
Would write /etc/shadow...

The numeric ID is host-dependent. It may differ from the example, and the preview may mention fewer changes if the account already exists. Treat any unexpected existing name, fixed ID, or configuration file as a stop-and-investigate result. A dry run is not a reservation: another account allocation can use an ID before the real run.

For a throwaway syntax check, you can avoid creating a file entirely. On systemd 255, --inline treats each positional argument as a configuration line:

$ systemd-sysusers --dry-run --inline 'u _preview - "Preview only"'
Creating group '_preview' with GID 981.
Creating user '_preview' (Preview only) with UID 981 and GID 981.
Would write /etc/group...

Output formatting and allocated numbers vary. The useful checks are the account and group names, a proposed allocation, and the Would write messages.

5. Apply the definition

Once the preview matches your intention, apply only the file you reviewed:

$ sudo systemd-sysusers /etc/sysusers.d/report-worker.conf
$ getent passwd _reporter
_reporter:x:981:981:Report worker:/usr/sbin:/usr/sbin/nologin
$ getent group _reporter
_reporter:x:981:

The UID, GID and exact passwd-field rendering are host-specific. A successful command returns status 0 and the two getent queries should return records. Running the command again is normally harmless: sysusers is designed to do nothing for users, groups and memberships that already exist.

Warning

This changes persistent account databases. There is no general inverse command that safely removes an account and all files owned by its UID. If the definition was wrong, first stop the service that might use it, preserve evidence about the allocated UID, remove or correct the configuration file, and have an administrator decide whether account removal is appropriate. Do not blindly run userdel or delete files by numeric ownership.

6. Add a supplementary group only when required

If the worker genuinely needs access to a device or another service-owned resource, use a separate m line to add it to an existing group:

u _reporter - "Report worker" - /usr/sbin/nologin
m _reporter input

An m line can implicitly create a missing user or group, so check both names before applying a change that grants access. Membership is an authorisation decision, not a harmless convenience. Prefer the narrowest existing group, and do not add a service account to broad groups such as sudo, adm or docker without documenting the resulting privilege.

After changing membership, rerun the file and verify it with:

$ getent group input
input:x:999:_reporter

The group ID and other members vary. If the account is already in the group, sysusers normally leaves it alone.

7. Understand precedence and overrides

All files are sorted lexicographically across the three directories. An administrator file in /etc/sysusers.d overrides a vendor file with the same name, while a symlink from /etc/sysusers.d to /dev/null disables a vendor file with that name. Earlier entries for the same user or group win and later conflicting entries are logged as warnings.

Keep overrides deliberate and inspect them before applying the full set:

$ ls -l /etc/sysusers.d /run/sysusers.d /usr/lib/sysusers.d
$ systemd-sysusers --cat-config --no-pager | less

Do not edit a vendor file under /usr/lib/sysusers.d. Package upgrades can replace it. If you must suppress one, record why the /dev/null symlink exists and test the package's service after the upgrade.

8. Keep home directories and disk-image work separate

sysusers records a home directory in the user database but does not create that directory. If an application needs one, create it with a matching tmpfiles.d definition and set ownership there, rather than assuming the u line creates it.

For an offline root filesystem, --root=/path/to/root prefixes paths and configuration searches with that directory. --image=/path/to/image targets a disk image instead. These options can modify a different system from the one named in your prompt, so confirm the mount or image and take a backup before using them. They are not needed for the host-local example in this guide.

Done means

  • The installed systemd version and command syntax were checked.
  • The account name was checked against both passwd and group databases.
  • The definition lives in an administrator-owned /etc/sysusers.d/*.conf file.
  • A dry run was reviewed before any account database was changed.
  • getent passwd and getent group confirm the resulting records.
  • The account has no interactive shell and receives only explicitly justified group membership.
  • Any correction plan preserves the account's UID and avoids blind deletion of owned files.