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.

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-10-02 · 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-389-ds/badge)](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:IaC Bazaar: live-tested

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

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-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.

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