An LDAP Directory That Refuses Anonymous Reads
389 Directory Server from AppStream. A fresh instance listens on every interface and lets anonymous clients read the tree; this role binds both listeners to loopback and limits anonymous clients to the rootDSE. The live test adds a user who binds, sees a wrong password and an anonymous search refused, and reads the LDAPS certificate. 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-10-02 · 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-389-ds?utm_source=syndication&utm_medium=readme&utm_campaign=artifact)
Ansible role 1.0.0, live-tested on IaC Bazaar: [An LDAP Directory That Refuses Anonymous Reads](https://www.iac-bazaar.com/catalog/ansible-389-ds?utm_source=syndication&utm_medium=readme&utm_campaign=artifact)
```yaml
# An LDAP Directory That Refuses Anonymous Reads: https://www.iac-bazaar.com/catalog/ansible-389-ds (download from your IaC Bazaar account)
```Preview:
Documentation
389-ds
389 Directory Server from AppStream, created once from a description you control, then hardened: both listeners on loopback, anonymous clients limited to the rootDSE, LDAPS with the certificate dscreate generates. Original role for EL 10, live-tested with podman on Rocky Linux 10.
No download, and no version to pin. EL 10 packages dirsrv, so the
role installs it by name and takes what the distribution ships: a security
update arrives through dnf, not through a new release of this role. What the
role owns is the configuration and the proof that the service works.
The distribution's unit, our configuration. The role installs
389-ds-base, openldap-clients, writes the configuration the package leaves open, and
enables the unit the package ships: systemctl cat dirsrv@main shows the
distribution's own unit, not one this role invented. The listener is
127.0.0.1:3389 by default, for a proxy that authenticates or a
client on the same host; the live test reads the listening sockets and
expects loopback only.
What dscreate leaves open. A fresh instance listens on every
interface (*:3389 and *:3636, measured) and lets an anonymous client read
the suffix entry. The role sets nsslapd-listenhost and
nsslapd-securelistenhost to loopback and nsslapd-allow-anonymous-access
to rootdse - anonymous clients can still read the rootDSE, which is how
they discover the naming contexts, and nothing below it. Each setting is read
first and replaced only when it differs, then the instance restarts.
Created once. dscreate is not re-runnable, so it runs only when the
instance's configuration directory does not exist; the description it reads
(with the Directory Manager password) is root's, mode 0600. The live test
adds a user as Directory Manager, binds as that user, sees a wrong password
refused (49) and an anonymous search refused (48 Inappropriate
authentication), reads the rootDSE anonymously and reads the LDAPS
certificate on loopback.
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-clamav
ClamAV from EPEL: clamd on a local socket and loopback TCP, signatures fetched before it starts and freshclam enabled after, since every ClamAV unit ships disabled. The README measures where a size limit fails open. The live test decodes the EICAR test file on the target, so no role file holds it, and finds the signature by name on three client paths. 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.