Skip to main content
RunBook Academy

LinuxIV · Users, Groups and IdentityIdentity

Service accounts and system accounts

Intermediate⏱ ~10 minbashuseraddusermodpasswdsystemctl

What you'll learn

  • Distinguish system accounts (UID < 1000) from service accounts and human accounts
  • Design a service account that can be authenticated by automation
  • Lock down service accounts with no shell, no password, and SSH keys
  • Audit the inventory of service accounts on a host

Prerequisites

Verified against Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL 9.x · Rocky Linux 9.x · AlmaLinux 9.x · Linux kernel 6.1 LTS / 6.6 LTS · systemd 255+ · OpenSSH 8.7p1 (RHEL 9) / 9.6p1 (Ubuntu 24.04) · nftables 1.0.x · chrony 4.x · Pacemaker 2.1.x · Corosync 3.1.x · 2026-08-09

Not yet marked complete on this device.

A service account is a non-human identity that a daemon, a CI job, or a deployment tool uses to authenticate to the system. Service accounts are how you give automation the access it needs without granting it to the humans behind it.

Three classes of account

ClassUID rangeLogin shellTypical use
System account1-999/usr/sbin/nologin or /bin/falseVendored daemons: sshd, chronyd, nginx
Service account1000-60000/usr/sbin/nologin (no interactive login)Custom daemons, CI/CD, deployment automation
Human account1000-60000/bin/bash or /bin/zshPeople

A service account is not a system account. System accounts are created by packages; service accounts are created by your operations team for your applications.

Creating a service account

Configuration changeuseradd -r
$ sudo useradd -r -m -d /opt/myapp -s /usr/sbin/nologin -c 'MyApp service account' myapp; getent passwd myapp
myapp:x:999:999:MyApp service account:/opt/myapp:/usr/sbin/nologin

Illustrative output

Service accounts that need authentication

Some service accounts need to authenticate: SSH into other hosts, authenticate to an API, or sign requests. The production discipline:

Configuration changeSSH-key-only service account
$ sudo useradd -r -m -d /var/lib/deploy -s /bin/bash deploy; sudo passwd -l deploy; sudo -u deploy ssh-keygen -t ed25519 -N '' -f /var/lib/deploy/.ssh/id_ed25519
Generating public/private ed25519 key pair.
Your identification has been saved in /var/lib/deploy/.ssh/id_ed25519
Your public key has been saved in /var/lib/deploy/.ssh/id_ed25519.pub

Illustrative output

  1. Lock the password. passwd -l ACCOUNT immediately after creation
  2. Use SSH keys only. Generate an ed25519 keypair with no passphrase. Place the public key in the remote system's authorized_keys
  3. Do not give the account an interactive shell unless required. /usr/sbin/nologin is the right default; switch to /bin/bash only if the account will run user-facing automation
  4. Restrict sudo. If the account needs root, give it only the specific commands it needs via /etc/sudoers.d/
  5. Audit the inventory. getent passwd shows all accounts. Cross-reference against your configuration management

Where service accounts live

The home directory of a service account is conventionally:

  • /opt/<application> for application service accounts.
  • /var/lib/<application> for data-heavy services.
  • /srv/<application> for services that serve content.
  • /run/<application> for ephemeral runtime state.
Read-only / Safeservice account homes
$ ls -ld /opt/myapp /var/lib/mysql /var/lib/docker /srv/www
drwxr-xr-x 3 myapp myapp 4096 Aug  9 11:11 /opt/myapp
drwxr-x--- 6 mysql mysql 4096 Aug  9 11:11 /var/lib/mysql
drwx------ 9 root root 4096 Aug  9 11:11 /var/lib/docker
drwxr-x--- 5 root www-data 4096 Aug  9 11:11 /srv/www

Illustrative output

systemd DynamicUser

For ephemeral service identities, systemd offers DynamicUser=:

[Service]
DynamicUser=yes
ExecStart=/usr/bin/myapp

When the service starts, systemd allocates a UID from the range 60001-60513 (or higher), runs the service as that UID, and deallocates the UID on stop. The service has no persistent identity — every restart gets a new UID.

DynamicUser is the right choice for stateless services that do not need persistent file ownership. It is not appropriate for services with persistent state (databases, message queues) because the file ownership becomes invalid on every restart.

Auditing service accounts

Read-only / Safeaudit human + service accounts
$ awk -F: '$3 >= 1000 &amp;&amp; $3 &lt; 65534 { print $1, $3, $7 }' /etc/passwd | sort -k2 -n
alice 1000 /bin/bash
deploy 1100 /bin/bash
myapp 999 /usr/sbin/nologin

Illustrative output

Read-only / Safeaudit system account shells
$ awk -F: '$3 &lt; 1000 &amp;&amp; $3 &gt; 0 &amp;&amp; $7 !~ /nologin/ { print $1, $3, $7 }' /etc/passwd
sync 1 /bin/sync
halt 7 /sbin/halt
shutdown 6 /sbin/shutdown

Illustrative output

Knowledge check

Knowledge check · 3 questions

  1. Q1. What is the recommended shell for a service account that is launched by systemd and needs no interactive login?

  2. Q2. A service account should always have a strong password.

  3. Q3. Which of the following are correct service-account practices? Select all that apply.

Passing score: 75%. Answers are checked in this browser.