Managing Credentials with passwd, Enforcing Expiration Policies with chage & Batch Updates with chpasswd
In any production Linux infrastructure, passwords represent the primary line of defense against unauthorized system access. Establishing robust credential hygiene requires more than simply setting passwords; it demands enforcing mandatory password rotation schedules, account expiration dates, complexity rules, and automated batch updates using Linux password tools.
The passwd command is a SetUID binary (owned by root with permissions -rwsr-xr-x) that enables regular users to safely update their own password hash in /etc/shadow without granting them direct read/write access to the file. When executed by root, passwd provides administrative controls:
| Option | Action | Syntax Example |
|---|---|---|
[username] |
Update password for specified user (prompts interactively) | sudo passwd alex |
-l |
Lock account password (prepends ! to hash in /etc/shadow) |
sudo passwd -l alex |
-u |
Unlock locked account password (removes leading !) |
sudo passwd -u alex |
-d |
Delete password (removes password requirement; allows passwordless login) | sudo passwd -d guest |
-e |
Expire password immediately (forces change on next login) | sudo passwd -e alex |
-S |
Display password status summary | sudo passwd -S alex |
sudo passwd -S alex
# Output: alex P 2026-11-02 0 90 7 -1
alex: The username.P: Status flag. P = Usable Password, L = Locked, NP = No Password.2026-11-02: Date password was last modified.0: Minimum password age in days.90: Maximum password age in days before mandatory change.7: Warning days before expiration.-1: Inactive grace period (-1 means disabled/never).While passwd handles daily changes, chage (Change Age) is the enterprise tool used by system administrators to audit and enforce organizational password compliance policies (e.g. PCI-DSS, SOC 2, ISO 27001).
sudo chage -l alex
# Last password change : Nov 02, 2026
# Password expires : Jan 31, 2027
# Password inactive : never
# Account expires : never
# Minimum number of days between password change : 0
# Maximum number of days between password change : 90
# Number of days of warning before password expires : 14
| Option | Policy Parameter | Syntax Example |
|---|---|---|
-M |
Maximum Password Age (force change every N days) | sudo chage -M 90 alex (expires every 90 days) |
-m |
Minimum Password Age (prevent changing password immediately) | sudo chage -m 7 alex (must wait 7 days before changing again) |
-W |
Warning Days (days prior to expiration user sees warning banners) | sudo chage -W 14 alex (warn user 14 days in advance) |
-I |
Inactivity Grace Period (days after expiration before account is locked) | sudo chage -I 30 alex (lock account if expired for 30 days) |
-E |
Account Expiration Date (absolute cutoff date YYYY-MM-DD) | sudo chage -E 2026-12-31 contractor |
-d 0 |
Set last change to Epoch 0 (forces change on next login) | sudo chage -d 0 alex |
Typing passwords interactively for hundreds of students or automated service accounts is tedious. The chpasswd (Change Password Batch) utility reads standard input formatted as username:password pairs and generates salted hashes automatically:
# 1. Update password for a single user via echo pipe
echo "alex:TempSecurePass2026!" | sudo chpasswd
# 2. Update multiple accounts from a secure batch list file
sudo chpasswd < /root/user_credentials.txt
# 3. Specify explicit SHA-512 cryptographic hashing algorithm (-c)
sudo chpasswd -c SHA512 < credentials.txt
Whenever passwords or aging policies are modified manually or via automation scripts, running pwck ensures no formatting errors were introduced:
# Audit user password files (read-only verification)
sudo pwck -r
Terminal Lab Exercise: Open your terminal and walk through setting, testing, and aging passwords on a test account:
# Step 1: Create a test account for lab practice
sudo useradd -m labuser
# Step 2: Set initial password using chpasswd
echo "labuser:InitialPass123" | sudo chpasswd
# Step 3: Inspect initial password status
sudo passwd -S labuser
sudo chage -l labuser
# Step 4: Enforce 60-day maximum age with a 10-day warning period
sudo chage -M 60 -W 10 labuser
# Step 5: Force the user to change password at next login
sudo passwd -e labuser
sudo chage -l labuser
# Notice "Last password change: password must be changed"
# Step 6: Clean up test account
sudo userdel -r labuser
echo "Password tools lab finished successfully!"
passwd binary executable has the SetUID permission bit set (-rwsr-xr-x) owned by root. When an unprivileged user executes passwd, the process runs with the effective privileges of root, allowing it to modify /etc/shadow securely on behalf of the user.
/etc/shadow to 0. Upon the user's next login, the system blocks access to the shell until the user successfully creates a new password.
-m) defines the number of days a user must keep a password before they are permitted to change it again (preventing users from immediately cycling back to an old favorite password). Maximum Password Age (-M) defines the maximum days a password remains valid before mandatory expiration.
!) to the encrypted hash string in the 2nd field of /etc/shadow. Because no valid cryptographic input hashes to a string starting with !, password authentication is disabled.
passwd -l only disables password-based authentication. If the user has SSH public key authentication configured in ~/.ssh/authorized_keys, they can still log in using their private key.
chpasswd automates batch password updates by consuming username:password records from standard input or files, encrypting them using system algorithms, and updating /etc/shadow in one pass.
/etc/shadow. This allows the user to log in without entering any password.
pam_pwquality (or legacy pam_cracklib) module configured in /etc/security/pwquality.conf, which enforces minimum length, uppercase, lowercase, numbers, and special characters.
sudo chage -E YYYY-MM-DD username. After that date, the account becomes locked regardless of password status.
passwd and press Enter. The system will prompt you for your current password first, then ask for your new password twice.
sudo chage -M 99999 username. Setting the maximum age to 99999 days effectively disables password expiration.
sudo passwd username. Root is not prompted for the old password and can reset the password directly.
/etc/shadow or run a bash loop checking chage -l for all users in /etc/passwd.