LDIF Templates
This directory contains LDAP Data Interchange Format (LDIF) files used to bootstrap the OpenLDAP configuration and data during container initialization.
Files with a .template extension use ${VARIABLE} placeholders that are substituted with environment variables at runtime. Static .ldif files are applied as-is.
Rendered LDIF files are assembled in version-sort order (sort -V); numerical prefixes control ordering.
Conditional templates use .ldif.optional.template. They render to .ldif.optional
in the temporary output directory. The owning feature script activates them with
mv to .ldif when needed; final assembly ignores files still ending in .optional.
Sources stay unchanged, including on read-only volumes.
Structure
ldif/
├── config/ # OpenLDAP configuration database (cn=config)
│ ├── base/ # Core configuration (always applied)
│ ├── tls/ # TLS settings (OPENLDAP_BOOTSTRAP_TLS=true)
│ ├── tls-required/ # Enforce TLS (OPENLDAP_BOOTSTRAP_TLS_REQUIRED=true)
│ ├── database-readonly/ # Read-only data DB user (OPENLDAP_BOOTSTRAP_DATA_READONLY=true)
│ ├── database-admin/ # Scoped users/groups administrator (OPENLDAP_BOOTSTRAP_DATA_ADMIN=true)
│ ├── database-management/ # Scoped application account ACLs (OPENLDAP_BOOTSTRAP_DATA_MANAGEMENT=true)
│ ├── monitor-readonly/ # Read-only monitor user (OPENLDAP_BOOTSTRAP_MONITOR_READONLY=true)
│ ├── auditlog/ # Audit file (OPENLDAP_BOOTSTRAP_AUDITLOG=true)
│ ├── ppolicy/ # Password policy overlay (OPENLDAP_BOOTSTRAP_PPOLICY=true)
│ ├── refint/ # Referential integrity overlay (OPENLDAP_BOOTSTRAP_REFINT=true)
│ ├── unique/ # Unique attributes overlay (OPENLDAP_BOOTSTRAP_UNIQUE=true)
│ ├── memberof/ # Memberof overlay (OPENLDAP_BOOTSTRAP_MEMBEROF=true)
│ ├── replication/ # Replication (OPENLDAP_BOOTSTRAP_REPLICATION=true)
│ └── custom/ # User-provided config LDIF files
└── data/ # LDAP directory data (populated on first bootstrap)
├── base/ # Root organization entry (always applied)
├── data-tree/ # Users, groups and services OUs (OPENLDAP_BOOTSTRAP_DATA_TREE=true)
├── database-admin/ # Directory administrator (OPENLDAP_BOOTSTRAP_DATA_ADMIN=true)
├── database-management/ # Application account (OPENLDAP_BOOTSTRAP_DATA_MANAGEMENT=true)
├── database-readonly/ # Read-only account entry (OPENLDAP_BOOTSTRAP_DATA_READONLY=true)
├── monitor-readonly/ # Read-only monitor account (OPENLDAP_BOOTSTRAP_MONITOR_READONLY=true)
├── ppolicy/ # Password policy group and default policy (OPENLDAP_BOOTSTRAP_PPOLICY=true)
├── refint-nothing/ # Passwordless replacement role (REFINT enabled and NOTHING_DN set)
├── replication/ # Replication service accounts (OPENLDAP_BOOTSTRAP_REPLICATION=true)
└── custom/ # User-provided data LDIF files
Numbered prefix grouping behavior
During bootstrap, files are also grouped by tens based on their numeric prefix (00, 01, ..., 99, etc.), as implemented in services/openldap-bootstrap/startup.sh.
- Files in the same ten-group (for example
40-*and49-*) are concatenated without a blank line between them. - When switching to a different ten-group (for example
49-*to50-*), bootstrap inserts one blank line. - Leading and trailing empty lines are removed from every file before it is concatenated.
This matters because, in LDIF parsing, a blank line separates records:
- No blank line => content is treated as one logical LDIF record/entry stream.
- Blank line present => starts a new LDIF record/entry.
Examples:
40-a.ldif+49-b.ldif=> same ten-group (4x), concatenated directly.49-b.ldif+50-c.ldif=> group change (4x->5x), one empty line inserted.
Numeric prefixes are optional: names such as schema.ldif and database.ldif are accepted. Each file without a numeric prefix forms its own group, separated from other files by a blank line. Prefixes with leading zeros, such as 01-, 08-, and 09-, are interpreted as decimal numbers.
config/base
Core OpenLDAP configuration applied on every bootstrap. Files are numbered to control load order:
| File | Description |
|---|---|
00-global.ldif.template |
Global search limits, idle/write timeouts, pending requests and incoming message sizes |
10-module.ldif.template |
Module path and module list (auto or explicit order) |
20-schema.ldif |
Schema configuration container |
30-schema-import.ldif.template |
Additional schemas to load |
40-frontend.ldif.template |
Frontend database (password hash algorithm) |
50-config.ldif.template |
Config database (olcDatabase=config) with root DN and credentials |
59-config-acl-close.ldif |
Closes config ACLs (deny all) |
60-database.ldif.template |
Main data database (MDB backend) with indexes and last successful bind settings |
65-database-acl.ldif.template |
Data database ACLs (password self-service, basic attributes readable by authenticated users) |
69-database-acl-close.ldif |
Closes data ACLs (deny all) |
70-monitor.ldif.template |
Monitor database configuration |
75-monitor-acl.ldif.template |
Monitor database ACLs |
79-monitor-acl-close.ldif |
Closes monitor ACLs (deny all) |
ACL files ending in -close.ldif append a final access to * by * none rule to deny any unmatched access, ensuring a safe default.
Root, admin and management accounts
A DN identifies an LDAP account or entry. These accounts serve different purposes:
| Account | Default DN | Purpose and permissions |
|---|---|---|
| Data root | cn=admin,<suffix> |
Maintenance superuser for the data database; bypasses that database's ACLs and administrative limits |
| Config root | cn=admin,cn=config |
Server configuration superuser; can change schemas, ACLs, root passwords and other settings in cn=config |
| Directory admin | cn=admin,ou=services,<suffix> |
Day-to-day user/group administration, for example through phpLDAPadmin; obeys the scoped ACLs |
| Management | cn=management,ou=services,<suffix> |
Application account, for example Authelia; reads users/groups and resets user passwords |
The two root DNs are configured through OPENLDAP_BOOTSTRAP_DATA_ROOT_* and
OPENLDAP_BOOTSTRAP_CONFIG_ROOT_*. Each bypasses ACLs only in its own database:
the data root is not automatically the configuration root. Config root can change
the data database's ACLs and root password, so reserve it for server maintenance.
Here, "root" means an LDAP superuser, not the Linux user running the container.
Root DNs can authenticate without a directory entry. The optional directory admin has a real entry so clients such as phpLDAPadmin 2 can retrieve it after login. Its DN and password are separate from the root credentials. Use it for routine administration and keep root credentials for maintenance/recovery.
data/database-admin and config/database-admin
Enable the standard branches and scoped administrator on a new installation:
OPENLDAP_BOOTSTRAP_DATA_TREE=true
OPENLDAP_BOOTSTRAP_DATA_ADMIN=true
OPENLDAP_BOOTSTRAP_DATA_ADMIN_PASSWORD_HASHED="{ARGON2}..."
An empty hash generates a password and prints it in the bootstrap logs, as for
the other accounts. OPENLDAP_BOOTSTRAP_DATA_ADMIN_DN defaults to
cn=admin,${OPENLDAP_BOOTSTRAP_DATA_TREE_SERVICES_DN}; use a DN starting with cn=.
Keep administrator and application accounts outside the writable users/groups
branches, normally in the separate services branch.
The parent OUs must exist: enable tree creation or supply custom LDIFs before
70-database-admin-account.ldif. Enabling this option does not modify an existing
database.
62-database-admin-acl.ldif.template lets the administrator create, read, edit,
rename and delete entries in the configured users/groups branches, and reset user
passwords. It denies password hash read/compare and access to shadowLastChange;
with ppolicy, 61-database-admin-ppolicy-acl.ldif.optional.template also denies access to
pwdHistory. The administrator can read its own non-secret attributes, including
its identifier, but cannot modify, rename, delete or reset its own account.
Other service accounts, entries outside users/groups and cn=config stay protected.
Use data root to rotate the directory administrator's password.
Password resets use the same write/manage privileges as management resets. With ppolicy, these administrative resets bypass quality, history-reuse and minimum-age checks; the application performing them must enforce the required password rules. This remains a powerful identity-management account: it can reset users' passwords and change group memberships, but it cannot grant itself configuration access.
For phpLDAPadmin 2, configure DN login (LDAP_LOGIN_ATTR=dn) and accept this
entry's object class (LDAP_LOGIN_OBJECTCLASS=organizationalRole). Configure its
LDAP connection/search credentials and TLS separately.
data/data-tree and data/database-management
OPENLDAP_BOOTSTRAP_DATA_TREE=true creates ou=users, ou=groups and ou=services
below the suffix. OPENLDAP_BOOTSTRAP_DATA_MANAGEMENT=true creates one account,
by default cn=management,ou=services,<suffix>, to read users/groups and reset user
passwords. By default, it cannot edit profiles or groups or read password hashes/history.
Both options are independent and disabled by default.
The OU DNs, account DN and password hash are configurable through the matching
OPENLDAP_BOOTSTRAP_DATA_TREE_*_DN and OPENLDAP_BOOTSTRAP_DATA_MANAGEMENT_* variables.
If custom LDIFs supply the OUs, leave tree creation disabled and load them before
80-database-management-account.ldif. Do not duplicate automatically created OUs.
config/database-management
OPENLDAP_BOOTSTRAP_DATA_MANAGEMENT_HIDDEN_ATTRIBUTES lists comma-separated
attributes hidden from the management account (default userPassword,shadowLastChange).
When ppolicy is enabled, OPENLDAP_BOOTSTRAP_DATA_MANAGEMENT_HIDDEN_PPOLICY_ATTRIBUTES
is added (default pwdHistory). The combined list must not be empty.
63-database-management-acl.ldif.template limits password writes to the users branch.
Its =wmx privileges allow administrative resets without the old password and
password changes that supply the old password, as Authelia does. The auth (x)
bit lets OpenLDAP verify that password without granting hash read/compare.
With ppolicy, these operations bypass quality, history-reuse and
minimum-age checks: enforce password requirements in the application.
Service accounts and configuration remain protected; other identities keep their
usual ACLs.
config/database-readonly
64-database-readonly-ppolicy-acl.ldif.optional.template denies pwdHistory access to the data
read-only account before its general read grant. It is loaded only when ppolicy
and the data read-only account are both enabled, by 20-database-readonly.sh.
Its final by * break lets other
identities follow the usual database ACLs, including administrator and replication
access and any custom grants before the final deny-all. Provide
64-database-readonly-ppolicy-acl.ldif or its .ldif.template variant through
the custom config directory to override the read-only restriction.
data/ppolicy
50-ppolicy-policy.ldif.template sets the default password policy, including
pwdMaxIdle in seconds (0: disabled). Positive values require
OPENLDAP_BOOTSTRAP_DATA_LAST_BIND=true and OPENLDAP_BOOTSTRAP_PPOLICY_DEFAULT_LOCKOUT=true.
pwdMinDelay and pwdMaxDelay configure progressive per-account lockouts after
failed binds (0/0: disabled). Successful authentication resets the progression;
pwdMaxFailure and pwdLockoutDuration still apply when the failure threshold is reached.
config/replication
Syncrepl-based multi-provider replication. Applied when OPENLDAP_BOOTSTRAP_REPLICATION=true.
| File | Description |
|---|---|
03-global-replication.ldif.template |
Server IDs for each replication node |
61-database-replication.ldif.template |
Syncrepl consumer on the data database |
67-database-replication-acl.ldif.template |
ACLs for data replication account |
180-overlays-replication-database.ldif.template |
Syncprov provider on the data database |
Overlay load order matters for all overlays (not only replication). Keep dependencies in mind when choosing numeric prefixes. For replication specifically, keep Syncprov overlays loaded last (highest numeric prefixes, as in 180-...) so they are initialized after other overlays.
Custom directories
Use these directories to customize the first initialization without rebuilding the image:
| Directory inside the container | Content |
|---|---|
/container/services/openldap-bootstrap/assets/ldif/config/custom |
Configuration (cn=config): ACLs, indexes, overlays, and other settings |
/container/services/openldap-bootstrap/assets/ldif/data/custom |
Initial directory entries: users, groups, and other LDAP data |
Create local directories and mount them into the container:
mkdir -p custom-config custom-data
docker run --name openldap \
-v "$(pwd)/custom-config:/container/services/openldap-bootstrap/assets/ldif/config/custom" \
-v "$(pwd)/custom-data:/container/services/openldap-bootstrap/assets/ldif/data/custom" \
osixia/openldap:2.6.15-rc
Put .ldif files in these directories, or use .ldif.template files with ${VARIABLE} placeholders to substitute environment variables. The mounts may be read-only: bootstrap renders templates in a temporary writable copy.
There are three ways to customize the bootstrap:
- Add content: use a new filename. For example,
custom-data/70-users.ldifcan contain user entries. Include adn:and the required attributes for each entry, with a blank line between entries. Parent entries must come before their children. - Replace a built-in fragment: copy its file into the matching custom directory, keep the filename, and edit it. For example, copy
config/base/65-database-acl.ldif.templateintocustom-config/to change the default ACLs, orconfig/base/60-database.ldif.templateto change database settings and indexes. - Remove a built-in fragment: provide an empty
.ldiffile with the same output filename. For example, an emptycustom-config/65-database-acl.ldifremoves the rules from65-database-acl.ldif.template.
Custom files are copied after built-in files, replacing files with the same output filename after template substitution. The resulting files are then assembled in numerical order, using the prefix grouping rules above. For configuration, a fragment in the same ten-group can add attributes to an existing entry; a different group starts a new entry.
Bootstrap imports the assembled entries with slapadd. Use entry attributes, without modification instructions such as changetype: modify or replace: olcAccess.
Replacing one fragment leaves the others in place. For example, replacing 65-database-acl.ldif.template keeps the final deny-all rule in 69-database-acl-close.ldif and any ACLs added by enabled features such as read-only accounts or replication.
Bootstrap runs only when both configuration and data directories are empty. This does not change an existing database.