1. Overview

Password management is an important security measure for any Linux system. Without a secure password, unauthorized people can access the system, leaving it vulnerable to malicious attacks. It’s therefore essential to define password policies that force the user to consider a complex one that is difficult to guess or crack.

In this tutorial, we’ll learn how to set up a firm password policy. We’ll focus mainly on the PAM (Pluggable Authentication Modules) and its related configuration files.

2. Setting PAM Modules

The Linux Pluggable Authentication Modules (PAM) library suite provides a Linux system administrator with techniques for authenticating users. It facilitates the swapping of authentication methods between secure applications flexibly and centrally by using configuration files rather than rewriting application code.

PAM combines multiple low-level authentication modules into a high-level API that provides dynamic authentication support for applications.

This tool distributes authentication functions across four different management groups, including a password management group, as well as the account, authentication, and session groups. Depending on the desired policy, these groups support a variety of PAM modules.

The configuration file for PAM is /etc/pam.conf and it includes the general behavior of the PAM suites. The directory /etc/pam.d contains a dedicated configuration file for each application that uses PAM.

The common syntax of those files contains a list of rules formatted as follows:

group-type   control-flag   module module-arguments 

For each line there is :

  • group-type: the authentication management group type (auth, account, password, and session)
  • control-flag: the PAM-API behavior if the module’s authentication task fails (requisite, required, sufficient, and optional)
  • module: the PAM module in question
  • module-flag: the options defining the module behavior

To manage password complexity there are /etc/pam.d/common-password and /etc/pam.d/system-auth files used respectively for Debian and Red Hat-based systems.

By default, here’s how /etc/pam.d/system-auth looks like:

auth        required      pam_env.so
auth        sufficient    pam_fprintd.so
auth        required      pam_deny.so
<...>
account     required      pam_unix.so
account     sufficient    pam_localuser.so
<...>
password    requisite     pam_cracklib.so try_first_pass retry=3 type=
password    sufficient    pam_unix.so md5 shadow nullok try_first_pass use_authtok
password    required      pam_deny.so

session     optional      pam_keyinit.so revoke
session     required      pam_limits.so
<...>

Many PAM modules are involved when managing password policies, such as pam_cracklib, pam_unix, pam_tally2, and pam_pwhistory

3. Setting Password Policy

According to the NIST password guidelines, password strength is primarily determined by password length. For this reason, many organizations are imposing that passwords are a complex mix of at least 12 to 16 characters. Additional settings, such as managing the password history, password lock and unlock, and aging data, are also frequent.

The tests in the following parts are executed in an Ubuntu 16 operating system. Therefore, we’ll use for the most part the file /etc/pam.d/common-password.

3.1. Password Quality

Generally speaking, the quality of a password is measured by its minimum length and the use of different sorts of characters (upper, lower, digit, and other). The module pam_cracklib supports both these laters as well as additional tests.

For Debian-based distribution, we use the command line tool apt to install the module pam_cracklib as follows:

$ sudo apt-get install libpam-cracklib

By default, pam_cracklib performs basic checks. It starts with checking if it’s a dictionary word. If it’s not the case, the process moves along to checking for palindromes, rotated passwords, reversed characters, or the same password with only a case change.

Let’s see the most common options to use with this module:

  • minlen=n: defines the minimum password length
  • dcredit=n: impose at most n digits when positive, and at least n digits when negative
  • ucredit=n: impose at most n uppercase letters when positive, and at least n uppercase letters when negative
  • lcredit=n: impose at most n lowercase letters when positive, and at least n lowercase letters when negative
  • ocredit=n: impose at most n special characters when positive, and at least n special characters when negative

In /etc/pam.d/common-password, we just append a line to the password management group. The example below allows forcing a password that contains at least: nine characters, one upper case letter, two digits, and one other character:

password   required   pam_cracklib.so retry=3 minlen=9 ucredit=-1 ocredit=-1 dcredit=-2

Here, the option retry=3 allows the user to enter the password at least three times before having an error. The default value of retry is 1.

The module pam_cracklib offers extra options to perform additional checks, including:

  • difok=n: defines the number of character changes in the new password, the default value is 5
  • minclass=n: imposes at least n characters from each of the four character classes
  • maxrepeat=n: rejects passwords that contain more than n similar consecutive characters; n=0 by default
  • maxsequence=n: accepts no more than n monotonic character sequences, such as “1234” or “abcd“; by default n=0 meaning that the option is disabled
  • reject_username: rejects a password that contains the username in straight or reversed form

3.2. Password History

Many users tend to have a bunch of passwords to alternate between them too frequently. It’s possible in Linux systems to prevent reusing old passwords by saving them in a dedicated location (/etc/security/opasswd).

By using the pam_unix module, we just append the following line in /etc/pam.d/common-password:

password   required   pam_unix.so sha512 shadow remember=40

The option remember=40 saves for each user the last 40 passwords to force password changes.

There’s also pam_pwhistory, a dedicated PAM module to replace the password history functionality implemented by pam_unix. It works with the same option (remember) and syntax as pam_unix. It supports also other functions such as customizing the location where to archive passwords (file=/path/filename) and prompting the user n times before returning an error(retry=n).

3.3. Lockout on Failure

Due to brute-force attacks, it’s imperative to implement a “lockout on failure” functionality. This is implemented by the pam_tally2 module in Linux systems. This module keeps track of access attempts, reset the count on success, and block access after a given number of failed attempts.

On top of /etc/pam.d/common-password, with the authentication management group, we add the following line:

auth   required   pam_tally2.so deny=3 unlock_time=3600 even_deny_root

This setting locks accounts after three failed attempts (deny=3) and automatically unlocks them an hour later (unlock_time=3600 in seconds). The admin can manually remove the lock if unlock_time is not specified.

The option even_deny_root locks also the root account.

3.4. Password Aging

The file /etc/login.defs contains the default settings for newly created accounts including those related to passwords. In this file, we can set parameters like minimum password age, expiration date (maximum age), and warning period:

# Password aging controls:
[...]
PASS_MAX_DAYS   30
PASS_MIN_DAYS   0
PASS_MIN_LEN    5
PASS_WARN_AGE   5

Managing this type of data is also supported by commands like chage to modify aging details and passwd to define/update the password itself.

4. Conclusion

In this article, we learned firstly the basic syntax of the PAM authentication tool. Then we saw different approaches using the PAM module to enforce a complex password in Linux systems.

To conclude, password policies are one of the pillars of system security. Considering a strong one is inevitable to prevent unauthorized access.