Feature Specification: Resource ldap
Created: 2026-10-07
Status: Implemented
Input: Reconstructed from the code of core/resources/ldap/ and its wiring in core/setups/ and core/effects/ at 093e68b6f, pull requests #1184, #1205 and #1236, and issue #527.
User Scenarios & Testing (mandatory)
The ldap resource gives a component an LDAP directory for its users,
through the ldap contract and the lldap provider. The shared rules are
in the resource family spec.
User Story 1 - Give a component a directory to authenticate against (Priority: P1)
Without a directory, nobody can log in: the single sign-on provider and
other components read their users from it. A request names a directory
group and a consumer name. The consumer node gets the directory coordinates
and a bind password file in the ldap contract result.
Independent Test: a contract test of ldap with lldap, a VM test of
the OpenBao LDAP engine, and unit tests of both sides.
Acceptance Scenarios:
- Given a routed request, When the consumer side evaluates, Then the result holds the group and all coordinates: with TLS the LDAPS URL and the CA, without TLS the plaintext URL and no CA.
- Given a directory domain and no base DN, When the policy evaluates, Then the base DN is one
dc=part per label after the first, for exampledc=example,dc=orgforldap.example.org. - Given no routed provider, When the deployment evaluates, Then there is no consumer side, no provider side and no daemon.
- Given the OpenBao LDAP engine, When the consumer binds as
authelia-bind, Then it can set the password of a user outsidelldap_adminand of nolldap_adminmember.
User Story 2 - Run the directory and seed its accounts (Priority: P1)
An empty directory has no admin and no groups. The provider node runs
lldap, and a provisioning job applies the groups, the seeded users and
their memberships. The administrator of the deployment gets single sign-on,
admin UI access and directory admin rights. The password of admin resets
to the generated bind password at each start.
Independent Test: VM tests of the seed isolation, the release of the administrator mail address and the provisioning, and unit tests of the grant and the coordinates.
Acceptance Scenarios:
- Given an administrator, When the provisioning runs, Then the administrator is a member of
authelia-users,fediversity-adminsandlldap_admin. - Given the administrator mail address held by another account, When the provisioning runs, Then it deletes that account. When
adminorauthelia-bindholds it, the provisioning logs this, keeps the account, and the apply of the administrator fails. - Given a seeded object that exists outside the state, When the provisioning runs, Then it adopts it. An object that the deployment did not seed stays.
User Story 3 - Serve the directory over LDAPS (Priority: P2)
On plaintext LDAP, the bind password and the user passwords that authelia
checks cross the network in clear text. A group with an lldap node must
therefore have a private CA. The node serves LDAPS with a leaf for its host
from the central OpenBao PKI, through the openbao-pki provider of the
ssl contract, and each consumer verifies against the PKI CA.
Independent Test: the ldap contract test binds over LDAPS against a
test CA. The LDAP engine VM test moves a mount from plaintext to LDAPS and
rotates a password through it. The application VM tests bind authelia
over LDAPS with a PKI leaf.
Acceptance Scenarios:
- Given a private CA, When the provider node evaluates, Then
lldapgets the leaf for its host as credentials, and a renewal restarts it. - Given an
lldapnode and no private CA, When the group evaluates, Then the evaluation fails and names the node and the private CA. - Given a node that runs
autheliaor the vars backend, When it evaluates, Then it trusts the PKI CA of thelldaphost.
User Story 4 - Publish the directory coordinates (Priority: P2)
A consumer in another group cannot read the configuration of the provider group, so the provider node publishes the URL, the user base DN and the management bind DN to OpenBao KV.
Independent Test: a unit test of the coordinates.
User Story 5 - Send password reset mail (Priority: P3)
A user resets a password without an operator. lldap sends reset mail
through the smtp resource, from a no-reply address on the
users domain. The link goes to the UI behind forward auth, which lets only
the reset routes through without a session. This is the only reset for an
lldap_admin member, such as the administrator.
Independent Test: a VM test of the reset mail, and a unit test of the mail wiring.
Acceptance Scenarios:
- Given a user without a session, When the user follows the reset link, Then the reset succeeds, and the login and API routes still send the user to
authelia. - Given an empty relay password, When
lldapstarts, Then the start fails.
Edge Cases
- The relay connection uses STARTTLS.
lldaptrusts only the public web PKI roots, so a relay with a private CA fails. - A relay with an empty public URL fails evaluation. Without a forward-auth entry point (no
oidcprovider in the group), the public URL is the plaintext listener, and the reset token travels in clear. - A mail address for the administrator without an administrator fails evaluation.
lldapmakes no private CA, and a self-signed leaf gives consumers nothing to verify. Abootstrapnode or a valkey node gives the group a private CA.- The API is not ready: the provisioning waits for a bounded time, fails, and retries later. A failed
adminlogin fails before the apply. A failed seeded user does not stop the others. - Until the leaf exists,
lldapdoes not start, on the plaintext port either. A renewal, in the last third of the leaf lifetime, closes the open consumer connections. - A stop with an open TLS database connection hangs until a short timeout kills it.
- The PKI CA is not on the engine node yet: the LDAPS mount has no CA, and its bind fails until the CA arrives.
Requirements (mandatory)
Functional Requirements
- FR-001: Without an explicit base DN, the policy MUST derive it from the directory domain: drop the first label, one
dc=part per remaining label. - FR-002: Users MUST be under
ou=peopleand groups underou=groupsof the base DN. - FR-003: The policy MUST give a consumer side and a provider side only when a provider is routed.
- FR-004: The policy MUST run the daemon only when a provider is routed.
- FR-005: The policy MUST generate a random bind password as a secret, readable by every account on the provider node.
- FR-006: The provider MUST give each want the URL, the CA, the host, the port, the base DNs, the bind DN and the bind password file. With TLS, the URL and port MUST be LDAPS and the CA the PKI CA. Without TLS, they MUST be plaintext, with no CA.
- FR-007: The provider node MUST open the web port. With TLS, it MUST open the LDAPS port and MUST NOT open the plaintext port. The plaintext listener then still answers on the loopback interface, where the provisioning connects. Without TLS, the node MUST open the plaintext port.
- FR-008: The provisioning MUST create
fediversity-adminsand each group of a seeded user, and MUST putauthelia-bindinlldap_password_manager, not inlldap_admin. - FR-009: The provisioning MUST delete a seeded user, group or membership that leaves the configuration, and MUST NOT change one that is not in its state.
- FR-009a: The provisioning MUST adopt a seeded user, group or membership that exists outside its state.
- FR-010: The release of the administrator mail address MUST NOT delete
adminorauthelia-bind. - FR-011: The provider node MUST publish the coordinates to OpenBao KV when it has the OpenBao vars backend.
- FR-012: The request MUST hold only data. The consumer side MUST give the result to the
ldapcontract of the consumer node. - FR-013: The setups MUST read the administrator from the group data, and evaluation MUST fail when a group with an
lldapnode does not name one. - FR-014: The forward-auth entry point MUST let only the reset routes through without a session, and MUST limit the rate of reset requests per client address.
- FR-015: In a group with a private CA, the provider node MUST serve LDAPS with a leaf for its host from the
openbao-pkisslprovider, and the result CA MUST be the PKI CA. Evaluation MUST fail for anlldapnode without a private CA. TLS is on by default. A deployment MAY turn it off, and the listener and consumers then stay on plaintext. - FR-016: Each consumer MUST connect to the result URL and verify LDAPS against the PKI CA:
autheliathrough the system trust, the LDAP engine by giving the CA to the mount and its bind checks. - FR-017: The LDAP engine MUST point a mount at a published URL with the same host and another scheme or port, and MUST NOT treat this as a second live deployment.
Key Entities
- ldap contract result: the URL, the CA (none for plaintext), the host, the port, the base DNs, the bind DN and the bind password file.
- Directory coordinates: the URL, the user base DN and the management bind DN (
admin).
Success Criteria (mandatory)
Measurable Outcomes
- SC-001: The
ldapcontract test, and the VM tests of the provisioning, the LDAP engine, the seed isolation, the admin release and the reset mail pass. - SC-002: The unit tests of the grant, the coordinates, the mail wiring, the TLS routing and both sides pass.
- SC-003: After a deployment, the administrator logs in through single sign-on and opens the
lldapweb UI.
Assumptions
- The daemon is the
lldapcomponent. The main consumer isautheliathroughoidc. - Without the LDAP engine, the consumer binds as
adminwith full rights. Only test topologies run so, and a separate bind account would not help there, because the consumer can read theadminpassword in KV. A unit test checks thatautheliabinds asauthelia-bindwith the engine and asadminwithout it.
Known Deviations
None.