Enforce password policy that actually holds

short · 30 min · Objective 3.4

Task

Configure password quality, history and lockout, then prove each one holds by trying to defeat it. The history rule in particular is easy to configure in a way that does nothing, and the point is to catch that before it ships.

Steps

  1. Configure minimum length and complexity with pam_pwquality. As tester, try to set a short password and confirm it is refused.
  2. Configure history with remember=5 in pam_unix (or pam_pwhistory). As tester, change the password and immediately try to change it back to the previous one. Confirm it is refused.
  3. Now defeat your own history rule: as tester, change the password six times in quick succession -- one more than remember=5, because after five changes the original is still the fifth password remembered -- and then back to the original. Confirm it SUCCEEDS, because nothing stopped you cycling through.
  4. Fix that by setting a minimum age with chage -m 1 tester, and confirm the second change within a day is now refused. History and minimum age only work as a pair.
  5. Configure lockout with pam_faillock: set deny and, crucially, unlock_time. Fail logins until locked, confirm with faillock, and wait for or reset the lock.
  6. Explain why omitting unlock_time turns the lockout into a denial-of-service that any attacker can trigger against any known username.
  7. Restore both backups and confirm normal login works.

Verify

# before step 7, while your policy is in place:
echo "short" | pwscore 2>&1 | grep -qi 'shorter than' && echo "quality enforced"
chage -l tester | grep -i 'minimum'                # non-zero
grep -Eqs '^\s*unlock_time\s*=\s*[1-9]' /etc/security/faillock.conf || grep -Eqs '^[^#]*pam_faillock.*unlock_time=[1-9]' /etc/pam.d/* && echo "unlock_time set"
# after step 7:
diff -r /etc/pam.d /root/pam.d.backup && diff -r /etc/authselect /root/authselect.backup && echo "pam restored"

pwscore tests a password against the policy in pwquality.conf without changing anyone's password: passwd --stdin is root-only, and root is warned but not refused. The unlock_time check reads only uncommented settings -- RHEL's stock faillock.conf carries # unlock_time = 600, which a plain grep counts as configured.

Step 3 is the one that matters. A history rule with no minimum age is configuration that reports a policy it does not enforce -- the same proxy trap as everywhere else in this project, wearing a security hat.

Notes

Current guidance favours length over rotation and prefers checking against breach corpora to forcing periodic changes. But where an organisation still mandates history, configure it so it actually holds -- which means the minimum age, every time.

This is an independent study companion for CompTIA Linux+ and is not produced by or endorsed by CompTIA.