4.3.2. Account Hardening and Password Policies
💡 First Principle: Password policies exist because humans choose predictable passwords and reuse them across systems. Policy controls (minimum length, complexity, history, expiration) compensate for human predictability. MFA compensates for password compromise — even if an attacker has your password, they can't authenticate without the second factor.
Password Policy Configuration:
# PAM password quality — /etc/pam.d/common-password (Debian) or /etc/pam.d/system-auth (RHEL)
# pam_pwquality module
# /etc/security/pwquality.conf
minlen = 14 # Minimum 14 characters
minclass = 3 # Must use 3 of 4 classes (upper, lower, digits, special)
maxrepeat = 3 # No more than 3 consecutive identical characters
dictcheck = 1 # Check against dictionary
# Password aging via /etc/login.defs (defaults for new accounts)
PASS_MAX_DAYS 90 # Password expires after 90 days
PASS_MIN_DAYS 7 # Minimum 7 days before change allowed
PASS_WARN_AGE 14 # Warn 14 days before expiry
# Apply per-user aging with chage
chage -M 90 -m 7 -W 14 alice
Restricted Shells and Login Prevention:
# Prevent interactive login for system accounts
usermod -s /sbin/nologin nginx # Login attempt prints "This account is currently not available"
usermod -s /bin/false nginx # Login attempt silently fails
# Restricted bash shell (/bin/rbash)
# Cannot cd to other directories, cannot set PATH, cannot use command with /
usermod -s /bin/rbash restricteduser
# pam_tally2 / faillock — account lockout
# /etc/pam.d/system-auth — add:
# auth required pam_faillock.so preauth deny=5 unlock_time=900
faillock --user alice # Show lockout status for alice
faillock --user alice --reset # Unlock alice's account
MFA with PAM:
Multi-factor authentication adds a time-based one-time password (TOTP) requirement via pam_google_authenticator or similar modules. After entering a password, the user must also provide a code from their authenticator app.
Breach List Checking:
Tools like pam_pwhistory prevent password reuse (password history). External breach checking compares passwords against known-compromised lists (Have I Been Pwned API) — some PAM modules support this integration.
Avoid Running as Root:
# Use sudo with specific commands instead of root login
# Use su - only when necessary and log it via auditd
# Service accounts should use nologin shell
# Development: never develop as root — test with a regular user first
⚠️ Exam Trap: /sbin/nologin and /bin/false both prevent interactive login, but they behave differently. nologin prints a message ("This account is currently not available") before refusing; false exits immediately with no output. For service accounts, either works. The exam may test which one provides a user-visible message.
Reflection Question: A compliance audit requires that all user accounts must lock after 5 failed login attempts and remain locked for 15 minutes. Which PAM module implements this, and what are the two key parameters?