Enable password age and complexity for production Linux servers for auditing

Jephe Wu - http://linuxtechres.blogspot.com

Objective: Enable password age and complexity for production Linux servers for auditing
Environment: CentOS 5


Steps:
1. modify /etc/login.defs

PASS_MAX_DAYS    60
PASS_MIN_DAYS    7 (days between password change)
PASS_MIN_LEN    8
PASS_WARN_AGE    28


2. make sure the following appears in /etc/default/useradd
INACTIVE=-1
EXPIRE=

note: this will disable password inactivity settings, INACTIVATE sets the number of days of inactivity after a password has expired before the account is locked. Normally, we don't set it by useradd or chage.

3. change the existing user password ages
chage -m 7 -M 60 -W 28 jephe
chage -m 7 -M 60 -W 28 user1

note: some other useful commands:
chage -l jephe
chage -d 0 jephe
(to immediately make the password expire so that the user has to change password upon login next time,
chage -d -1 jephe (to make password not expired)

If you encounters the following issues after password expiry, you might need to change ssh configuration

UsePrivilegeSeparation from yes to no, seems openssh 3.8 and above has already fixed 
this issue


$ ssh jephe@servername
jephe@servername's password:
You are required to change your password immediately (password aged)
Your password has expired, the session cannot proceed.
Connection to localhost closed.


passwd -l jephe (lock user)
passwd -u jephe (unlock user)
usermod -L jephe
usermod -U jephe



note: How do I force users to change their passwords upon the first login?

1.) Firstly, lock the account to prevent the user from using the login until the change has been made:
# usermod -L jephe
# chage -d 0 jephe  (make password expiry immediately)
# usermod -U jephe   (unlock user account)


or
According to Redhat knowledge base, you can directly push a encrypted password string to /etc/shadow. 

run command 'python', the salt can be a combination of exactly 2 upper or lower case alphabetic characters, digits, the dot (.) character, or the slash (/) character such as cd or 34
  • import crypt; print crypt.crypt("password","salt")
      
    The output is the encrypted password similar to 
        15CsBd8FAc9DN


  • ctrl -d to exit python
  • usermod -p "15CsBd8FAc9DN" jephe


or you might set a empty password:

usermod -p "" jephe 

4. enable password complexity

make sure /etc/security/opasswd exists, otherwise, create it:

touch /etc/security/opasswd
chown root:root /etc/security/opasswd
chmod 600 /etc/security/opasswd


note: opasswd maintains a list of old passwords for every user prohibiting the reuse of old passwords. The list is located in the /etc/security/opasswd file. This is not a plain text file, but should be protected the same as the /etc/shadow file. This is normally referred to as password history.


vi /etc/pam.d/system-auth to make it looks like this:
password    requisite     pam_cracklib.so try_first_pass retry=3 minlen=8 lcredit=-1 ucredit=-1 dcredit=-1 ocredit=-1 difok=3
password    sufficient    pam_unix.so md5 shadow nullok try_first_pass use_authtok remember=6


note: minimum 8 characters, 1 lowercase, 1 upper case, 1 number, 1 special character, the new password must have 3 characters which are different with the previous one, remember the last 6 passwords which cannot be used for new password.

According to my test, you have to use  lcredit=-1 ucredit=-1 dcredit=-1 ocredit=-1, not lcredit=1 ucredit=1 dcredit=1 ocredit=1, otherwise, it doesn't actually enforce that which mentioned above.


5. References

a. Securing and Hardening Red Hat Linux Production Systems- http://www.puschitz.com/SecuringLinux.shtml
b. Linux Password Policy - http://www.brandonhutchinson.com/wiki/Linux_Password_Policy
c. redhat acknowledge base -  doc7382