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.
Verification
Live-testedReally 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 · attributionPaste 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.
[](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:
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
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.
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.
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.
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.
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.
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.