LinuxIV · Users, Groups and IdentityIdentity
Service accounts and system accounts
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
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
| Class | UID range | Login shell | Typical use |
|---|---|---|---|
| System account | 1-999 | /usr/sbin/nologin or /bin/false | Vendored daemons: sshd, chronyd, nginx |
| Service account | 1000-60000 | /usr/sbin/nologin (no interactive login) | Custom daemons, CI/CD, deployment automation |
| Human account | 1000-60000 | /bin/bash or /bin/zsh | People |
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
$ sudo useradd -r -m -d /opt/myapp -s /usr/sbin/nologin -c 'MyApp service account' myapp; getent passwd myappmyapp:x:999:999:MyApp service account:/opt/myapp:/usr/sbin/nologinIllustrative 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:
$ 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_ed25519Generating 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.pubIllustrative output
- Lock the password.
passwd -l ACCOUNTimmediately after creation - Use SSH keys only. Generate an ed25519 keypair with no passphrase. Place the public key in the remote system's authorized_keys
- Do not give the account an interactive shell unless required.
/usr/sbin/nologinis the right default; switch to/bin/bashonly if the account will run user-facing automation - Restrict sudo. If the account needs root, give it only the specific commands it needs via /etc/sudoers.d/
- 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.
$ ls -ld /opt/myapp /var/lib/mysql /var/lib/docker /srv/wwwdrwxr-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/wwwIllustrative 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
$ awk -F: '$3 >= 1000 && $3 < 65534 { print $1, $3, $7 }' /etc/passwd | sort -k2 -nalice 1000 /bin/bash
deploy 1100 /bin/bash
myapp 999 /usr/sbin/nologinIllustrative output
$ awk -F: '$3 < 1000 && $3 > 0 && $7 !~ /nologin/ { print $1, $3, $7 }' /etc/passwdsync 1 /bin/sync
halt 7 /sbin/halt
shutdown 6 /sbin/shutdownIllustrative output
Knowledge check
Knowledge check · 3 questions
Q1. What is the recommended shell for a service account that is launched by systemd and needs no interactive login?
Q2. A service account should always have a strong password.
Q3. Which of the following are correct service-account practices? Select all that apply.
Passing score: 75%. Answers are checked in this browser.