Configure pam_faillock Without Locking Yourself Out
pam_faillock counts failed logins and locks an account past a threshold you set, and a wrong ordering can lock out an administrator too. By the end you will have a bounded policy in place, using settings documented by the installed Linux-PAM 1.5.3-5ubuntu5.7 package, and know how to inspect or reset a tally.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about 15 minutes for a careful review. You need root access, a second administrative session or console, and a service whose PAM stack you already understand. This is security-sensitive work: a syntax or ordering error in PAM can deny logins, including administrative ones.
1. Establish the current state
Identify the service you intend to protect first. Do not copy a login example into every PAM file: SSH, local login, a display manager and sudo can each run different stacks.
dpkg-query -W -f='${Package} ${Version}\n' libpam-modules:amd64
sudo sed -n '1,220p' /etc/security/faillock.conf
sudo faillock --user USERNAME
The configuration file may be absent or empty, which is fine. The faillock command prints the recorded failures for the named user when a tally exists; an empty result is a useful baseline. Swap in a real account name for USERNAME. The utility accepts --dir, --user, --reset and --legacy-output, but no general --help on this installation.
Checkpoint
Keep a root shell or console session open while you change PAM, and confirm you know the target service, the installed package version, and the current tally directory.
2. Choose a bounded policy
Put policy in /etc/security/faillock.conf. Module command-line options can override this file, but the installed manpage recommends the configuration file over placing policy on each PAM line.
The following policy records four consecutive failures inside the default 15-minute window and unlocks the account automatically after 20 minutes. silent suppresses any hint of a locked account during the pre-authentication check.
deny=4
unlock_time=1200
silent
- These values are an example, not a universal answer. A low
denycan itself be used for denial of service against a real account. - Root is normally exempt from being blocked. Enabling
even_deny_rootchanges that, and deserves its own recovery plan. - Tally files usually live under
/var/run/faillock/. That can be temporary storage. If failures must survive a reboot, set a persistentdir=in this file with ownership and permissions to match.
3. Back up and edit the policy
Make a root-only backup before changing the file. This command works whether the file already exists or not.
sudo cp -a /etc/security/faillock.conf /etc/security/faillock.conf.bak
sudoedit /etc/security/faillock.conf
Replace or merge the relevant settings, keeping unrelated site policy intact. Then check the result:
sudo sed -n '1,220p' /etc/security/faillock.conf
There is no separate daemon to restart for this file. Recovery: undo the change before testing with sudo cp -a /etc/security/faillock.conf.bak /etc/security/faillock.conf. Do not delete tally files as a first response; reset a named account only after confirming which account is affected.
4. Verify the PAM stack
The policy file only supplies options. The PAM service still has to call pam_faillock.so in the right positions. The installed manpage describes three arguments:
preauthchecks whether a user is already blocked before a credential module asks for a password. Optional whenauthsuccis used.authfailrecords a failure after the authentication module has already returned one.authsuccclears the recorded failures after successful authentication, unless the user is already blocked.
A representative sequence looks like this. Adapt it to the existing service file and its control flags; the surrounding modules matter, so do not swap a complete distribution-managed PAM file for this fragment.
auth required pam_faillock.so preauth
auth sufficient pam_unix.so
auth [default=die] pam_faillock.so authfail
auth sufficient pam_faillock.so authsucc
auth required pam_deny.so
The account phase can also call pam_faillock.so, but the manpage warns that the auth stack has to run first or its reset logic is skipped intentionally. Security warning: a pre-auth call without silent, or one using a requisite control field, can reveal whether a username exists. Treat that as an account-enumeration risk, not a cosmetic choice.
After editing a service file, review it as root and test the target service from the second session. There is no universal PAM syntax checker here, so a successful controlled authentication and a still-working administrative session are the checks that actually matter.
5. Inspect and recover a tally
Check a user before deciding whether a lock is expected:
sudo faillock --user USERNAME
To clear that user's recorded failures, use the explicit reset:
sudo faillock --user USERNAME --reset
sudo faillock --user USERNAME
The second command should show nothing remaining for that user. Security boundary: resetting is a privileged action because it removes the evidence and lets authentication proceed again. Record why you did it, and never use a blanket reset when only one account is affected.
If a legitimate user is locked, automatic recovery follows unlock_time when it is set. If the tally disappears after a reboot, check whether /var/run/faillock is mounted as temporary storage and whether you meant to set a persistent dir=. If the service now rejects every login, use the open root session or console to restore faillock.conf.bak, repair the service's PAM file, and test again before closing that session.
Done means
- Version and target recorded: the installed
libpam-modulesversion and target PAM service are noted. - Policy set:
/etc/security/faillock.confholds the intended threshold and lock duration. - Stack ordered correctly: the service calls
preauth,authfailand, where appropriate,authsuccconsistent with its existing stack. - Recovery session live: a second session or console remains usable.
- Reset tested:
sudo faillock --user USERNAMEshows the expected state, and reset recovery has been tried for a named account.