openldap_hints - collection of commands or procedures to help managing OpenLDAP.
CURRENT TODOS:
- Writeup: slapadd doesn't respect memberOf ... slapd needs to be online for memberOf ... as its an operational-on-write-action
As of Q4 2024:
2.5 - outgoing LTS, move away from this or prior 2x versions
2.6 - LTS
2.7 - features release
https://ldap.com/2024/07/16/openldap-2-6-long-term-support-announcement/
Current:
mdb
- Uses OpenLDAP's Lightning Memory-Mapped Database (LMDB) library to store data. Uses no caching and requires no tuning to deliver maximum search performance.
Now deprecated:
hdb
- Hierarchical variant of bdb. More spatially and execution efficient than bdb.
bdb
- BerkeleyDB.
Need to move/tidy this section up... but for quick reference.
ldap:/// LDAP TCP port 389
ldaps:/// LDAP over SSL TCP port 636
ldapi:/// LDAP IPC (Unix-domain socket)
Couple of examples
ldapadd -Y EXTERNAL -H ldapi:/// -f some_ldif.ldif
ldapadd -H ldaps:/// -D cn=bind_user,dc=some,dc=example -f some_ldif.ldif
Generally speaking commands with slap
in their name require slapd
to be stopped before they are run - e.g. slapadd
.
Whilst commands with ldap
in their name are the oppsite and need slapd
running - e.g. ldapadd
.
A notable exception is that if you have a sufficintly new OpenLDAP (2.4+ with hdb/mdb) , it is safe to slapcat
. So you can safely dump the DB. Of course if in doubt check.
Stop ldapsearch doing ldif line wrapping:
-o ldif-wrap=no
Find users within an OU, an example search could look like this, where the search base is the OU of interest:
ldapsearch -xLLL -b ou=Users,dc=domain,dc=something,dc=something
...refining this to count users:
ldapsearch -xLLL -b ou=Users,dc=domain,dc=something,dc=something "uid=*" uid | grep "uid:" | wc -l
Finding if a module is loaded (example ppolicy), using root+SASL:
ldapsearch -Y EXTERNAL -H ldapi:/// -b "cn=config" -s sub "(&(objectclass=olcModuleList)(olcModuleLoad={0}ppolicy.la))" | grep ^olcModuleLoad:
Search an OU (by setting base to that OU) for entries and sort by gidNumber
ldapsearch -S gidNumber -xLLL -b ou=some_ou_name,dc=something,dc=something
View config
(note use of SASL which allows a client to request the server uses credentials established by a method external to the mechanism, to authenticate this client)
ldapsearch -Y EXTERNAL -H ldapi:/// -b cn=config "(|(cn=config)(olcDatabase={1}mdb))"
View config, olcAccess
ldapsearch -Y EXTERNAL -H ldapi:/// -b cn=config "(|(cn=config)(olcDatabase={1}mdb))" olcAccess
ldapsearch -Y EXTERNAL -H ldapi:/// -b cn=config '(olcAccess=*)' olcAccess olcSuffix
Check replication contextCSN - here assumes -b
need not be supplied otherwise supply it (e.g. if not coming from ldap.conf)
ldapsearch -xLLL -s base ContextCSN
Use at own risk... this might go into a file you run an ldapdelete on. It will produce the children (one level) of the ou=people
ldapsearch -xLLL -s one -b "ou=people,dc=foo,dc=com" "(cn=*)" dn | awk -F": " '$1~/^\s*dn/{print $2}'
redirect above to file and then dry run delete e.g.
ldapdelete -n -vv -r -f listOfDNRemove.txt
Output an OU search then count the entries (DNs) whilst removing empty lines. Here using intermediate file, though you dont have to.
ldapsearch -o ldif_wrap=no -xLLL -s sub -b "ou=people,dc=foo,dc=com" dn > some_file
grep "\S" some_file | wc -l
ldapadd
is similar to ldapmodify
, except as the name suggests it only adds. slapd
needs to be online for the ldif
to be processed by ldapadd
or ldapmodify
.
It is not possible to ldapadd
an ldif
file generated by slapcat
- which is typically used to backup an ldap instance's config and user-data. To do this would involve changes by hand. Excerpt from man page
for slapcat
:
The output of slapcat is intended to be used as input to slapadd(8). The output of slapcat cannot generally be used as input to ldapadd(1) or other LDAP clients without first editing the output. This editing would normally include reordering the records into superior first order and removing no-user-modification operational attributes.
dn: cn=user,ou=example,dc=example,dc=com
changetype: modify
replace: userPassword
userPassword: use_slappasswd_to_generate
Dry mode -u
very useful to check before doing a final slapadd
operation.
Slapadd performance:
olcToolThreads
- set this to 2. Specify the maximum number of threads to use in tool mode. This should not be greater than the number of CPUs in the system. The default is 1. This effects slapdadd performance. It gets added to cn: config
.
Given the below ldif or similar, if you hit error ldap_modify: Other (e.g., implementation specific) error (80)
you may need to check/disable selinux
.
dn: cn=config
changetype: modify
replace: olcTLSCACertificateFile
olcTLSCACertificateFile: /path/to/cert.crt
-
replace: olcTLSCertificateFile
olcTLSCertificateFile: /path/to/cert.crt
-
replace: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /path/to/key.key
This ldif is requiring that access to the DIT is protected by a TLS connection - to disallow plain text communication.
dn: olcDatabase={2}mdb,cn=config
changetype: modify
replace: olcSecurity
olcSecurity: tls=1
Best to refer to the documentation so this...
https://www.openldap.org/doc/admin26/access-control.html
...but some guidance is here.
Using an LDIF like this will enable you to completely replace the FULL access list for mdb{2}.
This example is incomplete/partial and should be adapted as you see fit... it is merely an example ldif.
dn: olcDatabase={2}mdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0} to attrs=userPassword by dn="cn=SomeAdmin,ou=Administrators,dc=example,dc=com" write by anonymous auth by self =xw by * none
olcAccess: {1} to some_other_stuff by some_other_thing
olcAccess: {2} to dn.base="" by * read
=xw
is giving explicit auth+write, whereas write gives more.
The last line is necessary otherwise binds are broken. It is providing access to the DSE, so a client can determine some information in order to connect.
If you make ACL changes on the master which you expect to impact a replica , it is advisable to clean and restart the replica.
See:
If your ACLs change, then the LDAP server will be sending you notifications about entries which (until just now) did not exist to you, or the LDAP server will not send you notifications about entries that you now can no longer see. This manifests as weird consistency issues, which might cause exceptions to be thrown, or (even worse) might not.
https://syncrepl-client.readthedocs.io/en/latest/gotchas.html
Example LDIF to turn ACL logging on.
dn: cn=config
changetype: modify
replace: olcLogLevel
olcLogLevel: 128
Before proceeding with final stags (slapadd) verify /etc/openldap/slapd.d is correct location.
-
install OS on new server
-
install ldap server via RPM/DEB/compile etc.
-
ensure slapd is stopped
systemctl stop slapd
-
copy over config.ldif to /root/ on new master (config.ldif being the slapcat dump/backup from previous master)
-
replace hdb with mdb in config.ldif
sed -i 's/hdb/mdb/g' config.ldif
sed -i 's/Hdb/Mdb/g' config.ldif
-
ensure olcDbMaxSize is set by editing the config.ldif
cn: olcDatabase={2}mdb,cn=config
...
...
...
olcDbMaxSize: 1000000000
- move/backup the slapd.d dir that was provided by the install earlier
cd /etc/openldap/
cp -a slapd.d slapd.d.orig
- empty the slapd.d
rm -rf slapd.d/*
- import the config.ldif (config db dump)
slapadd -v -F /etc/openldap/slapd.d -n0 -l /root/config.ldif
- import the data.ldif (data dump)
slapadd -v -F /etc/openldap/slapd.d -l /root/data.ldif
- ensure ldap:ldap owner on slapd.d
chown -R ldap:ldap /etc/openldap/slapd.d
- sort out certificates
(generation or migration of certs is not covered here)
- start sladp
systemctl start slapd
Obviously this can be caused by many things, but do check the systemd pidfile location AND also check olcPidFile in cn=config. It may be olcPidFile needs set (to match systemd). Check logs for pidfile error.
Search a slapcat dump entry within an ldif dump file.
sed -n '/dn: cn=Something/,/modifiersName:/p' data.ldif | grep something
slapo-ppolicy
Taken from above URL 13.09.24
Table 3.1. Available Combinations of Identity and Authentication Providers
Identity Provider | Authentication Provider |
---|---|
Identity Management [a] | Identity Management |
Active Directory | Active Directory |
LDAP | LDAP |
LDAP | Kerberos |
Proxy | Proxy |
Proxy | LDAP |
Proxy | Kerberos |
[a] An extension of the LDAP provider type.
https://ldap3.readthedocs.io/en/latest/index.html
#!/srv/example/example_venv/bin/python3 or python3 somewhere
from ldap3 import Server, Connection, ALL
server = Server('ldaps://example', get_info=ALL, use_ssl=True, port=636)
conn = Connection(server, 'cn=binduser,dc=example,dc=ex,dc=uk', 'SOME_PW', auto_bind=True)
filter = '(objectclass=posixAccount)'
var_attributes=['sn','cn']
conn.search(search_base='dc=example,dc=ex,dc=uk', search_filter=filter, attributes=var_attributes, search_scope='SUBTREE')
debug1=conn.entries
print(debug1)
String based length
4.1.2. Attribute Types
A suggested minimum upper bound on the number of characters in a
value with a string-based syntax, or the number of bytes in a value
for all other syntaxes, may be indicated by appending this bound
count inside of curly braces following the syntax's OBJECT IDENTIFIER
in an Attribute Type Description. This bound is not part of the
syntax name itself. For instance, "1.3.6.4.1.1466.0{64}" suggests
that server implementations should allow a string to be 64 characters
long, although they may allow longer strings. Note that a single
character of the Directory String syntax may be encoded in more than
one octet since UTF-8 [RFC3629] is a variable-length encoding.
https://www.rfc-editor.org/rfc/rfc4512.txt
-
You need an olcRootDN entry, its important the suffix is correct to apply this
dn: olcDatabase={0}config,cn=config changetype: modify replace: olcRootDN olcRootDN: cn=admin,cn=config
-
You need a corresponding olcRootPW entry
dn: olcDatabase={0}config,cn=config changetype: modify replace: olcRootPW olcRootPW: {SSHA}sddasdsadsssomestuffheresadasdasdasda
-
Then configure the Apache DS connection to use these settings
Bind DN:
cn=admin,cn=config
Bind password
*****
Base DN
cn=config