linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
  • Introduction
  • Lessons
  • How it works
  • Simulator
  • Knowledge base
  • Interview prep
Index
Categories
All entries
Footer
linuxlab-TutorialsPricingAboutPrivacy & cookies
Copyright © 2026 LinuxLab. All rights reserved.
home/linux/kb/Security/pam

kb/security ── Security ── advanced

PAM: Pluggable Authentication Modules

PAM is the authentication framework in Linux. Programs (sudo, login, sshd) do not check passwords themselves. They call PAM, which decides whether to let you in through a stack of modules in `/etc/pam.d/<service>`.

view as markdownaka: pluggable-authentication-modules, pam-d, pam-conf

Why PAM exists

Without PAM, every application read /etc/passwd and /etc/shadow directly. To add LDAP, Kerberos, 2FA, or fail-after-N-attempts you would have to patch EVERY program. PAM solves this by moving the logic into a shared library and a stack of modules.

user → ssh login
          ↓
sshd calls pam_authenticate("sshd")
          ↓
PAM reads /etc/pam.d/sshd
          ↓
Module stack, one by one:
  pam_unix.so   → check /etc/shadow
  pam_faillock.so → failure counter
  pam_google_authenticator.so → 2FA
          ↓
"authenticated" / "failed" → return to sshd

Where things live

  • /etc/pam.d/<service> holds configs for specific applications (one per service: /etc/pam.d/sshd, /etc/pam.d/sudo, /etc/pam.d/login).
  • /etc/pam.d/other is the fallback for applications without their own config. The default is paranoid: deny everything. Do not change it to permissive.
  • /lib64/security/*.so (RHEL/Fedora) or /lib/x86_64-linux-gnu/security/*.so (Debian/Ubuntu) are the modules themselves.
  • /etc/security/*.conf holds configs for individual modules (limits.conf, faillock.conf, and so on).

The service name equals the file name in /etc/pam.d/. When sudo calls PAM, /etc/pam.d/sudo is read.

Config line syntax

type   control   module   [arguments]

Example from /etc/pam.d/sshd:

auth     required   pam_env.so
auth     substack   password-auth
account  required   pam_nologin.so
session  required   pam_loginuid.so
password include    system-auth

The four type values (what you check)

typeWhat it does
authChecks who you are (password, token, biometrics)
accountWhether you may log in right now (user not locked, not expired, in the right group)
passwordPassword change (called on passwd/chpasswd)
sessionWhat to do before/after login: mounting home, limits, audit

One service file usually contains all four types. PAM runs only the type needed by the calling application.

Control flags (what to do with a module result)

flagBehavior on successBehavior on fail
requiredcontinue the stackreturn fail AT THE END of the stack (deferred)
requisitecontinue the stackexit with fail IMMEDIATELY (do not run further)
sufficientexit with success IMMEDIATELY (if no required-fail happened before)continue the stack
optionalcontinue the stackcontinue the stack, fail is ignored
includeinsert the whole stack from another filesame
substacklike include, but isolates the "done" flag for the returnsame

The key difference between required and requisite: both demand success, but requisite fails instantly. You use this when you need to avoid showing the next prompt (if the username does not exist, do not ask for a password).

sufficient skips the rest of the stack on success, a common pattern for "either a key or a password":

auth sufficient pam_unix.so          # password succeeds → let in
auth required   pam_deny.so          # otherwise fallback fail

The most common modules

ModuleWhat it does
pam_unix.soChecks /etc/passwd + /etc/shadow (the standard)
pam_pwquality.soPolicy for a new password (length, classes, dictionary)
pam_faillock.soLockout after N failed attempts (was pam_tally2)
pam_nologin.soIf /etc/nologin exists, allows only root
pam_limits.soApplies /etc/security/limits.conf (ulimits)
pam_loginuid.soWrites the audit uid to /proc/self/loginuid
pam_mkhomedir.soCreates ~/ on first login (LDAP users)
pam_env.soLoads env from /etc/environment
pam_succeed_if.soConditional skip: "if uid >= 1000"
pam_selinux.soSets the SELinux context for the session (see selinux-apparmor)
pam_systemd.soCreates user.slice / XDG_RUNTIME_DIR
pam_google_authenticatorTOTP 2FA

The shared stack: common-auth / system-auth

So you do not duplicate the same modules in every pam.d/<service>, there are shared files:

  • Debian/Ubuntu: /etc/pam.d/common-{auth,account,password,session}, pulled in via @include common-auth.
  • RHEL/Fedora: /etc/pam.d/system-auth, password-auth, pulled in via auth substack system-auth.

To change global behavior (for example, requiring 2FA for all console logins), edit the shared file, not each service.

Typical cases

Lock a user after 5 failed attempts

# /etc/pam.d/system-auth (RHEL) or /etc/pam.d/common-auth (Debian)
auth required pam_faillock.so preauth silent deny=5 unlock_time=900
auth sufficient pam_unix.so
auth [default=die] pam_faillock.so authfail deny=5 unlock_time=900
account required pam_faillock.so

Check: faillock --user serge. Reset: faillock --user serge --reset.

Strengthen passwords: minimum 12 chars, 3 classes

# /etc/security/pwquality.conf
minlen = 12
minclass = 3

Applied through pam_pwquality.so, which is already wired into the password stack.

Forbid root login over SSH

Not through PAM but through PermitRootLogin no in sshd_config. Through PAM, like this:

# /etc/pam.d/sshd, in the auth stack:
auth required pam_succeed_if.so user != root

Debugging: what to do when you break it

The main rule: NEVER edit a PAM config without a second root session open. If you break it, there will be no logins, including through sudo.

bash
# 1. Logs
sudo journalctl -t sshd -t sudo --since "10 min ago"
sudo tail -f /var/log/auth.log         # Debian
sudo tail -f /var/log/secure           # RHEL
# 2. Test without logging in again
sudo -k && sudo -v                      # drop the sudo cache and re-authenticate
# 3. Check that the module loads at all
ls /lib64/security/pam_unix.so          # or /lib/x86_64-linux-gnu/security/
# 4. Documentation for a specific module
man pam_faillock
man pam_unix

If you break it so badly you cannot log in, boot into single-user mode (kernel cmdline: systemd.unit=rescue.target) and fix the file.

A safe fallback for /etc/pam.d/<service>:

auth required pam_unix.so
account required pam_unix.so
password required pam_unix.so
session required pam_unix.so

This returns things to "the way they were before PAM": only /etc/shadow is checked.

§ команды

bash
sudo cat /etc/pam.d/sudo

The config for sudo: see which modules are in the authentication stack

bash
sudo journalctl -t sshd -t sudo --since '10 min ago'

Logs of the most recent PAM checks, the main debugging tool

bash
sudo faillock --user serge

How many failed attempts a user has, to find out why login is denied

bash
sudo faillock --user serge --reset

Reset the lockout counter after a password mistake

bash
man pam_unix

Documentation for a specific PAM module describing all of its arguments

§ см. также

  • sudosudo: run a command as root`sudo` runs a command as another user (usually root) under the rules in `/etc/sudoers`. The standard path for privilege escalation.
  • sshSSH: Secure ShellSSH is an encrypted channel to a remote host: shell, file copy, port-forwarding. Standard port 22, authentication by keys or password.
  • selinux-apparmorSELinux and AppArmor: Mandatory Access ControlSELinux and AppArmor are MAC: a control layer on top of normal permissions. They stop a process from doing anything outside its profile or type.
  • secrets-managementSecrets management: Vault, k8s Secrets, sealed-secretsKeep secrets out of git and out of env vars in code. Options: HashiCorp Vault (general purpose, dynamic creds), k8s Secrets (base64, needs encryption- at-rest), sealed-secrets (commit-friendly), external-secrets (sync from a cloud vault).
  • cis-benchmark-hardeningCIS Benchmark and system hardening (lynis, OpenSCAP)CIS Benchmark is the Linux hardening standard. Lynis is a fast local audit with a score, OpenSCAP is the formal one with XCCDF profiles and a SCAP report. ansible-lockdown remediates. Keep audit and remediate separate.
Footer
linuxlab-
Copyright © 2026 LinuxLab. All rights reserved.
Tutorials
Pricing
About
Privacy & cookies