Lab: User Lifecycle, Password Policy, and Scoped sudo
Users and Groups, Password Policies, and sudo Security each covered one piece of the account lifecycle. This lab walks the full lifecycle end to end for a single realistic case — onboarding a contractor with a time-limited engagement, scoped privileges, and a clean, auditable offboarding — because that sequence, not any single command in isolation, is what actually gets tested in an LFCS-style task and what actually happens in production operations.
Goal and End Result
By the end of this lab you will have onboarded a contractor account (contractor1) with:
- a home directory and shell set explicitly, not left to defaults;
- a password that expires in 14 days and must be changed at next login;
sudoaccess scoped to exactly two commands, not full root;- a documented, verified offboarding procedure that locks the account without destroying its files.
Topology and Starting State
A single lab VM or container, with sudo access for your own account.
Requirements
chageandpasswd(part ofshadow-utils, present by default);visudofor safely editingsudorules.
Security and Snapshot Note
Warning
This lab modifies /etc/sudoers.d/ and creates a real, working account with sudo access. Always edit sudoers files with visudo or visudo -f, never a plain text editor — visudo syntax-checks the file before saving and refuses to save a broken one, which prevents the single most common way administrators accidentally lock sudo out for everyone. Before starting, confirm you have an independent way back into the system (a second open root session) in case a mistake is made.
Step 1: Create the Account with Explicit Settings
sudo useradd -m -d /home/contractor1 -s /bin/bash -c "Contractor - Q3 engagement" contractor1
sudo passwd contractor1
-c records a comment describing who this account is and why it exists — worth doing for any non-standard account, since six months later "why does this account exist" is a much harder question to answer without it.
Verify:
Step 2: Set a 14-Day Password Expiration and Forced Change at First Login
-M 14 sets the maximum password age to 14 days; -d 0 sets the last-changed date to the epoch, which forces a password change on the very next login regardless of the 14-day window — the standard way to guarantee a temporary, admin-set password is never the one actually used going forward.
Verify:
Last password change : password must be changed
Password expires : password must be changed
Password inactive : never
Account expires : never
Minimum number of days between password change : 0
Maximum number of days between password change : 14
Step 3: Set a Hard Account Expiration Date
A contractor engagement has a known end date — the account should not merely have an aging password, it should stop working entirely after the engagement ends, without anyone needing to remember to disable it manually.
sudo chage -E "$(date -d '+90 days' +%Y-%m-%d)" contractor1
sudo chage -l contractor1 | grep "Account expires"
-E sets an absolute account expiration date — after this date, the account cannot log in at all, independent of the password's own expiration cycle set in Step 2. This is the correct control for "this person's access should end on a known date," rather than relying on someone remembering to run usermod -L manually on the right day.
Step 4: Scope sudo to Exactly Two Commands
contractor1 needs to restart one specific application service and check its status — nothing more.
contractor1 ALL=(root) NOPASSWD: /usr/bin/systemctl restart myapp.service, /usr/bin/systemctl status myapp.service
As covered in sudo Security, listing the full, absolute path to each binary — not a bare command name — is required for this scoping to mean anything: sudo matches the exact path given, and a bare systemctl in the rule combined with a contractor1-controlled PATH could otherwise be tricked into resolving to a different binary entirely.
Verify:
User contractor1 may run the following commands on this host:
(root) NOPASSWD: /usr/bin/systemctl restart myapp.service, /usr/bin/systemctl status myapp.service
Sorry, user contractor1 is not allowed to execute '/usr/bin/systemctl stop myapp.service' as root on this host.
The status and restart commands succeed exactly as scoped; stop, which was never granted, is correctly refused — confirming the sudoers rule is doing precisely what it says and nothing broader.
Practical Scenario: Offboarding at the End of the Engagement
Problem. The contractor's engagement ends today, three days before the chage -E expiration date set in Step 3. Access needs to end immediately, but the account's files should be preserved for a retention period, not deleted outright.
Check current state before changing anything:
Command — lock the password and force immediate expiration:
usermod -L locks the password (prepends ! to the hash in /etc/shadow, preventing password-based login), and setting the expiration date to today ensures the account cannot be used at all from this point forward, independent of any password.
Verify:
Read every field, not just the first: L is the lock status (L locked, P usable password, NP no password); 07/29/2026 is the date of the last password change; then, in order, the minimum age (0), maximum age (14, from Step 2), the warning period (7 days), and the inactivity period (-1, disabled). The leading L is the one that confirms the lock, but the maximum-age and change-date fields are what let you confirm at a glance that the password-aging policy from Step 2 is still in force.
usermod -L alone does not fully disable an account
This is the exact gotcha interviewers use to separate rote answers from real understanding: usermod -L only locks the password hash — it does nothing to key-based SSH login, to any session already open, or to cron/at jobs the account owns. An attacker (or the contractor) with an authorized SSH key in ~/.ssh/authorized_keys can still log in to an account that passwd -S reports as L. That is precisely why this lab pairs usermod -L with chage -E "$(date +%Y-%m-%d)": the account-expiration date is enforced by the login stack regardless of authentication method, closing the key-based path that -L leaves open. Locking the password is necessary but not sufficient — always verify with an actual login attempt (below), and, for a hard offboarding, also remove or revoke the account's authorized keys.
The leading L confirms the account is locked. Attempt a login (or su - contractor1 from another session) to confirm it is actually refused, not just reported as locked.
Conclusion. The account is fully disabled without deleting /home/contractor1 or its files — the correct middle ground between leaving stale access open and destroying data that a retention or audit policy may require to keep for a period after offboarding.
Troubleshooting Tips
sudo -l -U contractor1shows nothing, though the sudoers file looks correct. Check the file's permissions withls -l /etc/sudoers.d/contractor1—sudosilently ignores any file insudoers.d/that is group- or world-writable, as a defense against a misconfigured permission accidentally allowing the rule to be tampered with.visudorefuses to save and reports a syntax error. This isvisudodoing its job — read the reported line number carefully rather than forcing a save; a broken sudoers file edited outsidevisudocan lock every user out ofsudo, including root's ownsudoaccess ifsudoitself is the only path to root on that system.- The account still appears able to log in after
chage -Ein the past. Confirm the system clock and timezone are correct (timedatectl) — an account expiration compared against a wrong system clock can behave unpredictably.
Rollback and Cleanup
Final Assessment Criterion
This lab is complete when all of the following hold:
contractor1's password is confirmed to require a change at first login (chage -lshows "must be changed");- the account has both a password expiration (14 days) and a hard account expiration date set independently;
sudo -l -U contractor1shows exactly the two scoped commands and nothing broader;- an attempt to run an unscoped
sudocommand ascontractor1is refused; - after offboarding,
passwd -S contractor1reports the account as locked (L), and the home directory still exists.
Exercises
- Repeat Steps 1–4 for a second contractor,
contractor2, granting a different pair of scoped commands. Confirm withsudo -l -Uthat the two contractors' sudo rules do not overlap. - Using
chage -l, explain the difference between what happens when a password expires (-M) versus when the account itself expires (-E), and describe a real scenario where you would want only one of the two, not both. - Write the single sentence you would put in a change-management ticket describing exactly what the offboarding scenario above changed, in a way that a auditor reviewing it six months later could understand without further context.