pam_faillock, A Lockout Proven To Lock And To Let Go

An account lockout on EL 10, put into the authentication stack through authselect because /etc/pam.d/system-auth is a generated symlink. The live test fails one account past the limit and watches the RIGHT password be refused, fails a second one short of the limit and watches it keep working, then resets the first and watches it come back. Original role, live-tested on Rocky Linux 10.

ansibleSecurity & Secrets

Verification

Live-tested

Really deployed to a container sandbox, proven idempotent (a second run changes nothing), verified against the role’s assertions, then torn down.

Conformance

  • Static validation (yamllint · ansible-lint)

Provenance

  • SHA-256 checksum
  • Signature (pending)

Functional

  • Live-tested - applied, verified, destroyed

Last verified 2026-09-26 · podman 4.9.3 · ansible 2.21.4 · how we verify

Cite it in your README

badge · attribution

Paste this beside the module in the repository that uses it. The badge is rendered from this artifact's verification record, so it reads live-tested because the record says so, and the link lands on this page.

README.md, GitLab, Gitea
[![IaC Bazaar: live-tested](https://www.iac-bazaar.com/api/artifacts/ansible-pam-faillock/badge)](https://www.iac-bazaar.com/catalog/ansible-pam-faillock?utm_source=syndication&utm_medium=readme&utm_campaign=artifact)

Ansible role 1.0.0, live-tested on IaC Bazaar: [pam_faillock, A Lockout Proven To Lock And To Let Go](https://www.iac-bazaar.com/catalog/ansible-pam-faillock?utm_source=syndication&utm_medium=readme&utm_campaign=artifact)

```yaml
# pam_faillock, A Lockout Proven To Lock And To Let Go: https://www.iac-bazaar.com/catalog/ansible-pam-faillock (download from your IaC Bazaar account)
```

Preview:IaC Bazaar: live-tested

Documentation

pam-faillock

A lockout that is proven to lock, and proven to let go. The role writes the faillock policy and puts pam_faillock into the authentication stack through authselect, which is the only supported way in on EL 10. The live test fails one account past the limit and watches the RIGHT password get refused, fails a second account one short of the limit and watches it keep working, then resets the first and watches it come back.

No download, and no version to pin. PAM and authselect are part of EL 10, so the role installs them by name and works through the tooling the distribution provides. What the role owns is the policy: how many failures, in what window, for how long, and whether root is included.

/etc/pam.d/system-auth is a symlink into /etc/authselect. Editing it is editing a generated file, and the next authselect apply-changes discards the edit without a word. The role uses authselect enable-feature with-faillock, keeps whatever profile the host already has, and runs authselect check on every pass rather than only after a change - because a stack that does not apply cleanly is a host that cannot authenticate at all.

Nothing validates faillock.conf, and a typo fails OPEN. With deny = notanumber, PAM printed "Bad number supplied for deny argument", let the authentication through, and applied no lockout at all. There is no checker to run and no error to notice: the policy is simply absent. That is the reason this role's live test exists in the form it does, and why it counts to the limit rather than asserting that the file contains the right words.

even_deny_root can lock an operator out of a host. It is on by default here because a lockout that exempts the account everyone attacks is not a lockout, but root_unlock_time is then the only way back in that does not need a console. Decide that before rolling it out, not after.

License

Commercial - IaC Bazaar EULA. (c) IaC Bazaar.

Usage code & full reference need an account

The complete copy-paste usage, the full input/output reference, and operational notes are free with an account - shown here and bundled in the download. Sign in and this section fills in.

  • Variables
  • Test

Related modules

Live-tested

ansible-aide

AIDE from AppStream on EL 10: a watched tree, a baseline database built once, and the oneshot unit and timer the package does not ship. The live test passes on an unchanged host, FAILS when a file appears inside a watched path and names it, ignores one inside an excluded path, and passes again once the change is gone. Original role, live-tested on Rocky Linux 10.

View module
Live-tested

ansible-authelia

Authelia from the upstream release (sha256-verified) as a hardened system service on loopback with file users and sqlite; its secrets are generated once on the host and reach the service as AUTHELIA_*_FILE variables. The live test hashes a password with Authelia's hasher, logs in, sees a wrong password refused and an anonymous visitor sent to the portal. Original role, live-tested on Rocky 10.

View module
Live-tested

ansible-bandit

bandit on EL 10 from PyPI into a venv of its own with a link in the PATH; the live test runs pip check, then scans a module that passes a string to subprocess.call with shell=True (B602, High, exit 1) and a clean module (exit 0). Pinned. Original role, live-tested on Rocky Linux 10.

View module
Live-tested

ansible-boundary

boundary on EL 10 from releases.hashicorp.com; SHA256SUMS is signature-checked against HashiCorp's key before get_url trusts it, the live test re-checks both, then runs authenticate against a dead address ('connection refused') and database init with a throwaway config (parsed, root key loaded, then the database refused). Pinned. Original role, live-tested on Rocky Linux 10.

View module
Live-tested

ansible-dockle

dockle on EL 10 from the GitHub release; get_url refuses it unless its SHA-256 is in the vendor's checksums file, and the live test re-checks it, then scans a one-layer image whose config names no user, expecting CIS-DI-0001 in the output, exit code 1 with --exit-level warn, and the warning counted in the JSON form. Pinned. Original role, live-tested on Rocky Linux 10.

View module
Live-tested

ansible-gitleaks

gitleaks on EL 10 from the GitHub release, refused by Ansible's get_url unless its SHA-256 is the one in the project's checksums file, and re-checked with sha256sum -c by the live test, which then plants a file holding an AWS access key that is not one and runs gitleaks detect over it, expecting 'leaks found: 1'. Original role, live-tested on Rocky Linux 10.

View module