PAM Authentication Modules: Fundamentals of Login Control
AI generated
$
/etc
Linux · PAM · Authentication
PAM authentication modules in detail
how Linux decides who gets to log in

Behind every login on Linux, whether via SSH, sudo or a local console, sits a configurable stack of authentication modules. PAM fully decouples applications from the concrete authentication logic and makes it possible to set up login lockouts, password policies and two factor procedures without changing a single line in the application itself.

15 min read PAM Stack · Control Flags · pam_unix · pam_faillock Linux-PAM · Debian · Ubuntu · RHEL

1. What PAM is and why it exists

PAM, Pluggable Authentication Modules, is an abstraction layer that decouples applications like sshd, sudo or login from the concrete implementation of authentication. Instead of every application bringing its own logic for password checks, account lockouts or two factor procedures, it simply calls the PAM library, and PAM decides based on a configuration file which modules get checked in which order. This decoupling was first introduced on Solaris and is today the standard on practically every Linux distribution as Linux-PAM.

The practical benefit becomes obvious immediately when introducing a new security measure: an administrator who wants to introduce account lockouts after multiple failed attempts for SSH does not need to change a single line in sshd itself, but merely adjusts the associated PAM configuration file. Depending on the configuration, the same change affects login, su or sudo simultaneously, because all these programs use the same PAM mechanism.

Historically, PAM was designed in 1995 by Sun Microsystems for Solaris, with the explicit goal of extracting authentication logic out of individual applications and moving it into reusable, swappable modules. Linux adopted this concept shortly after as its own implementation called Linux-PAM, which today ships with practically every major distribution and has by now grown far beyond the original Solaris specification, for example with modules for two factor authentication or biometric procedures.

On Debian and Ubuntu based systems, PAM is maintained through the package libpam-runtime, on RHEL based systems through pam itself, in both cases with the tool pam-auth-update or authselect respectively, which consistently updates shared profiles for multiple services. Anyone maintaining PAM exclusively by manually editing individual pam.d files without using these tools risks a later package update overwriting the manual changes, because package managers update the configuration files they manage during upgrades.

2. The PAM stack structure: auth, account, password, session

Every PAM configuration is organized into four functionally separated management groups. The auth group checks whether the presented credentials are actually correct, for example through password comparison or querying a second factor. The account group independently checks whether the account is currently even authorized to log in at all, for example whether it is not expired, locked, or time restricted. The password group only comes into play during a password change and checks new passwords against policies. The session group finally runs when setting up and tearing down a session, for example to set environment variables or log logins.

These four groups are deliberately independent of each other. A module in auth can successfully validate a password while a module in account still denies the login, for example because the account is outside its permitted time window. This separation allows fine grained control: password checking, account status checking and session management can be configured and swapped completely independently of one another, without affecting the other areas.


# Inspect which PAM service file handles a given application
cat /etc/pam.d/sshd | grep -v '^#'

# Each line has the shape: <group> <control-flag> <module> [arguments]
# auth    required   pam_env.so
# auth    [success=1 default=ignore] pam_unix.so nullok_secure
# account required   pam_unix.so
# password sufficient pam_unix.so obscure sha512
# session required   pam_limits.so

3. Control flags: required, requisite, sufficient, optional

Every line of a PAM configuration carries, besides group and module, a control flag that determines how the result of this module affects the overall outcome of the stack. required means the module must succeed, but a failure only leads to an overall failure after evaluating all further modules of the same group, which prevents an attacker from drawing conclusions from the timing of the abort. requisite behaves similarly strictly but aborts immediately on failure, without checking further modules of the same group.

sufficient means success of this module is enough to count the entire group as successful, provided no prior required module already failed, but on failure it is simply skipped and evaluation continues with the next module. optional finally only influences the overall result if it is the only module in the group, in practice it is mostly used for modules that merely supply additional information, such as setting environment variables, without deciding success or failure of the login.


# /etc/pam.d/sshd — excerpt illustrating control-flag semantics
# 1. Try key-based/2FA module first, sufficient to succeed alone
auth    sufficient   pam_google_authenticator.so nullok
# 2. Fall back to standard Unix password check, must also succeed
auth    required     pam_unix.so try_first_pass
# 3. requisite: abort immediately if the account is locked out
account requisite    pam_faillock.so
# 4. required: account must not be expired, checked regardless
account required     pam_unix.so

4. Key modules at a glance

The module pam_unix.so is the most fundamental PAM module and checks credentials against /etc/passwd and /etc/shadow, covering classic Unix password authentication, and appears in practically every auth and account configuration. The module pam_faillock.so counts failed login attempts per user and locks the account for a configurable time after a configurable number of failed attempts, a direct alternative to external tools like fail2ban, though at the account level rather than the network level.

The module pam_limits.so sets resource limits for a session based on /etc/security/limits.conf, such as the maximum number of open files or processes per user. The module pam_env.so sets environment variables from /etc/security/pam_env.conf at session start. For two factor authentication, pam_google_authenticator.so is used, checking time based one time passwords following the TOTP standard. Each of these modules can be combined independently, which makes PAM an extremely flexible toolkit.

For PHP-FPM and database workloads on production servers, pam_limits.so is especially practically relevant, because without clean limits a single user process can consume all available file descriptors of the system during a sudden traffic spike and thereby impair other services on the same server. An explicit limit through limits.conf prevents exactly this scenario without the application code itself having to know anything about it.


# /etc/security/limits.conf — resource limits enforced by pam_limits.so
# <domain>  <type>  <item>       <value>
www-data    soft    nofile        65536
www-data    hard    nofile        65536
www-data    soft    nproc         4096
deploy      hard    nproc         2048

5. Reading and understanding /etc/pam.d/ files

Every application using PAM has its own file under /etc/pam.d/, named after the application's so called service name, for example /etc/pam.d/sshd or /etc/pam.d/sudo. Many of these files include shared configuration files like /etc/pam.d/common-auth through the @include common-auth directive to avoid redundancy when the same basic configuration should apply to multiple services. In practice this means a change to common-auth simultaneously affects all services that include this file, which ensures consistent security policies but can also have unexpected side effects on other services with careless changes.

The order of lines within a group is decisive, because PAM evaluates them strictly from top to bottom. A sufficient module accidentally placed before a necessary required module can cause a login to report success even though a later, actually mandatory check is never reached. The rule therefore is to only change PAM configuration files with full understanding of the ordering and to always test changes first in a second, parallel open root session before ending the current session.

6. Practical example: login lockout after failed attempts with faillock

The file /etc/security/faillock.conf centrally controls the behavior of pam_faillock.so, without having to clutter the module line in every single /etc/pam.d/ file with arguments. The directive deny sets after how many failed attempts an account gets locked, unlock_time sets the lockout duration in seconds, and fail_interval defines the time window within which failed attempts are counted. This central configuration file has been the recommended approach since newer versions of pam_faillock, over the older practice of writing arguments directly into the PAM lines.

A locked account can be inspected with faillock --user username and unlocked early with faillock --user username --reset, which is especially useful when a legitimate user accidentally locked themselves out, for example through repeatedly mistyped passwords after a system change. It is important to exempt the root user from this lockout by default, or at least keep an alternative access path open, so as not to permanently lock yourself out of a server.


# /etc/security/faillock.conf — central faillock configuration
deny = 5
unlock_time = 900
fail_interval = 600
even_deny_root
root_unlock_time = 60

# /etc/pam.d/common-auth — enable faillock in the auth stack
auth required pam_faillock.so preauth
auth [success=1 default=ignore] pam_unix.so
auth [default=die] pam_faillock.so authfail
auth sufficient pam_faillock.so authsucc

7. Two factor authentication with pam_google_authenticator

The package libpam-google-authenticator provides a PAM module that checks time based one time passwords following the TOTP standard, compatible with common authenticator apps. Every user runs google-authenticator once, which stores a secret key in ~/.google_authenticator and outputs a QR code to scan. The module is then hooked into the respective auth group, typically combined with pam_unix.so, so a successful login requires both the password and the time limited code.

A critical configuration decision concerns the SSH server configuration itself: ChallengeResponseAuthentication yes in /etc/ssh/sshd_config must be set for OpenSSH to allow the PAM conversation for the second factor at all, and this setting must be active together with UsePAM yes. If either of these settings is missing, the PAM module never gets invoked, even if the PAM configuration file itself is correct, a mistake that in practice leaves many administrators searching in the wrong place for hours.

8. Debugging PAM problems

Another useful tool is pamtester, which allows testing individual PAM services in isolation from the actual application, for example pamtester sshd username authenticate, to check whether authentication for a given service fundamentally works without actually having to establish an SSH connection. This considerably shortens the feedback loop when testing configuration changes, since no full connection setup is required.


# Test a specific PAM service in isolation, without a real SSH connection
sudo pamtester sshd deployuser authenticate

# Check whether an account is currently locked by faillock
faillock --user deployuser

# Watch PAM related log entries live while reproducing a login issue
sudo journalctl -f | grep -i pam

# Temporarily enable verbose debug output for a single module
# (add "debug" as an argument to the module line in the pam.d file first)
sudo journalctl -f -u sshd

The most important debugging channel for PAM is the system log, viewable via journalctl -u sshd or more generally through journalctl | grep pam. Many modules additionally support a debug argument directly in the PAM configuration line, which writes considerably more detailed messages to the log, such as which specific module rejected a login and for what reason. This option should only be enabled temporarily in production, because it potentially logs sensitive details such as usernames on failed attempts.

A common debugging mistake is editing a PAM configuration file directly and closing the current SSH session before the change has been tested. If the new configuration is broken, nobody can log in via SSH anymore, not even the administrator themselves. The safe practice is therefore to keep a second root session open in a separate terminal before any change, and only consider the change complete after a successful test login from a new session.

An additional safety net is a scheduled, delayed rollback: a job set up via cron or a systemd timer that automatically restores the previous version of the pam.d file after five minutes, unless manually cancelled, prevents a permanent lockout even if the second root session was unavailable for some reason. This pattern is used by default in many automation tools for configuration changes to security critical services.

Module Management Group Purpose Configuration File
pam_unix.so auth, account, password Classic Unix password check /etc/shadow
pam_faillock.so auth, account Lockout after failed attempts /etc/security/faillock.conf
pam_limits.so session Resource limits per session /etc/security/limits.conf
pam_google_authenticator.so auth TOTP two factor check ~/.google_authenticator

9. Modules compared and ordering pitfalls

The table above shows that different modules deliberately serve different management groups and therefore act at different points in the login flow. A common configuration mistake is accidentally entering an account module like pam_faillock.so only in the auth group, which causes the lockout check to be skipped for already successfully authenticated but locked accounts, because account modules are evaluated independently from auth modules.

Equally critical is the order within the same group: a sufficient module for two factor authentication placed before the lockout check can cause a correctly entered second factor to complete the entire auth stack as successful before pam_faillock.so was even checked. The robust order consistently places lockout checks before any actual credential check, as shown in the example with preauth in the previous section.

Another point of comparison concerns maintainability: modules like pam_unix.so and pam_limits.so need almost no upkeep once correctly set up, while pam_faillock.so and pam_google_authenticator.so require regular attention, for example to catch accidentally permanently locked accounts or expired TOTP secrets after a device change. Anyone running PAM in production should therefore periodically check with faillock --user and a look into journalctl whether the configured modules actually behave as intended.

Mironsoft

Linux server hardening and login security for PHP hosting

Login control that matches your security policy?

We set up faillock lockouts, two factor authentication and password policies via PAM, review existing pam.d configurations for ordering mistakes, and document every change traceably.

PAM Audit

Review of existing pam.d files for control flag and ordering mistakes

Two Factor Setup

TOTP based two factor authentication for SSH and sudo

Brute Force Protection

faillock configuration with a safe exclusion for emergency access

10. Summary

PAM decouples applications from concrete authentication logic through a configurable stack of four management groups: auth, account, password and session. Control flags like required, requisite, sufficient and optional control how the result of a single module affects the overall outcome, and the order of lines within a group is decisive for the actual behavior.

Modules like pam_unix.so, pam_faillock.so and pam_google_authenticator.so cover the most common practical requirements: password checking, lockout after failed attempts and two factor authentication. Anyone changing PAM configurations should always keep a second root session open until the change has been successfully tested, because a mistake in the PAM configuration can block the entire login access to a server.

PAM Authentication Modules: The Key Facts at a Glance

Stack Structure

Four independent groups: auth, account, password, session. Each checks its own question.

Control Flags

required, requisite, sufficient and optional control how module results determine the overall outcome.

Key Modules

pam_unix.so for passwords, pam_faillock.so for lockouts, pam_google_authenticator.so for two factor.

Safe Testing

Always keep a second root session open before considering a PAM change complete.

11. FAQ: PAM Authentication Modules

1What is PAM?
Decouples applications from concrete authentication logic through configurable modules.
2auth vs. account?
auth checks credentials, account independently checks the account's login eligibility.
3What does sufficient mean?
Success is enough for the group, failure just moves on to the next module.
4Set up an account lockout?
Configure pam_faillock.so via faillock.conf and add it to the auth group.
5Unlock an account?
faillock --user username --reset lifts the lockout immediately.
6Two factor over SSH?
libpam-google-authenticator, a PAM line, plus ChallengeResponseAuthentication yes and UsePAM yes.
7Module never invoked?
Often an application setting like ChallengeResponseAuthentication yes is missing.
8Debug PAM problems?
journalctl -u sshd and the debug argument in the PAM line give details.
9Avoid locking myself out?
Always keep a second root session open until the change has been successfully tested.
10Wrong order, what happens?
A sufficient module before a lockout check can bypass it entirely.