The most surprising thing about enforcing password policies on Linux is that the system designed to handle it, PAM, is intentionally designed to be flexible, meaning there’s no single "on" switch for all policies.
Let’s see it in action. Imagine a user, alice, trying to change her password to something weak, like password.
[alice@server ~]$ passwd
Changing password for alice.
(current) UNIX password:
(new) :
(re-type) :
Sorry, passwords do not match
[alice@server ~]$ passwd
Changing password for alice.
(current) UNIX password:
(new) :
(re-type) :
Sorry, password rejected - it is too simple.
The passwd command itself doesn’t enforce anything. It’s a front-end that talks to the Pluggable Authentication Modules (PAM) system. PAM is the real enforcer.
The configuration for PAM lives in /etc/pam.d/. For password changes, the relevant file is usually /etc/pam.d/passwd. Let’s look at a typical entry for passwd:
#%PAM-1.0
auth required pam_env.so
auth sufficient pam_unix.so nullok try_first_pass
auth requisite pam_deny.so
auth required pam_shells.so
account required pam_unix.so
password requisite pam_cracklib.so retry=3 minlen=8 dcredit=-1 ucredit=-1 ocredit=-1 lcredit=-1 difok=3
password required pam_unix.so obscure sha512 shadow
This file tells the passwd command, in order, what modules to run for authentication (auth), account management (account), and password management (password).
The password section is where the magic for policy happens.
password requisite pam_cracklib.so retry=3 minlen=8 dcredit=-1 ucredit=-1 ocredit=-1 lcredit=-1 difok=3
password: This line applies to the password management phase.requisite: This is a control flag. Ifpam_cracklib.sofails, the entire module stack fails immediately. It’s stronger thanrequired.pam_cracklib.so: This is the module that actually checks the password against various policy rules.retry=3: Allows the user up to 3 attempts to enter a valid new password.minlen=8: The password must be at least 8 characters long.dcredit=-1: Requires at least one digit.-1means one or more.ucredit=-1: Requires at least one uppercase letter.ocredit=-1: Requires at least one other special character.lcredit=-1: Requires at least one lowercase letter.difok=3: The new password must differ from the old password by at least 3 characters.
If alice tries P@sswOrd1, it meets the minlen=8 and dcredit=-1 and ucredit=-1 and ocredit=-1 requirements. If her old password was oldpassword, and P@sswOrd1 differs by more than 3 characters, it would pass.
The password required pam_unix.so obscure sha512 shadow line then handles the actual hashing and storing of the password in /etc/shadow. obscure means the user won’t see the password they type, sha512 specifies the hashing algorithm, and shadow means it uses the shadow password file.
This modularity is key. You can add or remove modules, or change their parameters, to tailor your password policies precisely. For instance, to enforce a policy that requires at least two digits and disallows dictionary words, you might adjust the line to:
password requisite pam_cracklib.so retry=3 minlen=10 dcredit=-2 ucredit=-1 ocredit=-1 lcredit=-1 difok=5
This increases the minimum length to 10, requires two digits (dcredit=-2), and makes the password differ by at least 5 characters. The pam_cracklib.so module also has a dict=/etc/security/pwquality.conf option which allows for more granular control over disallowed words and character types.
The one thing most people don’t realize is that the pam_cracklib.so module’s effectiveness is heavily reliant on the pwquality library and its configuration file, /etc/security/pwquality.conf. While pam_cracklib.so takes arguments directly on the command line within the PAM configuration, pwquality.conf provides a persistent, centralized place for defining rules like minlen, dcredit, ucredit, lcredit, ocredit, difok, maxrepeat, gecoscan, enforce_for_root, and badwords. If you’ve set parameters in the PAM config, they often override the pwquality.conf settings for that specific PAM service, but pwquality.conf acts as a sensible default.
Once you’ve configured PAM, the next step is often to integrate password expiration and aging policies, which are also managed through PAM but leverage different modules like pam_unix.so with specific password aging arguments.