Skip to content

PAM, Password Policies & User Security

Chapter 22: PAM, Password Policies & User Security

Section titled “Chapter 22: PAM, Password Policies & User Security”
  • Understand the PAM architecture and module types
  • Configure strong password policies using PAM
  • Understand account lockout and session management
  • Configure MFA via PAM

Password policies enforce strong security rules for user accounts. They dictate how long a password must be, how complex it should be, and how the system should react (like temporarily locking the account) if someone types the wrong password too many times.

PAM (Pluggable Authentication Modules) provides a flexible, modular authentication framework.

PAM Architecture
─────────────────
Application (sshd, sudo, login, su)
│ calls pam_authenticate()
┌─────────────────────────────────────────────────────┐
│ PAM Library (libpam.so) │
│ │
│ Reads /etc/pam.d/<service> │
│ Processes module stack in order │
└──────────────────────┬──────────────────────────────┘
┌──────────────────────▼──────────────────────────────┐
│ PAM Module Stack │
│ │
│ pam_unix.so ← Traditional Unix auth │
│ pam_google_authenticator.so ← TOTP │
│ pam_faillock.so ← Account lockout │
│ pam_pwquality.so ← Password complexity │
│ pam_limits.so ← Resource limits │
│ pam_lastlog.so ← Last login info │
└─────────────────────────────────────────────────────┘
PAM Management Groups:
────────────────────────
auth: Verify identity (password, key, biometric)
account: Account validity (expired? locked? time restrictions?)
password: Update authentication credentials
session: Setup/teardown session (mount home dir, set env, log)
Control Flags:
────────────────
required: Must succeed; failure noted but stack continues
requisite: Must succeed; failure halts stack immediately
sufficient: Success ends stack; failure noted but stack continues
optional: Used for side effects; success/failure mostly ignored
[success=n]: Jump n modules ahead on success (modern syntax)

Terminal window
# PAM service files location
ls /etc/pam.d/
# Important files:
# sshd — SSH daemon auth
# sudo — sudo authentication
# su — su command auth
# login — Console login
# common-auth — Included by others (Ubuntu/Debian)
# system-auth — Included by others (RHEL)
# View a service's PAM config
cat /etc/pam.d/sshd
/etc/pam.d/common-auth
auth [success=2 default=ignore] pam_unix.so nullok_secure
auth [success=1 default=ignore] pam_winbind.so krb5_auth krb5_ccache_type=FILE cached_login try_first_pass
auth requisite pam_deny.so
auth required pam_permit.so
auth optional pam_cap.so

Terminal window
# Install
apt-get install libpam-pwquality # Debian/Ubuntu
yum install pam_pwquality # RHEL
# /etc/security/pwquality.conf — Password requirements
/etc/security/pwquality.conf
# Minimum password length
minlen = 14
# Minimum character class requirements (negative = minimum count)
dcredit = -1 # At least 1 digit
ucredit = -1 # At least 1 uppercase
lcredit = -1 # At least 1 lowercase
ocredit = -1 # At least 1 special character
# Maximum consecutive same characters
maxrepeat = 3 # No more than 3 of the same char in a row
# Maximum consecutive same class characters
maxclassrepeat = 4 # No 4+ consecutive chars from same class
# Reject palindromes
palindrome = 1
# Check if password is based on username/GECOS
usercheck = 1
# Reject passwords from dictionary
dictcheck = 1
# Minimum number of characters that must be different from old password
difok = 8
# Number of passwords to remember (prevents reuse)
# Requires pam_pwhistory.so
/etc/pam.d/common-password
# Apply pam_pwquality to password changes
password requisite pam_pwquality.so retry=3
password [success=1 default=ignore] pam_unix.so obscure sha512 shadow \
use_authtok remember=12 # Remember last 12 passwords

/etc/security/faillock.conf
# pam_faillock — Lock accounts after repeated failures
# Replaces older pam_tally2
/etc/security/faillock.conf
# Number of failed attempts before lockout
deny = 5
# Time window for counting failures (seconds)
fail_interval = 900 # 15 minutes
# Lockout duration (seconds)
unlock_time = 900 # 15 minutes
# Admin accounts need stricter policy
# [users] section applies to all users
# Don't lock root (prevents lockout attack; root should use key auth anyway)
# even_deny_root
# root_unlock_time = 60
# Audit failed attempts
audit
Terminal window
# /etc/pam.d/common-auth — Add faillock support
auth required pam_faillock.so preauth
auth [success=1 default=ignore] pam_unix.so nullok_secure
auth [default=die] pam_faillock.so authfail
auth sufficient pam_faillock.so authsucc
auth requisite pam_deny.so
# View lockout status
faillock --user alice
# alice:
# When Type Source Valid
# 2024-01-15 10:00:00 RHOST 192.168.1.100 V
# Unlock a locked account
faillock --user alice --reset

Terminal window
# Set password aging policies
# Per-user aging
chage -l alice # View aging info
chage alice # Interactive
# Set specific values
chage -M 90 alice # Max password age: 90 days
chage -m 7 alice # Min password age: 7 days (prevent rapid cycling)
chage -W 14 alice # Warn 14 days before expiry
chage -I 30 alice # Lock account 30 days after expiry
chage -E 2025-12-31 alice # Account expiry date
# System-wide defaults for new accounts
# /etc/login.defs
PASS_MAX_DAYS 90 # Maximum password age
PASS_MIN_DAYS 7 # Minimum password age
PASS_WARN_AGE 14 # Days before warning
# Apply aging to all existing accounts (except system accounts)
for user in $(awk -F: '$3 >= 1000 {print $1}' /etc/passwd); do
chage -M 90 -m 7 -W 14 "$user"
done

Terminal window
# /etc/security/limits.conf — PAM-enforced resource limits
# Format: <domain> <type> <item> <value>
# Limit for all users
* soft nofile 65536 # Open file descriptors
* hard nofile 131072
* soft nproc 4096 # Number of processes
* hard nproc 8192
* soft stack 8192 # Stack size (KB)
* hard stack unlimited
# Specific user
alice soft cpu 240 # CPU time limit (minutes)
alice hard memlock unlimited # No memory locking limit
# Group-based
@developers soft nofile 32768
# /etc/pam.d/common-session — Enable limits
session required pam_limits.so
# Verify limits for a user
su - alice -c 'ulimit -a'

Terminal window
# ── Security Audit Commands ───────────────────────────────
# Find users with empty passwords
awk -F: '$2 == "" {print "NO PASSWORD:", $1}' /etc/shadow
# Find system accounts that can login (security issue)
awk -F: '$7 != "/sbin/nologin" && $7 != "/bin/false" && $3 < 1000 {
print "SYSTEM ACCOUNT WITH SHELL:", $1, "UID:", $3, "SHELL:", $7
}' /etc/passwd
# Find accounts with UID 0 (should be only root)
awk -F: '$3 == 0 {print "UID 0 ACCOUNT:", $1}' /etc/passwd
# Find duplicate UIDs
awk -F: '{print $3}' /etc/passwd | sort | uniq -d | while read uid; do
echo "DUPLICATE UID $uid:"
awk -F: -v u="$uid" '$3 == u {print " ", $1}' /etc/passwd
done
# Check password expiry for all users
awk -F: '$3 >= 1000 && $3 < 65534 {print $1}' /etc/passwd | while read user; do
EXPIRY=$(chage -l "$user" 2>/dev/null | grep "Password expires" | cut -d: -f2)
echo "$user: expires$EXPIRY"
done
# Find users who haven't logged in for 90+ days
lastlog | awk '$4 != "Never" && $4 != "Latest" {
# Parse date and check age - manual implementation needed
print
}' | head -20

Q1: What is PAM and how does the module stack work?

Answer: PAM (Pluggable Authentication Modules) is a framework that decouples authentication from applications. Instead of each application implementing its own authentication logic, they call PAM APIs, which consult a configuration file (/etc/pam.d/<service>) that defines a stack of modules to run. The stack has 4 management groups: auth (verify identity), account (check account validity), password (update credentials), session (setup/teardown). Each module has a control flag: required (must succeed, failure noted but continues), requisite (failure immediately halts), sufficient (success ends the group), optional (mostly ignored). This allows mixing Unix passwords, LDAP, OTP, and biometrics by adding modules to the stack.

Q2: How would you configure a system to lock accounts after 5 failed login attempts?

Answer: Using pam_faillock: (1) Install/configure /etc/security/faillock.conf with deny = 5, fail_interval = 900, unlock_time = 1800. (2) Add to /etc/pam.d/common-auth: auth required pam_faillock.so preauth before the main auth module and auth [default=die] pam_faillock.so authfail after. (3) Verify: attempt 5 wrong passwords, then faillock --user <user> confirms the lock. Unlock manually with faillock --user <user> --reset. Also configure even_deny_root carefully — if root gets locked, ensure you have out-of-band access (console, AWS SSM).


ComponentPurpose
PAMPluggable authentication framework
pam_unixTraditional Unix password auth
pam_pwqualityPassword complexity enforcement
pam_faillockAccount lockout after failures
pam_limitsResource limits (ulimits)
pam_google_authenticatorTOTP/2FA
/etc/login.defsSystem-wide account defaults
chagePassword aging configuration

Chapter 18 (PAM).


Advantages: Prevents trivial account takeovers, enforces compliance. Disadvantages: Overly strict policies encourage users to write passwords on sticky notes.


  • Setting password expiry too frequently — users will just append numbers to the same password.
  • Locking out the root account via PAM faillock without an alternative emergency access method.

SymptomCauseDiagnosisFix
User cannot change passwordPassword doesn’t meet complexity rulesCheck /var/log/secure or auth.logInform user of the specific policy (length, class)
Account locked due to failed loginsfaillock triggeredfaillock --user usernameUnlock with: faillock —user username —reset

Objective: Configure and test password policies.

Terminal window
# 1. Check current password aging rules
chage -l username
# 2. Configure password complexity (e.g., via pam_pwquality)
# vi /etc/security/pwquality.conf
# minlen = 14
# minclass = 3
# 3. Check faillock status
faillock

  1. Configure PAM to enforce a 14-character minimum password length and prevent using the last 5 passwords.
  2. Use chage to force a user to change their password on their next login.

  • pam_pwquality enforces password complexity.
  • pam_faillock protects against brute-force attacks by locking accounts.
  • chage manages password expiration and aging policies.
  • NIST now recommends long passphrases and removing arbitrary rotation requirements.

  • NIST SP 800-63B (Digital Identity Guidelines)
  • man chage, man pam_pwquality


Last Updated: July 2026