Skip to main content
RunBook Academy

← All labs in Linux

Lab · intermediate · ~45 min

Lab: User and group management with safe defaults

B · Nested virtualisationC · Simulation

Objectives

  • Create a service account with locked password and no interactive shell
  • Set password aging policies via chage
  • Add an existing user to a supplementary group without breaking memberships
  • Audit the host for unexpected UID 0 accounts and world-readable home directories

Prerequisites

This lab trains the muscle memory of safe service-account creation and identity-policy enforcement. Every command in this lab has a production counterpart, and every audit has a finding.

Objective

By the end of this lab, you can create a hardened service account, set a password aging policy, add an existing user to a supplementary group safely, and audit the host for common identity misconfigurations.

Architecture

flowchart LR
  CR["useradd / usermod<br/>account creation"]
  AG["chage<br/>password aging"]
  AUDIT["awk / getent<br/>identity audit"]
  HOMES["find<br/>home-dir audit"]
  LOCK["passwd -l<br/>lock the password"]

Requirements

  • A Linux host (Ubuntu 24.04 LTS or Debian 12 preferred).
  • Root or sudo access.
  • An existing test user you can modify safely (do not use root or any account you cannot recreate).

Scenario

Your team is preparing a new application deployment. You need to:

  1. Create a myapp service account for the application daemon.
  2. Set the myapp account’s password aging policy.
  3. Add an existing user (alice) to a docker supplementary group to allow her to use Docker without sudo.
  4. Audit the host for identity drift.

Tasks

Task 1: Create the service account

sudo useradd -r -m -d /opt/myapp -s /usr/sbin/nologin -c 'MyApp service account' myapp
sudo passwd -l myapp
getent passwd myapp

Verify:

  • UID is below 1000 (because of -r).
  • Home directory exists at /opt/myapp.
  • Login shell is /usr/sbin/nologin.
  • Password is locked (! prefix in /etc/shadow).

Task 2: Set the aging policy

sudo chage -M 90 -m 7 -W 14 myapp
sudo chage -l myapp

Verify the aging fields are set. Note: service accounts typically should not have passwords that expire in the traditional sense, but aging fields are still useful for EXPIRED account handling if the account is ever unlocked.

Task 3: Safely add alice to a supplementary group

Before:

id alice
groups alice

Append to the docker group (not replace):

sudo usermod -aG docker alice
id alice

Verify alice retains her existing memberships AND has docker.

Task 4: Audit UID 0 accounts

awk -F: '$3 == 0 { print $1 }' /etc/passwd

The expected output is exactly one line: root. Any other line is a finding.

Task 5: Audit system account shells

awk -F: '$3 < 1000 && $3 > 0 && $7 !~ /nologin/ { print $1, $7 }' /etc/passwd

The output should be empty or contain only the special-cased accounts (sync, halt, shutdown). Anything else is a finding.

Task 6: Audit world-readable home directories

sudo find /home -type d -perm -o+r 2>/dev/null
ls -ld /home/*/

Each home directory should be drwx------ (0700) or drwxr-x--- (0750). World-readable home directories leak the contents of .ssh/, .bash_history, and similar sensitive files.

Task 7: Audit the new account

getent passwd myapp
getent shadow myapp
ls -ld /opt/myapp

Verify the account is correctly hardened.

Validation

The lab is complete when:

  • myapp exists, UID below 1000, locked password, no interactive shell.
  • myapp has aging fields set to 90 max / 7 min / 14 warn.
  • alice retains her original memberships and has docker added.
  • The UID 0 audit returns only root.
  • The system-account-shell audit returns no surprises.
  • No world-readable home directories exist (or all findings are documented).

Expected outcome

A hardened service account ready for an application deployment, and evidence that the host’s identity database is in a known-good state.

Troubleshooting

  • “useradd: UID 999 is already in use” — pick a different UID in the system range or check for stale packages.
  • alice lost her memberships in Task 3usermod -aG was not used. Restore with usermod -aG <list of groups> alice based on the original id output.
  • “chage: permission denied” — running as non-root. Use sudo.
  • myapp home directory missing-m was not passed. Remove the account with userdel -r myapp and recreate with -m.

Cleanup

Remove the test account:

sudo userdel -r myapp

Verify removal:

getent passwd myapp
ls /opt/myapp

The lab host should be in the same state as before the lab.

What you learned

You can now create production-grade service accounts, set aging policies without locking humans out, and audit the identity database for the most common production misconfigurations.

Deliverables

  • · A written summary of the service account created and the aging policy set
  • · Output of getent passwd, awk UID 0 audit, and find for world-readable home directories
  • · A demonstration of `usermod -aG` versus `usermod -G` (with a rollback plan)

Verification status

Last reviewed
2026-08-09
Executed end to end
not yet run on hardware

The commands and configuration here have been reviewed against the verified software versions, but nobody has run this lab start to finish on a system meeting its prerequisites. Treat the Expected Outcome as the intended result rather than an observed one, and keep the Cleanup section to hand.