access.conf, In The Stack And Proven With PAM Itself
EL ships /etc/security/access.conf with no active rule and pam_access is not in the stack to read it, so every account is admitted from anywhere. This role writes the policy, adds the module through authselect, and refuses to write a rule set that would lock out the account running it. The live test asks PAM, with the origin set. 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-27 · 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-access?utm_source=syndication&utm_medium=readme&utm_campaign=artifact)
Ansible role 1.0.0, live-tested on IaC Bazaar: [access.conf, In The Stack And Proven With PAM Itself](https://www.iac-bazaar.com/catalog/ansible-pam-access?utm_source=syndication&utm_medium=readme&utm_campaign=artifact)
```yaml
# access.conf, In The Stack And Proven With PAM Itself: https://www.iac-bazaar.com/catalog/ansible-pam-access (download from your IaC Bazaar account)
```Preview:
Documentation
pam-access
EL ships /etc/security/access.conf with no rules in it, and pam_access is
not in the stack to read them. 4,671 bytes of documentation, a control that
appears configured, and every account admitted from anywhere. This role writes
the policy, puts the module into the authentication stack through authselect -
/etc/pam.d/system-auth is a symlink into generated files, so editing it by hand
does not survive - and proves each rule by asking PAM.
No download, and no version to pin. pam and authselect are EL 10 packages.
What the role owns is access.conf in full and one authselect feature, and what
it proves is that a named account gets in from a named place and nobody else
does.
The order of the file is the policy. pam_access stops at the first rule
that matches, so a blanket allow above a deny makes the deny dead. That is why
the template renders the rules in a fixed order and why
pam_access_prepend_rules is documented as the dangerous escape hatch rather
than the convenient one.
This role can lock you out of a host, so it checks first. With
pam_access_deny_all and a group list that does not include you, the next login
is refused - and after - : ALL : ALL, root's ssh logins are refused too, because
pam_access_allow_root_from is LOCAL by default. Before writing anything the
role reads the account this play is connected as, the groups the host gives it,
and whether the connection arrived over ssh, and refuses to write a policy that
would shut that account out. The check has one limit, stated because it matters:
it requires that a non-LOCAL origin exists for root, not that the origin is
yours.
A line pam_access cannot parse is ignored, and the account is admitted.
Measured: with this is not a rule in the file, the account under test was still
allowed. Nothing validates access.conf - there is no checker to give a
template validate: - so the live test drives PAM with pamtester rather than
reading the file back, and it reads the refusal message as well as the exit code.
First match wins, in both directions. With + : ALL : ALL above
- : user : ALL the user was admitted; with the deny first the same user was
refused. This is the trap that makes a long access.conf unreadable: a rule
added at the top for one host silently retires everything below it.
LOCAL is a real origin, not the absence of one. A rule allowing a user from
10.99.0.0/24 refused that user from 203.0.113.7 and from a console login
with no remote host at all. + : root : LOCAL is what admits root on the
console, and it is what makes root's network logins refused.
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.