Package: slapddgen
slapddgenslapddgenUsageModifying the templatesDockerBuildingRunningProductionConfigurationcn=config.ldifcn=module{0}.ldif,cn=configolcDatabase={-1}frontend.ldif,cn=configolcDatabase={0}config.ldif,cn=configolcDatabase={1}monitor.ldif,cn=configolcDatabase={2}mdb.ldif,cn=configolcOverlay={0}memberof.ldif,olcDatabase={2}mdb,cn=configolcOverlay={1}refint.ldif,olcDatabase={2}mdb,cn=configolcOverlay={2}ppolicy.ldif,olcDatabase={2}mdb,cn=configolcOverlay={3}unique.ldif,olcDatabase={2}mdb,cn=configcn=schema.ldif,cn=configcn=*.ldif,cn=schema,cn=configNOTE: This tool is very very alpha. Works for me, might work for you.NOTE: Ensure your editor does not strip trailing whitespace if you
open any of the files incn=schemaas that will break the ldif format.slapddgengenerates aslapd.dthat you can load into an OpenLDAP
server by pointing at it withslapd -F. This will start a server
with online configuration, akaolc, meaning the configuration
itself is stored in the directory server, not inslapd.conf.UsageThe input for this tool is contained inconfig.json, or whatever--config_fileis pointed at. There's too many things to do this
with environment variables or CLI switches. Removing things fromconfig.jsonis guaranteed to blow shit up, though for the modules,
ACLs, indices and unique empty arrays should be fine.Once you've installed slapddgen you can run it with aslapddgen generate --config_file=/path/to/config.json --output_dir=/path/to/write/config/toModifying the templatesIf you know what you're doing you can modify the templates intemplates/slapd.dto suit your needs. Doing so if you'vepip installed
slapddgen will be annoying, so in that case cloning the repository and
doing apip install -e .instead will be more helpful.DockerThere is also an exampleDockerfilethat you can use to package
it all up in a Docker container. This can be useful for testing purposes
amongst other things.BuildingVERSION=$(gitrev-parse--abbrev-refHEAD)dockerbuild--no-cache=true\--build-argBUILD_DATE=$(date-u+'%Y-%m-%dT%H:%M:%SZ')\--build-argCOMMIT=$(gitrev-parseHEAD)\--build-argVERSION=${VERSION}\-tldap:${VERSION}.When building a release usegit describe --abbrev=0 --tagsinstead
for theVERSION.Runningdockerrun-it-p3389:389-p6636:636ldapThis will expose port 389 in the container, theldap://URL, to the host
on port 3389 (so you don't need to bind on a priviledged port) and do the
same for port 636,ldaps://.You can change the entrypoint with--entrypoint=/bin/sh. Once you've done
that you can still manually launch OpenLDAP in the container by runningslapd -u ldap -g ldap -d 256.ProductionWhen running it for production purposes it's important to ensure
configuration and data can persist to disk. Otherwise you'd start up with a
fresh and empty directory service every time your restart the container.To that end, you should probably volume mount the following:Configuration:/etc/openldapDatabase:/var/lib/openldap/openldap-dataA separate user,ldapdis create which defaults to a UID of55555. This
is to ensure you can correctly map a host user and the container user so you don't
get into permission issues with the volume mounts.In order to change the UID of theldapduser in the container you have to
rebuild it and pass in--build-arg UID=<number>.Configurationslapddgen generates a bunch of configuration for you and assumes the following
DIT layout:- {{suffix}}
--- {{baseOU}},{{suffix}}
----- ou=accounts,{{baseOU}},{{suffix}}
----- ou=groups,{{baseOU}},{{suffix}}
----- ou=policy,{{baseOU}},{{suffix}}You can of course change this yourself by modifying the templates.The configuration generated uses online/dynamic configuration, aka olc, akaolcConfig. As such there is noslapd.confto speak of and you'll have to
apply ldif's with the help ofldapmodifyto configure the OpenLDAP server
further.The resultingslapd.ddirectory can be used to start an OpenLDAP server
from scratch. The following sections assume that you've run slapddgen and
explain some of the things in the generated configuration.cn=config.ldifThe following settings are defaults related to Alpine:olcConfigFile: /etc/openldap/slapd.conf
olcConfigDir: /etc/openldap/slapd.d/
olcArgsFile: /run/openldap/slapd.args
olcPidFile: /run/openldap/slapd.pidOf note is:olcPasswordCryptSaltFormat: $6$rounds=50000$%.16sThis uses crypt's SHA512 with 50.000 rounds (key stretching). This relates to
theolcPasswordHashsetting inolcDatabase={-1}frontend.ldifas well asolcPPolicyHashCleartextinolcOverlay={2}ppolicy.ldif,olcDatabase={2}mdb,cn=config.cn=module{0}.ldif,cn=configConfigures which modules are loaded. Of note areolcModulePathand the
multitude ofolcModuleLoadentries, relative toolcModulePath.olcDatabase={-1}frontend.ldif,cn=configThe frontend database is a special, pseudo, database which contains settings
that apply as defaults to all the otherolcDatabases.The two interesting entries are:olcMonitoring: FALSE
olcPasswordHash: {CRYPT}olcMontioringdisables the monitoring overlay for all databases. It'll be
enabled explicitly forolcDatabase={2}mdb.ldif. The other ensures that we
always use{CRYPT}as our password hashing mechanism. Which settings are
applied to password hashing is defined byolcPasswordCryptSaltFormat.olcDatabase={0}config.ldif,cn=configThe only thing of interest here are theolcAccessentries, defining the
ACLs which allow entities to read/writecn=config.olcDatabase={1}monitor.ldif,cn=configLike the previous section,olcAccessis the only interesting bit.olcDatabase={2}mdb.ldif,cn=configThis one is interesting, as this defines the data storage of our actual
entries in the DIT, as well as other things like ACLs.Of interest:olcSuffix: dc=example,dc=com
olcRootDN: cn=Manager,dc=example,dc=com
olcRootPW: {CRYPT}super-long-hash
olcMonitoring: TRUE
olcDbMaxSize: 536870912
olcDbDirectory: /var/lib/openldap/openldap-data
olcDbIndex: objectClass eq
olcDbIndex: uid eq,sub
olcDbIndex: uidNumber eq
olcDbIndex: gidNumber eq
olcDbIndex: member eq
olcDbIndex: memberof eqolcSuffixdefines the default suffix for all entries.olcRootDNis the
DN of this database "root" user, and can modify anything regardless of ACLs.
TheolcRootPWis the password of theolcRootDN, generated withslappasswd -h '{CRYPT}' -c '$6$rounds=50000$%.16s'.olcMonitoringenables monitoring for this database andolcDbDirectorycontains the path on disk where this database is stored.TheolcDbIndexentries define the indices OpenLDAP will maintain for us
and help speed up search operations.olcDbMaxSizedefines the size of the memory map that will be allocated
for the database. It cannot grow past this value at runtime though you
can set it to a higher value and then restart. The value is in bytes,
our default is half a gibibyte (GiB).As usual there's also a number ofolcAccessentries governing access to
the data.olcOverlay={0}memberof.ldif,olcDatabase={2}mdb,cn=configHere we store the configuration for the memberof overlay. The memberof
overlay adds a virtual attributememberOfto any entry in the DIT storing
what things this DN is a member of.Imagine you have threegroupOfNamesthat refer to a user in thememberattribute. ThememberOfattribute for that user will then contain the
DNs of these threegroupOfNames. Note thatmemberOfwill only contain
the immediate/direct memberships, not any inherited ones (it will
not recursively expand the member attributes).The settings of interest are:olcMemberOfDangling: error
olcMemberOfDanglingError: constraintViolation
olcMemberOfRefInt: TRUE
olcMemberOfGroupOC: groupOfNames
olcMemberOfMemberAD: member
olcMemberOfMemberOfAD: memberOfolcMemberOfDanglingspecifies that we'll return an error in case a
modification would result in a dangling reference, returning an error of
typeolcMemberOfDanglingError.olcMemberOfRefIntspecifies that we use the referential integrity
overlay (see the next section).olcMemberOfGroupOCspecifies whichobjectClasswe monitor for
dangling references. This is usually only useful for gorups and we usegroupOfNamesfor groups.olcMemberOfADspecifies the attribute used
to store members of a group in, that'smemberandolcMemberOfMemberOfADspecifes the attribute in which the relation is stored,memberOf.olcOverlay={1}refint.ldif,olcDatabase={2}mdb,cn=configThis configures the referential integrity overlay. Referential integrity
will take care of updating any references to a DN stored in the specified
attributes should that DN get renamed/moved.Of note:olcRefintAttribute: owner
olcRefintAttribute: manager
olcRefintAttribute: memberOf
olcRefintAttribute: member
olcRefintAttribute: roleOccupant
olcRefintModifiersName: cn=Manager,dc=example,dc=comTheolcRefintAttributes specify which attributes we want to enforce
referential integrity for. This can only every be attributes that store
a distinguished name.olcRefintModifiersNamespecifes what we'll store in themodifiersNameoperational attribute for any entry that gets updated by the referential
integrity overlay.olcOverlay={2}ppolicy.ldif,olcDatabase={2}mdb,cn=configThe password policy overlay allows to configure certain minimum
requirements for passwords (like those stored in theuserPasswordattribute).Of note:olcPPolicyHashCleartext: TRUE
olcPPolicyDefault: cn=password,ou=policy,dc=example,dc=com
olcPPolicyUseLockout: FALSEolcPPolicyHashCleartextmeans that the server will automatically hash
any password sent in as clear text usingolcPasswordHash.olcPPolicyDefaultdefines an entry in the DIT where we store our
default password policy on which we can set other settings. The entry
should haveobjectClass: pwdPolicy. Its settingsare documented
here.You can create additional/different password policies in theou=policypart of the tree and attach them to a user by adding thepwdPolicySubentryattribute on them, pointing to a different policy.olcPPolicyUseLockoutinstructs the server whether it should return anInvalidCredentials(FALSE) when attempting to bind or anAccountLocked(TRUE) instead. This configuration defaults toFALSEin order to not be
able to use this feature to enumerate accounts.olcOverlay={3}unique.ldif,olcDatabase={2}mdb,cn=configThe unique overlay allows enforcing uniqueness contraints of attributes on
a part of the tree (or the whole tree). Though the RDN is always enforced to
be unique (so you can't have two people with the sameuidfor example)
other attributes are not, most crucially things likeuidNumber,gidNumberorhomeDirectory.You can create constraints by adding anolcUniqueURIentry of the form:ldap:///[base dn]?[attributes...]?scope[?filter].For example, if you wanted to enforce uniquegidNumbers you could do:ldap:///?gidNumber?sub. Unfortunately this will enforcegidNumberconstraints across bothposixAccountandposixGroupso you won't be
able to create aposixAccountwithgidNumberset to aposixGroups
GID, which is undesirable. Instead do something like this:olcUniqueURI: ldap:///ou=groups,ou=example,dc=example,dc=com?gidNumber?sub
olcUniqueURI: ldap:///ou=accounts,ou=example,dc=example,dc=com?gidNumber?sub
olcUniqueURI: ldap:///ou=example,dc=example,dc=com?uidNumber?subNow the constraint will be enforced independently on these parts of the
tree, not as a whole.cn=schema.ldif,cn=configNothing of relevance to see or change here. It just needs to exist. Once
the server has been started this entry will be updated automatically
with the server's internal object classes and attributes (mostly all theolc* object classes and attributes).cn=*.ldif,cn=schema,cn=configContains the schema files loaded by the server.Updating this is rather tricky. The "easiest" way is to generate aslapd.confwith theincludestatements for the schemas and then dump it out
usingslapdest -f /path/to/slapd.conf -F /path/to/slapd.d.