OpenLDAP’s own Administrator’s Guide, in the chapter on configuring slapd, says the flat file is
on its way out: “The older style slapd.conf(5) file is still supported, but its use is
deprecated and support for it will be withdrawn in a future OpenLDAP release.” The replacement
is cn=config, the runtime-editable configuration tree introduced back in the 2.3 days.
I read that note every couple of years. I still draw my clients a flat file.
⚙️ What cn=config actually is
The dynamic backend has one advantage: changes can be made without restarting slapd. Run
ldapmodify and the new overlay, index, or log level takes effect on the running server with no
restart. For a directory that serves 20K RFC2307 lookups per second, never taking it down to
reconfigure sounds like an indisputable win.
The same property that makes it powerful is the one that can cause a lot of problems.
⚠️ The feature that is also the sharp edge
A runtime-editable configuration means every configuration change is a live change to the
directory of record. There is no staging step in the mechanism, and no restart acting as a
checkpoint. The moment your ldapmodify returns, the new ACL is already deciding who can read
what, in production, for everyone.
Most of the time that is fine. The problem is the day you discover that a sensitive attribute type is exposed to the wrong user. An untested access rule doesn’t wait politely for a maintenance window to reveal itself; it is already the policy.
Restarting a server in a replicated environment costs almost nothing. The LDAP client by default will fail over to the next server in the list, or hit the load balancer URI again, opening up a connection to another server.
With a flat file, the change goes through source control and review before it ever reaches a
server: you edit the file, you diff it against what is running, and you restart slapd on your
schedule, in a rolling fashion, across your replica set. That restart isn’t overhead I tolerate.
It’s the checkpoint I want.
📖 Config you can actually read
When your configuration is a file, it is a file. It lives in git. It diffs. Someone can read the
whole thing top to bottom and understand what this server does. Changes show up in a merge
request review with hopefully useful comments explaining why. The flat file can be indented in
places (especially the to lines in access controls) and is much easier for a human to read.
Now look at what cn=config leaves on disk. The slapd.d/ tree is a spray of generated LDIF
with names like olcDatabase={1}mdb.ldif, carrying numeric ordering prefixes, entryUUIDs,
timestamps, and a CRC checksum in a header that tells you, in the project’s own words, not to
edit the file by hand. That warning is correct; the on-disk form was never meant for human eyes.
To answer the simple question “what is this server’s configuration,” you don’t read a file, you
slapcat the config database and interpret the dump. You can put slapd.d/ under version
control, but you end up versioning a machine’s scratch space, and the diff stops telling you
what a person changed and starts telling you what the backend rearranged. The flat file keeps
the config’s canonical form the one you review.
🍰 Have your cake and eat it too
With the flat file, you can still have runtime changes for the handful of situations where it
does make sense. In the flat file I always enable the config database itself, database config.
That exposes cn=config on the running server for on-the-fly edits while the flat file stays
the persistent source of truth, and it buys exactly the live moves worth having. I can raise
olcLogLevel to chase a problem and drop it again without bouncing the server. One very good
use of the OLC is short-lived TLS certificates: I can refresh slapd with a renewed TLS
certificate, not changing any value, but just resetting it to the same one.
Because the configuration was loaded from the file and there is no slapd.d/ behind it, those
live edits live in memory only. They vanish on restart and the server comes back up as the file
I reviewed. The durable configuration is still the artifact in git; the live change is
explicitly temporary, which is exactly what a live change should be.
The usual case for going all-in on cn=config instead is “I can’t afford the restart.” With the
modern mdb backend a restart is cheap, and any directory serious enough to fear one already
rolls restarts across replicas behind a load balancer without causing client impact. And
replicating cn=config itself over syncrepl, sometimes pitched as the payoff, is the part I
would argue hardest against: besides being a lot of unnecessary moving parts, it takes the one
unreviewed keystroke and hands it the whole fleet, so a bad change lands everywhere at once with
the checkpoint removed on every node. That is the blast radius sold as a feature.
😴 Boring, on purpose
None of this is a claim that cn=config is bad. It’s a claim that a static configuration file
has real, present-tense virtues, reviewability and a built-in checkpoint. Trading them away
should be a decision you make on purpose rather than a default you inherit because a man page
said deprecated.
It ties straight back to the reliability trap: the directory you can still reason about years later is the one whose configuration you could read, diff, and talk about like the artifact it is. Keep the config flat, keep the live window narrow and temporary, and never confuse the option that saves you a restart today with the one that keeps you fluent for the outage you can’t see coming.
The flat file isn’t the old way I haven’t gotten around to leaving. It’s the checkpoint I chose to keep.