Size: 59330
Comment: group info about old slapd.conf with info about newer DIT storage
|
Size: 62131
Comment: Correcting security mistake in "Force StartTLS or SSL connection", adding explaination about olcLocalSSF
|
Deletions are marked like this. | Additions are marked like this. |
Line 1: | Line 1: |
[[https://openldap.org/|OpenLDAP]] is an [[OpenSource|open source]] implementation of the [[WikiPedia:Lightweight Directory Access Protocol]]. It includes [[DebianPkg:libldap-2.4-2|libraries]], [[DebianPkg:ldap-utils|clients]], and a [[DebianPkg:slapd|server]]. This page is about configuring and running the OpenLDAP Standalone LDAP Daemon `slapd` on Debian. | [[https://openldap.org/|OpenLDAP]] is an [[OpenSource|open source]] implementation of the [[LDAP]] protocol. It includes [[DebianPkg:libldap-2.4-2|libraries]], [[DebianPkg:ldap-utils|clients]], and a [[DebianPkg:slapd|server]]. This page is about configuring and running the OpenLDAP Standalone LDAP Daemon `slapd` on Debian. |
Line 6: | Line 6: |
The OpenLDAP server is provided by the DebianPkg:slapd package and the tools for interacting with, querying and modifying entries in local or remote LDAP servers are provided by the DebianPkg:ldap-utils package, so start by installing these: {{{ # apt install slapd ldap-utils Reading package lists... Done Building dependency tree Reading state information... Done The following additional packages will be installed: [...] Do you want to continue? [Y/n] Y [...] Configuring slapd ----------------- Please enter the password for the admin entry in your LDAP directory. Administrator password: SECRET Please enter the admin password for your LDAP directory again to verify that you have typed it correctly. Confirm password: SECRET [...] }}} As can be seen from the above example, you will be prompted to provide a password for the database administrator as part of the installation (or, in case of a noninteractive installation, a random password will be set). |
[[PackageManagement#Installing.2C_removing.2C_upgrading_software|Install]] the following packages: * [[DebianPkg:slapd]] - the OpenLDAP server * [[DebianPkg:ldap-utils]] - tools for interacting with, querying and modifying entries in local or remote LDAP servers `debconf` will prompt you for a password for the database administrator (or, in case of a noninteractive installation, a random password will be set). |
Line 47: | Line 29: |
The OpenLDAP specific tools are low-level, and meant to be executed directly on the systems where `slapd` has been installed (they can generally be executed while `slapd` isn't running as they access the underlying database(s) directly). |
|
Line 59: | Line 44: |
The generic tools can be used on servers as well as clients. |
|
Line 70: | Line 58: |
The OpenLDAP specific tools are low-level, and meant to be executed directly on the systems where `slapd` has been installed (they can generally be executed while `slapd` isn't running as they access the underlying database(s) directly), while the generic tools can be used on servers as well as clients. |
|
Line 77: | Line 63: |
{{{#!wiki note | |
Line 78: | Line 65: |
}}} | |
Line 249: | Line 237: |
The ``dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth`` entry is a rather prolix way of defining the system `root` user (`uid` and `gid` 0), connecting via SASL EXTERNAL authentication. | The {{{dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth}}} entry is a rather prolix way of defining the system `root` user (`uid` and `gid` 0), connecting via SASL EXTERNAL authentication. |
Line 271: | Line 259: |
Here's an example of how to change the default ACLs so that 'chsh' and 'chfn' can work with LDAP by giving users write access to their own (and administrator access to everyone's) {{{loginShell}}} and {{{gecos}}} attributes: | Here's an example of how to change the default ACLs so that `chsh` and `chfn` can work with LDAP by giving users write access to their own (and administrator access to everyone's) {{{loginShell}}} and {{{gecos}}} attributes: |
Line 287: | Line 275: |
If you choose to use LDAP for many functions, such as having a single server for DNS, Authentication, and networking flat file database replacement, you may wish to have LDAP administrative users for each subtree in addition to the global admin ({{{dn="cn=admin, dc=example, dc=com}}}). The following example is useful when using a separate authentication tree which includes Samba. | If you choose to use LDAP for many functions, such as having a single server for DNS, Authentication, and networking flat file database replacement, you may wish to have LDAP administrative users for each subtree in addition to the global admin ({{{dn="cn=admin, dc=example, dc=com}}}). The following example is useful when using a separate authentication tree which includes [[Samba]]. |
Line 442: | Line 430: |
FIXME: revise, update and merge these two | |
Line 446: | Line 433: |
To enable [[WikiPedia:Transport_Layer_Security|TLS]] in `slapd`, you will need the '''server certificate''' and the associated '''private key''', both in [[WikiPedia:Privacy-Enhanced_Mail|PEM]] format. You may also have an '''intermediate certificate'''. Clients will need the '''CA certificate''' which is the Issuer of the server or intermediate certificate. | To enable [[WikiPedia:Transport_Layer_Security|TLS]] in `slapd`, the server needs the '''server certificate''' and the associated '''private key''', both in [[WikiPedia:Privacy-Enhanced_Mail|PEM]] format. You may also have an '''intermediate certificate'''. Clients will need the '''CA certificate''' which is the Issuer of the server or intermediate certificate. |
Line 449: | Line 436: |
The error {{{main: TLS init def ctx failed: -1}}} in server logs may indicate a permission problem on certificate/key files. |
|
Line 482: | Line 471: |
By default, `slapd` supports [[WikiPedia:StartTLS|StartTLS]] on the standard LDAP port 389. If you wish to enable the LDAPS protocol on port 636, then edit `/etc/default/slapd`, add `ldaps:///` to the `SLAPD_SERVICES` line, and restart `slapd`. | If a client uses an LDAP URL for connection configuration, it can be configured to use StartTLS by including the StartTLS extension in the URL (the {{{ldapurl(1)}}} tool is useful for constructing correct LDAP URLs). For example: {{{ ldap://ldap.example.com/dc=example,dc=com????!StartTLS }}} == Enabling LDAPS on port 636 == By default, `slapd` only supports [[WikiPedia:StartTLS|StartTLS]] on the standard LDAP port 389. Some legacy LDAP clients do not support the StartTLS operation, but are able to use LDAPS (LDAP over SSL) on port 636. If you wish to enable the LDAPS protocol on port 636 to support such clients, then edit `/etc/default/slapd`, add `ldaps:///` to the `SLAPD_SERVICES` line, and restart `slapd`. |
Line 504: | Line 503: |
== Configuring TLS/SSL == By default, slapd runs as user/group openldap, so it can't read the key file. On Debian Lenny, the preferred solution to this dilemma seems to be to chown the key to root:ssl-cert, set permissions to 640 and add the user openldap to group ssl-cert: {{{ usermod -a -G ssl-cert openldap }}} In Wheezy, not adding openldap to the ssl-cert group caused this in logs: {{{ main: TLS init def ctx failed: -1 }}} === Enable LDAPS (if required) === StartTLS is the standard operation for initiating TLS/SSL on an LDAP connection. StartTLS operates on the standard LDAP port (389) and no alternative port is necessary. Clients using OpenLDAP libldap can be configured to use StartTLS, if they use an LDAP URL for connection configuration, by including the StartTLS extension in the URL. For example: {{{ ldap://ldap.example.com/dc=example,dc=com????!StartTLS }}} The {{{ldapurl(1)}}} tool is useful for constructing correct LDAP URLs. Some legacy LDAP clients do not support the StartTLS operation, but are able to use LDAPS (LDAP over SSL) on port 636. To support such clients, add {{{ldaps:///}}} to the {{{SLAPD_SERVICES}}} list in {{{/etc/default/slapd}}}. {{{ SLAPD_SERVICES="ldap:/// ldapi:/// ldaps:///" }}} === Symptoms: === In {{{slapd}}} debug output: {{{ [...] TLS: could not set cipher list HIGH:MEDIUM:-SSLv2. (or similar) }}} In /var/log/syslog: {{{ [...] main: TLS init def ctx failed: -1 }}} === Diagnosis: === If you try to install the OpenLDAP server ({{{slapd}}}) with Debian Lenny, it comes compiled against the GnuTLS library. It means you cannot use an OpenSSL style directive like {{{TLSCipherSuite HIGH:MEDIUM:-SSLv2}}} in {{{slapd.conf}}}. === Cure: === In {{{/etc/ldap/slapd.conf}}}, either comment out `TLSCipherSuite` option to let gnutls choose rather sane default for you, or use something like: {{{ TLSCipherSuite NORMAL }}} To get all the supported GnuTLS cipher suite names: {{{ # aptitude install gnutls-bin # man gnutls-cli }}} And skip to `TLS/SSL control options` section of man page. To use only 256 bit cyphers, use this (paranoiac?) setting: |
== Force StartTLS or SSL connection == By default, client can connect with StartTLS, SSL or without encryption. If you wish to disable connection without encryption and allow only secured connection with StartTLS or SSL, you can add `olcSecurity` option with value `ssf=n`. Where n is the minimum number of bits required for the cryptographic key. All connections with key below that value will be denied. Normally values of the key lenght would be 40, 56, 64, 128, 164 and 256 More over the `olcLocalSSF` have to be equal or higher than `olcSecurity` or the ldapi connection will be denied. {{{ ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF dn: cn=config changetype: modify replace: olcLocalSSF olcLocalSSF: 128 - replace: olcSecurity olcSecurity: ssf=128 EOF }}} == Troubleshooting == '''`[...] TLS: could not set cipher list HIGH:MEDIUM:-SSLv2.` in {{{slapd}}} debug output:, `[...] main: TLS init def ctx failed: -1` in syslog:''' If you try to install ({{{slapd}}}) with Debian Lenny, it comes compiled against the GnuTLS library. It means you cannot use an OpenSSL style directive like {{{TLSCipherSuite HIGH:MEDIUM:-SSLv2}}} in {{{slapd.conf}}}. In {{{/etc/ldap/slapd.conf}}}, either comment out `TLSCipherSuite` option to let gnutls choose rather sane default for you, or use something like `TLSCipherSuite NORMAL` For info about the supported GnuTLS cipher suite names, see the [[DebianPkg:gnutls-bin]] package and the `TLS/SSL control options` in [[DebianMan:gnutls-cli.1]] To use only 256 bit cyphers, use this setting: |
Line 563: | Line 533: |
Another useful tool to test server-supported TLS options is to use `gnutls-cli-debug`. First add `ldaps:///` string to the `SLAPD_SERVICES` option in `/etc/default/slapd`, restart `slapd` and then run {{{ gnutls-cli-debug -p 636 <fqdn_of_you_ldap_host> }}} That will show you cryptographic suits your LDAP server supports. === Symptoms (round 2) === If you are getting messages such as {{{ slapd TLS: can't connect: A TLS packet with unexpected length was received.. }}} or {{{ Could not negotiate a supported cipher suite. }}} take a wander by this. === Diagnosis: === How did you generate your certificates? If you generated them using OpenSSL, you're going to run into problems. Debian switched over to using gnutls a while ago, and it doesn't play nice with OpenSSL certificates. So, to fix this, check out the next section. NOTE: On Debian Squeeze openldap is linked with gnutls as well, but works just fine with certificate generated by openssl. NOTE about the above note: I don't find it to be the case, except for the CA cert. I ended up having to generate a new key & csr to sign with gnutls's certtool and then signing it with my existing openssl created CA like so: {{{ certtool --generate-privkey --outfile ldap.gnutls.key certtool --generate-certificate --load-privkey ldap.gnutls.key --outfile ldap.gnutls.crt --load-ca-certificate ca.crt --load-ca-privkey ca.key }}} Again, this allows you to keep your existing OpenSSL CA. ldapsearch -x -LLL -s base -b "" === Procedure: === You're going to need the gnutls certificate generator: [[http://www.gnu.org/software/gnutls/manual/html_node/The-certtool-application.html|certtool]] available in DebPkg:gnutls-bin Run these two commands to generate a new self-signed key (into the current working directory): {{{ certtool --generate-privkey --outfile ca-key.pem certtool --generate-self-signed --load-privkey ca-key.pem --outfile ca-cert.pem }}} Then, update your certificate locations in /etc/ldap/slapd.conf ({{{TLSCertificateFile}}} points to ca-cert.pem and {{{TLSCertificateKeyFile}}} points to ca-key.pem), comment out {{{TLSCACertificateFile}}}, and change {{{TLSVerifyClient}}} to {{{never}}}. In /etc/ldap/ldap.conf, comment out {{{TLS_CACERT}}} and change {{{TLS_REQCERT}}} to {{{never}}}. Since the certificate is self-signed, we can't have gnutls trying to verify it (hence the {{{never}}}), otherwise it will never run. Then restart your services, and you're good (assuming all your links point properly to ldaps://url/). |
Another useful tool to test server-supported TLS options is to use `gnutls-cli-debug`. First add `ldaps:///` string to the `SLAPD_SERVICES` option in `/etc/default/slapd`, restart `slapd`, then run `gnutls-cli-debug -p 636 <fqdn_of_you_ldap_host>`. That will show you cryptographic suits your LDAP server supports. '''`slapd TLS: can't connect: A TLS packet with unexpected length was received..` or `Could not negotiate a supported cipher suite.`:''' Debian uses GnuTLS, and it doesn't play nice with OpenSSL certificates. Use the gnutls certificate generator [[http://www.gnu.org/software/gnutls/manual/html_node/The-certtool-application.html|certtool]], available in [[DebPkg:gnutls-bin]]. See [[DebianMan:certtool.1]]. * Generate a new CA key, and a self-signed certificate into the current working directory: {{{ # generate a CA private key certtool --generate-privkey --outfile ca.key # generate a self-signed CA certificate certtool --generate-self-signed --load-privkey ca.key --outfile ca.crt }}} * update {{{TLSCertificateKeyFile}}} and {{{TLSCertificateFile}}} options with your key/certificate locations in {{{/etc/ldap/slapd.conf}}} * comment out {{{TLSCACertificateFile}}} and change {{{TLSVerifyClient}}} to {{{never}}}. * restart slapd {{{systemctl restart slapd}}} Since this certificate is self-signed, certificate verification must be disabled on LDAP clients: * In {{{/etc/ldap/ldap.conf}}}, comment out {{{TLS_CACERT}}} and change {{{TLS_REQCERT}}} to {{{never}}}. * configure your client to use the {{{ldaps://}}} URL. If you have an existing CA private key/certificate and wish to sign {{{slapd}}}'s certificate with it. this allows you to keep your existing OpenSSL CA: {{{ certtool --generate-privkey --outfile ldap.key certtool --generate-certificate --load-privkey ldap.key --outfile ldap.crt --load-ca-certificate my.ca.crt --load-ca-privkey my.ca.key }}} Verify with `ldapsearch -x -LLL -s base -b ""` |
Line 615: | Line 570: |
Since version 4, DebianPkg:samba is able to act as an [[https://en.wikipedia.org/wiki/Active_Directory|Active Directory]] [[https://en.wikipedia.org/wiki/Domain_controller|Domain Controller]], which essentially ties together LDAP, Kerberos, DNS and other services. In order to do so, Samba includes internal implementations of the necessary services. Instructions for setting up Samba to act as an AD DC can be found in the [[https://wiki.samba.org/index.php/Setting_up_Samba_as_an_Active_Directory_Domain_Controller|Samba wiki]]. |
Since version 4, [[Samba]] is able to act as an [[https://en.wikipedia.org/wiki/Active_Directory|Active Directory]] [[https://en.wikipedia.org/wiki/Domain_controller|Domain Controller]], which essentially ties together LDAP, Kerberos, DNS and other services. In order to do so, Samba includes internal implementations of the necessary services. See [[Samba/ActiveDirectoryDomainController]] It is still possible to use OpenLDAP as a backend for user account information for old, NT4-style Domain setups. See [[Samba/DcWithLdapBackend]] |
Line 620: | Line 575: |
{{{#!wiki note Older/obsolete information on setting up LDAP + Kerberos can be found at [[LDAP/OpenLDAPSetup#Kerberos]] }}} |
|
Line 750: | Line 711: |
Next, create `/etc/krb5.conf` with the following contents: | Next, create `/etc/krb5.conf` with the following basic information about your realm (this file should be copied to all clients as well): |
Line 767: | Line 728: |
} }}} And, put the server-specific configuration in `/etc/krb5kdc/kdc.conf` (which has the same format as `/etc/krb5.conf`): {{{ [realms] EXAMPLE.COM = { |
|
Line 769: | Line 739: |
[dbdefaults] ldap_kerberos_container_dn = cn=kerberos,ou=Services,dc=example,dc=com |
|
Line 776: | Line 743: |
ldap_kerberos_container_dn = cn=kerberos,ou=Services,dc=example,dc=com |
|
Line 1368: | Line 1337: |
See [[http://www.openldap.org/doc/admin24/replication.html]] for a detailed explanation of OpenLDAP Replication. Several types of replication are possible, this section focuses on how to configure !MirrorMode Replication (`syncrepl`), which can be achived by following the steps below. === 1: Create a special user for the replication of the data. === This by default can't be done using the SASL/EXTERNAL authentication, since you will get a 'no write access to parent' error. Please use a basedn suited to your situation, in example change the "dc=nodomain" to the basedn for your server. Please see step 7 for the password chosen and use {{{slappasswd}}} command to format it. {{{ $ ldapmodify -D "cn=admin,dc=nodomain" -W<<EOT > dn: cn=mirrormode,dc=nodomain > changetype: add > objectClass: simpleSecurityObject > objectClass: organizationalRole > cn: mirrormode > description: Syncrepl user for mirrormode operation > userPassword: e1NTSEF9SktNQmpPV29zOEtPSCtaWmdDeTVUa056U3c5NWF5bis= > EOT Enter LDAP Password: adding new entry "cn=mirrormode,dc=nodomain" $ }}} All the other steps can easily be done using the SASL/EXTERNAL authentication as explained in [[https://wiki.debian.org/LDAP/OpenLDAPSetup#Missing_slapd.conf.3F|Missing slapd.conf]]. Just save the given information in a file and load it with: $ ldapmodify -Y EXTERNAL -H ldapi:/// -f <file.ldif> === 2: Load the syncrepl module === {{{ |
OpenLDAP supports several different types of replication (see the [[http://www.openldap.org/doc/admin24/replication.html|Administrator's Guide]] for a detailed explanation). This section will focus on one approach, called Multi-Provider. In Multi-Provider mode, each server acts as a ''master''/''producer'', meaning that any server can accept changes to the LDAP database and will propagate it to the other servers. This means that any server can accept changes, even if one or more of the other servers are offline. However, it also means that there will be more traffic between the servers and that there is a risk of [[https://en.wikipedia.org/wiki/Split-brain_(computing)|split-brain]] if changes are performed on different servers during a network split. The create a Multi-Provider cluster, first install `slapd` (see [[#Initial_Installation|initial installation]] above) on each server and edit `/etc/default/slapd` to list each server's own FQDN as part of the `ldap://` URI. In other words, on e.g. `serverA.example.com`, the entry: {{{ SLAPD_SERVICES="ldapi:// ldap://" }}} should read: {{{ SLAPD_SERVICES="ldapi:// ldap://serverA.example.com }}} Next, configure [[#TLS.2FSSL|TLS/SSL]] on each server. Once TLS is up and running, restart `slapd` on each server in order for the changes to `/etc/default/slapd` and the TLS/SSL configuration to take effect: {{{ # systemctl restart slapd }}} Make sure the `syncprov` module is loaded and enabled for the `cn=config` database on each server: {{{ # ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF |
Line 1396: | Line 1371: |
}}} === 3: Set up replicator privileges === Make sure the newly created replication user can read the data to be replicated: {{{ dn: olcDatabase={1}hdb,cn=config changetype: modify delete: olcAccess olcAccess: {0}to attrs=userPassword,shadowLastChange by self write by anonymous auth by dn="cn=admin,dc=nodomain" write by * none - add: olcAccess olcAccess: {0}to attrs=userPassword,shadowLastChange by self write by anonymous auth by dn="cn=admin,dc=nodomain" write by dn="cn=mirrormode,dc=nodomain" read by * none - }}} === 4: Set up the provider slapd === {{{ dn: olcOverlay=syncprov,olcDatabase={1}hdb,cn=config changeType: add |
dn: olcOverlay=syncprov,olcDatabase={0}config,cn=config changetype: add |
Line 1421: | Line 1379: |
}}} === 5: Set up indexing for entryUUID === Note that using the session log requires searching on the entryUUID attribute. Setting an eq index on this attribute will greatly benefit the performance of the session log on the provider: {{{ dn: olcDatabase={1}hdb,cn=config changeType: modify delete: olcDbIndex olcDbIndex: objectClass eq - add: olcDbIndex olcDbIndex: objectClass,entryCSN,entryUUID eq - }}} === 6: Set the server ID. === Make sure you use different ID's for different servers, in example 0, 1, etc...: {{{ |
EOF modifying entry "cn=module{0},cn=config" adding new entry "olcOverlay=syncprov,olcDatabase={0}config,cn=config" }}} Assign an ID to each server: {{{ serverA# ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF |
Line 1440: | Line 1390: |
changeType: modify | changetype: modify |
Line 1442: | Line 1392: |
olcServerID: 0 - }}} === 7: Enable the replication. === Make sure you use the correct IP number for each ldap server and make sure they point to each other! Also, the credentials are just an example. Choose a password of your own of course: {{{ dn: olcDatabase={1}hdb,cn=config changeType: modify add: olcSyncrepl olcSyncrepl: rid=001 provider=ldap://172.16.42.74:389 bindmethod=simple binddn="cn=mirrormode,dc=nodomain" credentials=_ei7N8o.gh=o44 searchbase="dc=nodomain" schemachecking=on type=refreshAndPersist retry="60 +" |
olcServerID: 1 EOF modifying entry "cn=config" serverB# ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF dn: cn=config changetype: modify add: olcServerID olcServerID: 2 EOF modifying entry "cn=config" [...repeat for each server...] }}} Make sure that there is a user with read/write access to the `cn=config` database on each server (note: alternatively, this can be accomplished using ACLs and a separate replication user): {{{ # slappasswd New password: SECRET Re-enter new password: SECRET {SSHA}4D/nsBlxhRDzqBb028tynzJzbO+iNpnA # ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF dn: olcDatabase={0}config,cn=config changetype: modify replace: olcRootDN olcRootDN: cn=admin,cn=config - replace: olcRootPW olcRootPW: {SSHA}4D/nsBlxhRDzqBb028tynzJzbO+iNpnA EOF modifying entry "olcDatabase={0}config,cn=config" }}} Note: run `slappasswd` on each server to generate unique hashes even if you use the same password for all servers. Finally, configure each server with knowledge about the other servers and enable syncing: {{{ # ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF dn: cn=config changetype: modify replace: olcServerID olcServerID: 1 ldap://serverA.example.com/ olcServerID: 2 ldap://serverB.example.com/ [...repeat for any further servers...] dn: olcDatabase={0}config,cn=config changetype: modify add: olcSyncRepl olcSyncRepl: rid=001 provider=ldap://serverA.example.com/ bindmethod=simple binddn="cn=admin,cn=config" credentials=SECRET searchbase="cn=config" type=refreshAndPersist retry="5 5 300 5" timeout=1 starttls=critical tls_reqcert=demand olcSyncRepl: rid=002 provider=ldap://serverB.example.com/ bindmethod=simple binddn="cn=admin,cn=config" credentials=SECRET searchbase="cn=config" type=refreshAndPersist retry="5 5 300 5" timeout=1 starttls=critical tls_reqcert=demand [...repeat for any further servers...] |
Line 1456: | Line 1470: |
- }}} And you're up and running. Try adding something to one of the LDAP servers and see it appear automagically at the other. Well done my friend! |
EOF modifying entry "cn=config" modifying entry "olcDatabase={0}config,cn=config" }}} Note: `olcSyncRepl` and `olcMirrorMode` need to be set in the same transaction, so do not split the above modifications into several commands. Test the replication of the `cn=config` database: {{{ serverA# ldapsearch -LLLQ -Y EXTERNAL -H ldapi:/// -b olcDatabase={-1}frontend,cn=config olcSizeLimit dn: olcDatabase={-1}frontend,cn=config olcSizeLimit: 500 serverB# ldapsearch -LLLQ -Y EXTERNAL -H ldapi:/// -b olcDatabase={-1}frontend,cn=config olcSizeLimit dn: olcDatabase={-1}frontend,cn=config olcSizeLimit: 500 serverA# ldapmodify -Y EXTERNAL -H ldapi:/// <<EOF dn: olcDatabase={-1}frontend,cn=config changetype: modify replace: olcSizeLimit olcSizeLimit: 501 EOF modifying entry "olcDatabase={-1}frontend,cn=config" serverA# ldapsearch -LLLQ -Y EXTERNAL -H ldapi:/// -b olcDatabase={-1}frontend,cn=config olcSizeLimit dn: olcDatabase={-1}frontend,cn=config olcSizeLimit: 501 serverB# ldapsearch -LLLQ -Y EXTERNAL -H ldapi:/// -b olcDatabase={-1}frontend,cn=config olcSizeLimit dn: olcDatabase={-1}frontend,cn=config olcSizeLimit: 501 serverA# # ldapmodify -Y EXTERNAL -H ldapi:/// <<EOF dn: olcDatabase={-1}frontend,cn=config changetype: modify replace: olcSizeLimit olcSizeLimit: 500 modifying entry "olcDatabase={-1}frontend,cn=config" EOF }}} As can be seen from the above example, the change to `olcSizeLimit` on `serverA` was automatically propagated to `serverB`. It is now time to configure the replication of the other databases (e.g. `dc=example,dc=com`). Since the `cn=config` database is now replicated across servers, the remaining steps __only have to be performed on one of the servers__. First, setup indexing for two attributes which are heavily used in the replication: {{{ # ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF dn: olcDatabase={1}mdb,cn=config changetype: modify add: olcDbIndex olcDbIndex: entryCSN eq olcDbIndex: entryUUID eq EOF modifying entry "olcDatabase={1}mdb,cn=config" }}} Second, add the `syncprov` overlay to the database: {{{ # ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF dn: olcOverlay=syncprov,olcDatabase={1}mdb,cn=config changetype: add objectClass: olcOverlayConfig objectClass: olcSyncProvConfig olcOverlay: syncprov EOF adding new entry "olcOverlay=syncprov,olcDatabase={1}mdb,cn=config" }}} Third, enable replication: {{{ # ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF dn: olcDatabase={1}mdb,cn=config changetype: modify add: olcSyncRepl olcSyncRepl: rid=011 provider=ldap://serverA.example.com/ bindmethod=simple binddn="cn=admin,dc=example,dc=com" credentials=SECRET searchbase="dc=example,dc=com" type=refreshAndPersist retry="5 5 300 5" timeout=1 starttls=critical tls_reqcert=demand olcSyncRepl: rid=012 provider=ldap://serverB.example.com/ bindmethod=simple binddn="cn=admin,dc=example,dc=com" credentials=SECRET searchbase="dc=example,dc=com" type=refreshAndPersist retry="5 5 300 5" timeout=1 starttls=critical tls_reqcert=demand [...repeat for any further servers...] - add: olcMirrorMode olcMirrorMode: TRUE EOF modifying entry "olcDatabase={1}mdb,cn=config" }}} Note the changes to the `dn`, `rid`, `binddn` and `searchbase` compared to when replication was enabled for the `cn=config` database. The changes to the configuration will be replicated to the other servers which will then start replicating the `dc=example,dc=com` database. The above three steps need to be repeated for each additional database that you have configured (a default installation has no further databases). |
Line 1463: | Line 1592: |
* The Debian-specific setup and configuration of DebianPkg:slapd are documented in [[https://salsa.debian.org/openldap-team/openldap/raw/master/debian/slapd.README.Debian|/usr/share/doc/slapd/README.Debian.gz]]. * Debian users have contributed some wiki pages about [[LDAP|LDAP and OpenLDAP]]. * OpenLDAP includes comprehensive documentation in the form of [[ManPage|man pages]]. In the beginning you will likely need (at least) [[DebianMan:5/slapd-config|slapd-config(5)]], [[DebianMan:1/ldapsearch|ldapsearch(1)]], [[DebianMan:1/ldapmodify|ldapmodify(1)]], and [[DebianMan:5/ldif|ldif(5)]]. There are individual man pages for significant features of [[DebianMan:8/slapd|slapd(8)]] such as [[DebianMan:5/slapd-config|configuration]], [[DebianMan:5/slapd.access|access control]], [[DebianMan:5/slapd.backends|backends]], and [[DebianMan:5/slapd.overlays|overlays]]. * The OpenLDAP project maintains an [[https://openldap.org/doc/admin24/|Administrator's Guide]]. * The Ubuntu Server Guide includes [[https://ubuntu.com/server/docs/service-ldap|a chapter on OpenLDAP]], including guides for specific use cases. * The [[Derivatives/Census/DebOps|DebOps]] project maintains an [[https://github.com/debops/debops/tree/master/ansible/roles/slapd|Ansible role for OpenLDAP]] which provides a good starting point for a real-world setup * LDAP is defined in a number of [[WikiPedia:Request_for_Comments|RFC]] documents, beginning with [[RFC:4510|RFC 4510]]. * More information about LDAP in general may be found on [[https://ldap.com/|LDAP.com]]. * Questions about the Debian packages may be emailed to the maintainers at pkg-openldap-devel@lists.alioth.debian.org. Please check [[DebianBug:src:openldap|the list of open bugs]] in case your issue is already known. * Questions about OpenLDAP software may be emailed to the OpenLDAP mailing list at openldap-technical@openldap.org. |
* [[https://salsa.debian.org/openldap-team/openldap/raw/master/debian/slapd.README.Debian|/usr/share/doc/slapd/README.Debian.gz]] (Debian-specific setup and configuration) * [[ManPage|man pages]]: [[DebianMan:slapd-config.5]], [[DebianMan:slapcat.1]], [[DebianMan:ldapsearch.1]], [[DebianMan:ldapmodify.1]], and [[DebianMan:ldif.1]], [[DebianMan:slapd.1]], [[DebianMan:slapd.8]], [[DebianMan:slapd.access.5]], [[DebianMan:slapd.backends.5]], [[DebianMan:slapd.overlays.5]]. * [[https://openldap.org/doc/admin24/guide.html|OpenLDAP Software 2.4 Administrator's Guide]]. * [[https://ubuntu.com/server/docs/service-ldap|LDAP - Ubuntu Server documentation]] * The [[Derivatives/Census/DebOps|DebOps]] project's [[https://github.com/debops/debops/tree/master/ansible/roles/slapd|Ansible role for OpenLDAP]] * [[RFC:4510|RFC 4510]] - Lightweight Directory Access Protocol (LDAP) * [[https://alioth-lists.debian.net/cgi-bin/mailman/listinfo/pkg-openldap-devel|Pkg-openldap-devel]] Debian mailing list * [[DebianBug:src:openldap|src:openldap - Debian Bug Tracking System]] * [[https://www.openldap.org/lists/|OpenLDAP Mailing lists]] |
Line 1476: | Line 1605: |
CategorySystemAdministration | CategorySoftware | CategoryObsolete ToDo: refactor | CategorySystemAdministration | CategorySoftware | ToDo: merge information from [[LDAP/Kerberos]] |
OpenLDAP is an open source implementation of the LDAP protocol. It includes libraries, clients, and a server. This page is about configuring and running the OpenLDAP Standalone LDAP Daemon slapd on Debian.
Contents
Initial Installation
Install the following packages:
slapd - the OpenLDAP server
ldap-utils - tools for interacting with, querying and modifying entries in local or remote LDAP servers
debconf will prompt you for a password for the database administrator (or, in case of a noninteractive installation, a random password will be set).
By default, an initial database is created using the system's DNS domain name. If your system is in the domain example.com, the database suffix (BaseDN) will be dc=example,dc=com. The domain name and other low-level details can be changed by running dpkg-reconfigure -plow slapd after installation.
To check the database suffix, once the server is running, use ldapsearch(1) to read the namingContexts attribute of the root DSE:
# ldapsearch -x -LLL -s base -b "" namingContexts dn: namingContexts: dc=example,dc=com
Tools
After the above installation, two groups of tools will be available on your system:
OpenLDAP specific
The OpenLDAP specific tools are low-level, and meant to be executed directly on the systems where slapd has been installed (they can generally be executed while slapd isn't running as they access the underlying database(s) directly).
LDAP generic
The generic tools can be used on servers as well as clients.
Configuration
Since version 2.3 (released in 2005), the actual configuration for OpenLDAP servers is managed within a special database (DIT), typically rooted at the cn=config entry. This configuration system is known as OpenLDAP online configuration, or OLC (and further described in slapd-config(5)).
The old configuration scheme, using a plain slapd.conf(5) file is still supported, but its use is deprecated and support for it will be withdrawn in a future release. There is, however, still a lot of online documentation which refers to the old configuration scheme and which therefore needs to be adapted to the new configuration scheme.
After the initial installation, the config tree will typically look something like this:
# ldapsearch -LLLQ -Y EXTERNAL -H ldapi:/// -b cn=config dn dn: cn=config dn: cn=module{0},cn=config dn: cn=schema,cn=config dn: cn={0}core,cn=schema,cn=config dn: cn={1}cosine,cn=schema,cn=config dn: cn={2}nis,cn=schema,cn=config dn: cn={3}inetorgperson,cn=schema,cn=config dn: olcDatabase={-1}frontend,cn=config dn: olcDatabase={0}config,cn=config dn: olcDatabase={1}mdb,cn=config
the cn=config root entry contains global settings
cn=module{0},cn=config stores a list of dynamically loaded modules
cn=schema,cn=config contains the built-in system schema definitions with user schema as child entries
the olcDatabase={-1}frontend,cn=config entry contains further global settings (but ones which might affect or be affected by dynamically loadable modules)
the remaining olcDatabase={id}type,cn=config entries contain per-database settings.
While editing a configuration using the various LDAP tools LDIF records may seem a bit unwieldy, such knowledge is anyway necessary for day-to-day interaction with the LDAP directory. Additionally, the advantage of online configuration is that configuration changes can be applied without having to restart the slapd server and, since the configuration is just another database, it is also replicated to other servers.
The mapping between the old configuration options and the new style options can often be determined by consulting the slapd-config(5) man page (and, if necessary, by comparing with the slapd.conf(5) man page). It is also possible to introspect a running slapd instance to find the configuration classes/attributes which are actually available on that particular instance.
To do so, first find the name of the (sub)entry holding the controlling (sub)schema for the cn=config DIT:
# ldapsearch -Y EXTERNAL -H ldapi:/// -LLLQ -b "cn=config" -s base subschemaSubentry dn: cn=config subschemaSubentry: cn=Subschema
then read out a list of attributes from this entry:
# ldapsearch -x -LLL -b cn=Subschema -s base '(objectClass=subschema)' +
Note: this will generally produce a lot of output, you might want to grep for things like the objectClass definition of the olcGlobal class:
# ldapsearch -x -LLL -b cn=Subschema -s base -o ldif-wrap=no '(objectClass=subschema)' + | \ grep "^objectClasses:" | \ grep "NAME 'olcGlobal'"
Schema Files
One of the consequences of the change from the slapd.conf configuration system to the online configuration system is that the handling of LDAP Schema files is also different.
Traditionally, files ending in .schema, either installed in /etc/ldap/schema or, sometimes, somewhere under /usr/share/doc/<package>/ were included in the legacy slapd.conf file.
Under the new configuration system, files ending in .ldif can be imported into the configuration using ldapadd(1). This copies them into the configuration database and the source files are no longer used afterward.
The slapd package includes .ldif versions of schema files in /etc/ldap/ldif, but many other packages (and online articles on configuring OpenLDAP) only provide .schema files, which need to be converted to .ldif format before they can be used.
One tool for doing so is the schema2ldif utility provided by the schema2ldif package:
# apt install schema2ldif [...] # schema2ldif < /usr/share/doc/<package>/<xyz>.schema > /tmp/<xyz>.ldif # ldapadd -Q -Y EXTERNAL -H ldapi:/// -f /tmp/<xyz>.ldif adding new entry "cn=<xyz>,cn=schema,cn=config"
Database Backends
OpenLDAP supports a number of different database backends, the default one being MDB and the alternatives slated for removal. Unless you have specific needs, like running a legacy installation, you should stick with the default.
It is, however, worth pointing out that the backend type is reflected in the configuration tree (see, for example, the olcDatabase={1}mdb,cn=config entry in the previous section), meaning that you might have to adapt configuration examples provided in various guides found on the Internet if they are based on other backends.
Permissions
Administrator Access
In Buster and earlier releases, an administrator entry is created under the BaseDN (e.g. cn=admin,dc=example,dc=com) as part of the initial database creation:
# ldapsearch -LLLQ -Y EXTERNAL -H ldapi:/// -b dc=example,dc=com dn: dc=example,dc=com objectClass: top objectClass: dcObject objectClass: organization o: example.com dc: example dn: cn=admin,dc=example,dc=com objectClass: simpleSecurityObject objectClass: organizationalRole cn: admin description: LDAP administrator
While no such entry is present after installing slapd in later releases:
# ldapsearch -LLLQ -Y EXTERNAL -H ldapi:/// -b dc=example,dc=com dn: dc=example,dc=com objectClass: top objectClass: dcObject objectClass: organization o: example.com dc: example
The administrator is also defined separately in the OpenLDAP configuration, on a per-datbase basis, via the olcRootDN and olcRootPW attributes:
# ldapsearch -LLLQ -Y EXTERNAL -H ldapi:/// -b "olcDatabase={1}mdb,cn=config" olcRootDN OlcRootPW dn: olcDatabase={1}mdb,cn=config olcRootDN: cn=admin,dc=example,dc=com olcRootPW: {SSHA}37s466RsEERQnkgsaj5IL6MfW8JwRhdq
Note that the olcRootDN does not have to refer to an actual entry in the database. Also, the user defined in olcRootDN is not subject to any access control list, ACL, checks or other checks, such as password policies defined by using the ppolicy overlay, which may be a positive or a negative, depending on your preferences.
This duplicate administrator definition can be addressed either by deleting the cn=admin,dc=example,dc=com entry (which would match the behavior of later Debian packages):
# ldapdelete -x -D "cn=admin,dc=example,dc=com" -W -H ldapi:/// cn=admin,dc=example,dc=com Enter LDAP Password:
or by deleting the olcRootDN and olcRootPW attributes (in which case appropriate ACLs are necessary to give cn=admin,dc=example,dc=com sufficient rights):
# ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF dn: olcDatabase={1}mdb,cn=config changetype: modify delete: olcRootPW - delete: olcRootDN dn: olcDatabase={0}config,cn=config changetype: modify delete: olcRootDN EOF modifying entry "olcDatabase={1}mdb,cn=config" modifying entry "olcDatabase={0}config,cn=config"
Access Control Lists
The current access control lists are stored as per-database olcAccess attributes in the cn=config database:
# ldapsearch -LLLQ -Y EXTERNAL -H ldapi:/// -b cn=config -s one olcAccess dn: cn=module{0},cn=config dn: cn=schema,cn=config dn: olcBackend={0}mdb,cn=config dn: olcDatabase={-1}frontend,cn=config olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break olcAccess: {1}to dn.exact="" by * read olcAccess: {2}to dn.base="cn=Subschema" by * read dn: olcDatabase={0}config,cn=config olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break dn: olcDatabase={1}mdb,cn=config olcAccess: {0}to attrs=userPassword by self write by anonymous auth by * none olcAccess: {1}to attrs=shadowLastChange by self write by * read olcAccess: {2}to * by * read
The dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth entry is a rather prolix way of defining the system root user (uid and gid 0), connecting via SASL EXTERNAL authentication.
All in all, Debian's default access rules (shown above) allow only the system root user to change the configuration, by connecting with SASL EXTERNAL authentication (which is only possible over the ldapi:/// connection):
# ldapsearch -Y EXTERNAL -H ldapi:/// -b "cn=config"
In addition, the default access rules allow anyone to search the directory without any authentication:
# ldapsearch -x -b "dc=example,dc=com"
Finally, the database administrator has unrestricted access (via the olcRootDN and OlcRootPW attributes discussed above). To connect as the database administrator, use simple authentication, and when prompted, enter the password configured during installation:
# ldapsearch -x -D "cn=admin,dc=example,dc=com" -W -b "dc=example,dc=com"
Access Control Example 1 - chsh and chfn
Here's an example of how to change the default ACLs so that chsh and chfn can work with LDAP by giving users write access to their own (and administrator access to everyone's) loginShell and gecos attributes:
# ldapmodify -Y EXTERNAL -H ldapi:/// <<EOF dn: olcDatabase={1}mdb,cn=config changetype: modify add: olcAccess olcAccess: {1}to attrs=loginShell,gecos by dn="cn=admin,dc=example,dc=com" write by self write by * read EOF
Access Control Example 2 - Multiple LDAP Admins
If you choose to use LDAP for many functions, such as having a single server for DNS, Authentication, and networking flat file database replacement, you may wish to have LDAP administrative users for each subtree in addition to the global admin (dn="cn=admin, dc=example, dc=com). The following example is useful when using a separate authentication tree which includes Samba.
# The manager dn has full write access to the auth subtree # Everyone else has read access to not otherwise protected fields and entries access to dn.sub="ou=auth,dc=example,dc=com" by dn="cn=Manager,ou=auth,dc=example,dc=com" write by * read
Basic Tasks
Logging
The server logs are sent to the system log (syslog and/or the journal). The default log level is none.
To enable basic request logging, change the log level to stats:
# ldapmodify -Q -H ldapi:/// -Y EXTERNAL <<EOF dn: cn=config changetype: modify replace: olcLogLevel olcLogLevel: stats EOF modifying entry "cn=config"
If you wish to disable request logging later, repeat the procedure and set the log level to none.
For more information, read about olcLogLevel in the slapd-config(5) man page.
Database Max Size
The default database uses the LMDB storage backend. This backend requires little configuration or tuning, but there is one important parameter: the max size.
The database is stored in a sparse file, /var/lib/ldap/data.mdb. It has a fixed maximum size, specified by the olcDbMaxSize parameter. The default database has its max size configured to 1 GiB upon installation. When the database reaches its max size, writes (even updates to existing entries) will fail.
Use du(1) to check the actual space used by the database:
du -h /var/lib/ldap/data.mdb
To check the current max size of database #1:
ldapsearch -H ldapi:/// -Y EXTERNAL -b "olcDatabase={1}mdb,cn=config" olcDbMaxSize
To set the max size of database #1 to 10 GiB (10737418240 bytes):
ldapmodify -H ldapi:/// -Y EXTERNAL << EOF dn: olcDatabase={1}mdb,cn=config changetype: modify replace: olcDbMaxSize olcDbMaxSize: 10737418240 EOF
On 32-bit systems, the max size is constrained by address space limitations, and it may not be possible to grow the database larger than about 2 GiB. For larger databases, a 64-bit system is recommended.
For more information, read about maxsize in slapd-mdb(5).
Changing the Administrator's Password
The password configured during installation is saved in two places. To change the password, both values must be updated. If only one is changed, the old password can still be used. This should be fixed in the next release; see Debian bug #821331.
Use slappasswd(8) to hash the new password, and then use ldapmodify(1) to update the hashed password in the olcRootPW attribute in the database configuration.
# slappasswd New password: newpassword Re-enter new password: newpassword {SSHA}zYHmkowzdMxwX0KtEPNak5IbzfY8YmdQ # ldapmodify -H ldapi:/// -Y EXTERNAL SASL/EXTERNAL authentication started SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth SASL SSF: 0 dn: olcDatabase={1}mdb,cn=config changetype: modify replace: olcRootPW olcRootPW: {SSHA}zYHmkowzdMxwX0KtEPNak5IbzfY8YmdQ modifying entry "olcDatabase={1}mdb,cn=config"
Next, use ldappasswd(1) to change the password the administrator's account in the directory.
# ldappasswd -x -D cn=admin,dc=example,dc=com -W -S New password: newpassword Re-enter new password: newpassword Enter LDAP Password: oldpassword
Finally, test authenticating with the old and new passwords, and confirm that only the new password can be used.
# ldapwhoami -x -D cn=admin,dc=example,dc=com -W Enter LDAP Password: oldpassword ldap_bind: Invalid credentials (49) # ldapwhoami -x -D cn=admin,dc=example,dc=com -W Enter LDAP Password: newpassword dn:cn=admin,dc=example,dc=com
Indexes
For better performance do more indexing than the default:
# ldapmodify -Y EXTERNAL -H ldapi:/// <<EOF dn: olcDatabase={1}mdb,cn=config changetype: modify add: olcDbIndex olcDbIndex: cn pres,sub,eq - add: olcDbIndex olcDbIndex: sn pres,sub,eq - add: olcDbIndex olcDbIndex: uid pres,sub,eq - add: olcDbIndex olcDbIndex: displayName pres,sub,eq - add: olcDbIndex olcDbIndex: default sub - add: olcDbIndex olcDbIndex: uidNumber eq - add: olcDbIndex olcDbIndex: gidNumber eq - add: olcDbIndex olcDbIndex: mail,givenName eq,subinitial - add: olcDbIndex olcDbIndex: dc eq EOF
Note: use the correct database backend in the first line, as noted above, the default type is currently mdb.
Do not leave out the - (dash character) from the file, it is needed. After execution of the ldapmodify command, slapd will launch a internal task to create indexes. Don't stop slapd during indexing.
TLS/SSL
Enabling TLS/SSL
To enable TLS in slapd, the server needs the server certificate and the associated private key, both in PEM format. You may also have an intermediate certificate. Clients will need the CA certificate which is the Issuer of the server or intermediate certificate.
The files must all be readable by the openldap user. It is recommended to ensure the private key is not readable by any user except openldap.
The error main: TLS init def ctx failed: -1 in server logs may indicate a permission problem on certificate/key files.
To configure the server certificate, private key, and intermediate certificate used by slapd:
ldapmodify -H ldapi:/// -Y EXTERNAL << EOF dn: cn=config changetype: modify replace: olcTLSCertificateFile olcTLSCertificateFile: /etc/ssl/certs/server.pem - replace: olcTLSCertificateKeyFile olcTLSCertificateKeyFile: /etc/ssl/private/server.key - replace: olcTLSCACertificateFile olcTLSCACertificateFile: /etc/ssl/certs/intermediate.pem EOF
If you do not have an intermediate certificate, the olcTLSCACertificate lines should be omitted. The root CA does not need to be configured in slapd.
If the modifications fail with ldap_modify: Other (e.g., implementation specific) error (80), check the file paths for typos, and ensure the files are readable by the openldap user.
After applying the configuration, test a secure connection using StartTLS:
LDAPTLS_CACERT=/etc/ssl/certs/ca.pem ldapwhoami -H ldap://ldap.example.com -ZZ -x
where ca.pem is the root CA certificate and ldap.example.com is the server's name, exactly matching the Common Name (CN) or Subject Alternative Name (SAN) in the server certificate.
If the secure connection is successful, ldapwhoami should just print anonymous. If it fails, append -d 1 to the command line to enable debug output, and look for lines beginning with TLS:.
If a client uses an LDAP URL for connection configuration, it can be configured to use StartTLS by including the StartTLS extension in the URL (the ldapurl(1) tool is useful for constructing correct LDAP URLs). For example:
ldap://ldap.example.com/dc=example,dc=com????!StartTLS
Enabling LDAPS on port 636
By default, slapd only supports StartTLS on the standard LDAP port 389. Some legacy LDAP clients do not support the StartTLS operation, but are able to use LDAPS (LDAP over SSL) on port 636.
If you wish to enable the LDAPS protocol on port 636 to support such clients, then edit /etc/default/slapd, add ldaps:/// to the SLAPD_SERVICES line, and restart slapd.
vi /etc/default/slapd ... SLAPD_SERVICES="ldap:/// ldapi:/// ldaps:///" ... service slapd restart
LDAPS can be tested the same way, using -H ldaps:// instead of -ZZ:
LDAPTLS_CACERT=/etc/ssl/certs/ca.pem ldapwhoami -H ldaps://ldap.example.com -x
Again, if successful, it should just print anonymous.
For more information, read about TLS Options in the slapd-config(5) man page, noting that the TLS implementation used in Debian is GnuTLS. The OpenLDAP Administrator's Guide also has a chapter about TLS.
Force StartTLS or SSL connection
By default, client can connect with StartTLS, SSL or without encryption. If you wish to disable connection without encryption and allow only secured connection with StartTLS or SSL, you can add olcSecurity option with value ssf=n. Where n is the minimum number of bits required for the cryptographic key. All connections with key below that value will be denied. Normally values of the key lenght would be 40, 56, 64, 128, 164 and 256 More over the olcLocalSSF have to be equal or higher than olcSecurity or the ldapi connection will be denied.
ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF dn: cn=config changetype: modify replace: olcLocalSSF olcLocalSSF: 128 - replace: olcSecurity olcSecurity: ssf=128 EOF
Troubleshooting
[...] TLS: could not set cipher list HIGH:MEDIUM:-SSLv2. in slapd debug output:, [...] main: TLS init def ctx failed: -1 in syslog: If you try to install (slapd) with Debian Lenny, it comes compiled against the GnuTLS library. It means you cannot use an OpenSSL style directive like TLSCipherSuite HIGH:MEDIUM:-SSLv2 in slapd.conf.
In /etc/ldap/slapd.conf, either comment out TLSCipherSuite option to let gnutls choose rather sane default for you, or use something like TLSCipherSuite NORMAL
For info about the supported GnuTLS cipher suite names, see the gnutls-bin package and the TLS/SSL control options in gnutls-cli.1
To use only 256 bit cyphers, use this setting:
TLSCipherSuite SECURE256:!AES-128-CBC:!ARCFOUR-128:!CAMELLIA-128-CBC:!3DES-CBC:!CAMELLIA-128-CBC
Another useful tool to test server-supported TLS options is to use gnutls-cli-debug. First add ldaps:/// string to the SLAPD_SERVICES option in /etc/default/slapd, restart slapd, then run gnutls-cli-debug -p 636 <fqdn_of_you_ldap_host>. That will show you cryptographic suits your LDAP server supports.
slapd TLS: can't connect: A TLS packet with unexpected length was received.. or Could not negotiate a supported cipher suite.: Debian uses GnuTLS, and it doesn't play nice with OpenSSL certificates. Use the gnutls certificate generator certtool, available in gnutls-bin. See certtool.1.
- Generate a new CA key, and a self-signed certificate into the current working directory:
# generate a CA private key certtool --generate-privkey --outfile ca.key # generate a self-signed CA certificate certtool --generate-self-signed --load-privkey ca.key --outfile ca.crt
update TLSCertificateKeyFile and TLSCertificateFile options with your key/certificate locations in /etc/ldap/slapd.conf
comment out TLSCACertificateFile and change TLSVerifyClient to never.
restart slapd systemctl restart slapd
Since this certificate is self-signed, certificate verification must be disabled on LDAP clients:
In /etc/ldap/ldap.conf, comment out TLS_CACERT and change TLS_REQCERT to never.
configure your client to use the ldaps:// URL.
If you have an existing CA private key/certificate and wish to sign slapd's certificate with it. this allows you to keep your existing OpenSSL CA:
certtool --generate-privkey --outfile ldap.key certtool --generate-certificate --load-privkey ldap.key --outfile ldap.crt --load-ca-certificate my.ca.crt --load-ca-privkey my.ca.key
Verify with ldapsearch -x -LLL -s base -b ""
OpenLDAP as a Backend
Samba
Since version 4, Samba is able to act as an Active Directory Domain Controller, which essentially ties together LDAP, Kerberos, DNS and other services. In order to do so, Samba includes internal implementations of the necessary services. See Samba/ActiveDirectoryDomainController
It is still possible to use OpenLDAP as a backend for user account information for old, NT4-style Domain setups. See Samba/DcWithLdapBackend
Kerberos
Older/obsolete information on setting up LDAP + Kerberos can be found at LDAP/OpenLDAPSetup#Kerberos
Configuring MIT Kerberos to use OpenLDAP as a backend allows one to tie Kerberos principals together with user/machine accounts and can be used in lieu of ordinary passwords stored in the userPassword attribute.
In the following instructions, it will be assumed that the Kerberos KDC and the OpenLDAP server will be setup on the same system (server.example.com). If that is not the case, it should be easy enough to adapt the instructions below (in essence by using LDAP over TLS instead of the ldapi:/// unix socket).
First, install the packages containing the LDAP-enabled Kerberos servers (krb5-kdc-ldap and krb5-admin-server) and the schema2ldif tool:
# apt install krb5-kdc-ldap krb5-admin-server schema2ldif
Then load the kerberos schema:
# zcat /usr/share/doc/krb5-kdc-ldap/kerberos.openldap.ldif.gz | ldapadd -Q -Y EXTERNAL -H ldapi:/// adding new entry "cn=kerberos,cn=schema,cn=config"
And add an index on the krbPrincipalName (improves performance and also suppresses some log messages if slapd is configured to log more than default) for the database(s) where you intend to store Kerberos data:
# ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF dn: olcDatabase={1}mdb,cn=config add: olcDbIndex olcDbIndex: krbPrincipalName eq,pres,sub EOF modifying entry "olcDatabase={1}mdb,cn=config"
Next, you need to create and configure two entries which will be used by the Kerberos servers to connect to OpenLDAP. If you are running Kerberos and OpenLDAP on the same system, these steps are optional, but recommended. In order to keep things nicely separated, everything will be created under a separate organizationalUnit. Note that a simple bind (-x -D) is used instead of an EXTERNAL bind since write access to the dc=example,dc=com DIT is necessary:
# ldapadd -x -D cn=admin,dc=example,dc=com -W <<EOF dn: ou=Services,dc=example,dc=com objectClass: organizationalUnit objectClass: top ou: Services dn: ou=kerberos,ou=Services,dc=example,dc=com objectClass: organizationalUnit objectClass: top ou: kerberos dn: uid=kdc,ou=kerberos,ou=Services,dc=example,dc=com uid: kdc objectClass: account objectClass: simpleSecurityObject userPassword: {CRYPT}x description: Kerberos KDC Account dn: uid=kadmin,ou=kerberos,ou=Services,dc=example,dc=com uid: kadmin objectClass: account objectClass: simpleSecurityObject userPassword: {CRYPT}x description: Kerberos Admin Server Account EOF Enter LDAP Password: SECRET adding new entry "ou=Services,dc=example,dc=com" adding new entry "ou=kerberos,ou=Services,dc=example,dc=com" adding new entry "uid=kdc,ou=kerberos,ou=Services,dc=example,dc=com" adding new entry "uid=kadmin,ou=kerberos,ou=Services,dc=example,dc=com"
The passwords that were set for the two users were placeholders, so it is necessary to specify real ones:
# ldappasswd -x -D cn=admin,dc=example,dc=com -W -S uid=kdc,ou=kerberos,ou=Services,dc=example,dc=com New password: SECRET_A Re-enter new password: SECRET_A Enter LDAP Password: SECRET # ldappasswd -x -D cn=admin,dc=example,dc=com -W -S uid=kadmin,ou=kerberos,ou=Services,dc=example,dc=com New password: SECRET_B Re-enter new password: SECRET_B Enter LDAP Password: SECRET
Now the ACLs need to be adapted to grant appropriate permissions to these two new entities. Something like this:
ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF dn: olcDatabase={1}mdb,cn=config add: olcAccess olcAccess: {0}to attrs=krbPrincipalKey by anonymous auth by dn.exact="uid=kdc,ou=kerberos,ou=Services,dc=example,dc=com" read by dn.exact="uid=kadmin,ou=kerberos,ou=Services,dc=example,dc=com" write by self write by * none - add: olcAccess olcAccess: {1}to dn.subtree="cn=krbContainer,ou=kerberos,ou=Services,dc=example,dc=com" by dn.exact="uid=kdc,ou=kerberos,ou=Services,dc=example,dc=com" read by dn.exact="uid=kadmin,ou=kerberos,ou=Services,dc=example,dc=com" write by * none EOF modifying entry "olcDatabase={1}mdb,cn=config"
If you plan to let the KDC track the time of last login success and lockout status (see below), then you will need to change the lines referring to the uid=kdc,ou=kerberos,ou=Services,dc=example,dc=com entry so that it also has write access.
If you skipped creating the kdc and kadmin entities, you instead need to grant permissions to the root user:
ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF dn: olcDatabase={1}mdb,cn=config add: olcAccess olcAccess: {0}to attrs=krbPrincipalKey by anonymous auth by dn.exact="dn:gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" write by self write by * none - add: olcAccess olcAccess: {1}to dn.subtree="cn=krbContainer,ou=kerberos,ou=Services,dc=example,dc=com" by dn.exact="dn:gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" write by * none EOF modifying entry "olcDatabase={1}mdb,cn=config"
Note: if you plan to add principals to entries in subtrees other than cn=krbContainer,ou=kerberos,ou=Services,dc=example,dc=com, like ou=People,dc=example,dc=com, then the ACLs will need to be adapted to grant the appropriate permissions.
Next, create /etc/krb5.conf with the following basic information about your realm (this file should be copied to all clients as well):
[libdefaults] default_realm = EXAMPLE.COM dns_lookup_realm = false dns_lookup_kdc = false ticket_lifetime = 24h forwardable = true proxiable = true rdns = false [realms] EXAMPLE.COM = { kdc = server.example.com admin_server = server.example.com default_domain = example.com }
And, put the server-specific configuration in /etc/krb5kdc/kdc.conf (which has the same format as /etc/krb5.conf):
[realms] EXAMPLE.COM = { database_module = openldap_ldapconf } [dbmodules] openldap_ldapconf = { db_library = kldap ldap_kerberos_container_dn = cn=kerberos,ou=Services,dc=example,dc=com # if either of these is false, then the ldap_kdc_dn needs to # have write access as explained above disable_last_success = true disable_lockout = true ldap_conns_per_server = 5 ldap_servers = ldapi:/// # this object needs to have read rights on # the realm container, principal container and realm sub-trees ldap_kdc_dn = "uid=kdc,ou=kerberos,ou=Services,dc=example,dc=com" # this object needs to have read and write rights on # the realm container, principal container and realm sub-trees ldap_kadmind_dn = "uid=kadmin,ou=kerberos,ou=Services,dc=example,dc=com" # this file will be used to store plaintext passwords used # to connect to the LDAP server ldap_service_password_file = /etc/krb5kdc/service.keyfile # OR, comment out ldap_kdc_dn, ldap_kadmind_dn and # ldap_service_password_file above and enable the following # two lines, if you skipped the step of creating entries/users # for the Kerberos servers #ldap_kdc_sasl_mech = EXTERNAL #ldap_kadmind_sasl_mech = EXTERNAL #ldap_servers = ldapi:/// }
And also create a /etc/krb5kdc/kadm5.acl file specifying the (future) Kerberos principal(s) which should have administrator access (traditionally, all principals ending with /admin):
*/admin@EXAMPLE.COM *
Now, use kdb5_ldap_util to create the Kerberos realm by setting up some basic entries in the LDAP database:
# sudo kdb5_ldap_util -D cn=admin,dc=example,dc=com create -subtrees dc=example,dc=com -r EXAMPLE.COM -s -H ldapi:/// Password for "cn=admin,dc=example,dc=com": Initializing database for realm 'EXAMPLE.COM' You will be prompted for the database Master Password. It is important that you NOT FORGET this password. Enter KDC database master key: SOME_SECRET Re-enter KDC database master key to verify: SOME_SECRET
And use the same utility to store the LDAP passwords which kadmin and kdc need to bind (connect) to the LDAP server (skip if you did not create these entries):
# kdb5_ldap_util -D cn=admin,dc=example,dc=com stashsrvpw -f /etc/krb5kdc/service.keyfile uid=kdc,ou=kerberos,ou=Services,dc=example,dc=com Password for "cn=admin,dc=example,dc=com": SECRET Password for "uid=kdc,ou=kerberos,ou=Services,dc=example,dc=com": SECRET_A Re-enter password for "uid=kdc,ou=kerberos,ou=Services,dc=example,dc=com": SECRET_A # kdb5_ldap_util -D cn=admin,dc=example,dc=com stashsrvpw -f /etc/krb5kdc/service.keyfile uid=kadmin,ou=kerberos,ou=Services,dc=example,dc=com Password for "cn=admin,dc=example,dc=com": SECRET Password for "uid=kadmin,ou=kerberos,ou=Services,dc=example,dc=com": SECRET_B Re-enter password for "uid=kadmin,ou=kerberos,ou=Services,dc=example,dc=com": SECRET_B
Now it's finally time to start the Kerberos servers:
# systemctl start krb5-kdc krb5-admin-server
Try adding a Kerberos principal with the kadmin.local tool:
# kadmin.local Authenticating as principal root/admin@EXAMPLE.COM with password. kadmin.local: addprinc bob WARNING: no policy specified for bob@EXAMPLE.COM; defaulting to no policy Enter password for principal "bob@EXAMPLE.COM": BOB_SECRET Re-enter password for principal "bob@EXAMPLE.COM": BOB_SECRET Principal "bob@EXAMPLE.COM" created. kadmin.local: q
By default, principals will be created in the container defined with ldap_kerberos_container_dn in /etc/krb5.conf above. If you want to add a principal somewhere else in the DIT (including to an existing entry), use the -x option to addprinc:
# kadmin.local Authenticating as principal root/admin@EXAMPLE.COM with password. kadmin.local: addprinc -x uid=alice,ou=People,dc=example,dc=com alice WARNING: no policy specified for alice@EXAMPLE.COM; defaulting to no policy Enter password for principal "alice@EXAMPLE.COM": ALICE_SECRET Re-enter password for principal "alice@EXAMPLE.COM": ALICE_SECRET Principal "alice@EXAMPLE.COM" created. kadmin.local: q
If you want to be able to use Kerberos to secure LDAP queries from clients, you need to create an appropriate principal (ldap/server.example.com) on the server and export it to a keytab (e.g. /etc/krb5.ldap.keytab):
# kadmin.local Authenticating as principal root/admin@EXAMPLE.COM with password. kadmin.local: addprinc -randkey ldap/server.example.com WARNING: no policy specified for ldap/server.example.com@EXAMPLE.COM; defaulting to no policy Principal "ldap/server.example.com@EXAMPLE.COM" created. kadmin.local: ktadd -k /etc/krb5.ldap.keytab ldap/server.example.com Entry for principal ldap/server.example.com with kvno 3, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:/etc/krb5.ldap.keytab. Entry for principal ldap/server.example.com with kvno 3, encryption type aes128-cts-hmac-sha1-96 added to keytab WRFILE:/etc/krb5.ldap.keytab. kadmin.local: q
Change the permissions of the keytab so that the openldap user or group can read it, but nobody else:
# chown root:openldap /etc/krb5.ldap.keytab # chmod 0640 /etc/krb5.ldap.keytab
Next, edit /etc/default/slapd to tell slapd where to find the keytab by uncommenting the export KRB5_KTNAME and setting it to the location of the keytab you just created:
export KRB5_KTNAME=/etc/krb5.ldap.keytab
And restart slapd:
# systemctl restart slapd
Then create a regular expression mapping Kerberos principals to LDAP entries, something like:
# ldapmodify -H ldapi:/// -Y EXTERNAL << EOF dn: cn=config changetype: modify replace: olcAuthzRegexp olcAuthzRegexp: {0}"uid=([^/]*)/admin,(cn=example.com,)?cn=gssapi,cn=auth" "cn=admin,dc=example,dc=com" olcAuthzRegexp: {1}"uid=([^/]*),(cn=example.com,)?cn=gssapi,cn=auth" "uid=$1,ou=People,dc=example,dc=com EOF
Now, on the same or a different system (but one which has a suitable /etc/krb5.conf installed), initialize a Kerberos principal and try connecting with it (using the -Y GSSAPI mechanism):
# kinit alice Password for alice@EXAMPLE.COM: # klist Ticket cache: FILE:/tmp/krb5cc_xyz Default principal: alice@EXAMPLE.COM ... # ldapwhoami -Q -Y GSSAPI -H ldapi:/// dn:uid=alice,ou=People,dc=example,dc=com
If you want to setup a secondary KDC, first setup OpenLDAP replication to the second server and then:
install krb5-kdc-ldap (not the admin server)
copy over /etc/krb5.conf, /etc/krb5kdc/service.keyfile and /etc/krb5kdc/stash files from the primary KDC
(optionally) create a kerberos principal and keytab on the secondary KDC and restart slapd
start the secondary KDC (systemctl start krb5-kdc)
DNS/Bind9
OpenLDAP can also be used as a backend to store DNS zones for bind9 (although the remaining configuration is still performed using the customary config files).
First, install bind9-dyndb-ldap (bind9 will be pulled in as a dependency if necessary):
# apt install bind9-dyndb-ldap
Next, the bind schema needs to be installed from /usr/share/doc/bind9-dyndb-ldap/schema.ldif.gz. Sadly, it requires some manual editing since it is formatted for the 389 Directory Server. The lines dn:cn=dns,cn=schema,cn=config and objectClass: olcSchemaConfig need to be added at the top, the existing dn needs to be commented out, attributeTypes should be olcAttributeTypes, objectClasses should be olcObjectClasses and attributes already defined in the cosine schema should be commented out. Something like this:
# zcat /usr/share/doc/bind9-dyndb-ldap/schema.ldif.gz | sed 's/^attributeTypes:/olcAttributeTypes:/; s/^objectClasses:/olcObjectClasses:/; 1,/1.3.6.1.4.1.2428.20.0.0/ {/1.3.6.1.4.1.2428.20.0.0/!s/^/#/}; 1idn: cn=dns,cn=schema,cn=config\nobjectClass: olcSchemaConfig ' >> /tmp/dns.schema
Then load the dns schema:
# ldapadd -Q -Y EXTERNAL -H ldapi:/// -f /tmp/dns.schema adding new entry "cn=dns,cn=schema,cn=config"
Load and enable the syncrepl module (the protocol is used for communication between slapd and bind9, so it needs to be enabled even if you do not plan to do any replicated setup with multiple slapd servers):
# ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF dn: cn=module{0},cn=config changetype: modify add: olcModuleLoad olcModuleLoad: syncprov EOF Modifying entry "cn=module{0},cn=config" # ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF dn: olcOverlay=syncprov,olcDatabase={1}mdb,cn=config changeType: add objectClass: olcOverlayConfig objectClass: olcSyncProvConfig olcOverlay: syncprov olcSpCheckpoint: 100 10 olcSpSessionLog: 100 EOF adding new entry "olcOverlay=syncprov,olcDatabase={1}mdb,cn=config"
Now you are ready to start creating DNS zones. Here's an example (based on /usr/share/doc/bind9-dyndb-ldap/example.ldif):
# ldapadd -x -D cn=admin,dc=example,dc=com -W <<EOF dn: ou=Services,dc=example,dc=com objectClass: organizationalUnit objectClass: top ou: Services # Top dns container dn: ou=dns,ou=Services,dc=example,dc=com objectClass: organizationalUnit objectClass: top ou: dns # Zone example.com dn: idnsName=example.com,ou=dns,ou=Services,dc=example,dc=com objectClass: top objectClass: idnsZone objectClass: idnsRecord idnsName: example.com idnsUpdatePolicy: grant EXAMPLE.COM krb5-self * A; idnsZoneActive: TRUE idnsSOAmName: server.example.com idnsSOArName: root.server.example.com idnsSOAserial: 1 idnsSOArefresh: 10800 idnsSOAretry: 900 idnsSOAexpire: 604800 idnsSOAminimum: 86400 NSRecord: example.com. ARecord: 192.168.1.1 # DNS records for zone example.com dn: idnsName=server,idnsName=example.com,ou=dns,ou=Services,dc=example,dc=com objectClass: idnsRecord objectClass: top idnsName: server CNAMERecord: example.com. dn: idnsName=foo,idnsName=example.com,ou=dns,ou=Services,dc=example,dc=com objectClass: idnsRecord objectClass: top idnsName: foo ARecord: 192.168.1.50 ARecord: 192.168.1.51 ARecord: 192.168.1.52 dn: idnsName=bar,idnsName=example.com,ou=dns,ou=Services,dc=example,dc=com objectClass: idnsRecord objectClass: top idnsName: bar ARecord: 192.168.1.100 dn: idnsName=baz,idnsName=example.com,ou=dns,ou=Services,dc=example,dc=com objectClass: idnsRecord objectClass: top idnsName: baz CNAMERecord: bar dn: idnsName=_ldap._tcp,idnsName=example.com,ou=dns,ou=Services,dc=example,dc=com objectClass: idnsRecord objectClass: top idnsName: _ldap._tcp SRVRecord: 0 100 389 server dn: idnsName=_ntp._udp,idnsName=example.com,ou=dns,ou=Services,dc=example,dc=com objectClass: idnsRecord objectClass: top idnsName: _ntp._udp SRVRecord: 0 100 123 server EOF adding new entry "ou=Services,dc=example,dc=com" adding new entry "ou=dns,ou=Services,dc=example,dc=com" adding new entry "idnsName=example.com,ou=dns,ou=Services,dc=example,dc=com" adding new entry "idnsName=server,idnsName=example.com,ou=dns,ou=Services,dc=example,dc=com" adding new entry "idnsName=foo,idnsName=example.com,ou=dns,ou=Services,dc=example,dc=com" adding new entry "idnsName=bar,idnsName=example.com,ou=dns,ou=Services,dc=example,dc=com" adding new entry "idnsName=baz,idnsName=example.com,ou=dns,ou=Services,dc=example,dc=com" adding new entry "idnsName=_ldap._tcp,idnsName=example.com,ou=dns,ou=Services,dc=example,dc=com" adding new entry "idnsName=_ntp._udp,idnsName=example.com,ou=dns,ou=Services,dc=example,dc=com"
Finally, configure bind9 to use this zone by editing /etc/bind/named.conf.local and adding a section like this:
dyndb "my_db_name" "/usr/lib/bind/ldap.so" { uri "ldapi:///"; base "ou=dns,ou=Services,dc=example,dc=com"; auth_method "simple"; bind_dn "uid=admin,dc=example,dc=com"; password "SECRET"; server_id "server"; };
Start bind9:
# systemctl start bind9
And run a quick test:
# apt install dnsutils [...] # dig example.com. @localhost +short 192.168.1.1
DHCP
The ISC DHCP server has support for using a LDAP server as a backend, provided that you install the isc-dhcp-server-ldap package:
# apt install isc-dhcp-server-ldap schema2ldif
Then, convert and load the dhcp schema:
# zcat /usr/share/doc/isc-dhcp-server-ldap/dhcp.schema.gz > /tmp/dhcp.schema && schema2ldif /tmp/dhcp.schema | ldapadd -Q -Y EXTERNAL -H ldapi:/// adding new entry "cn=dhcp,cn=schema,cn=config"
Add some indexes:
# ldapmodify -Y EXTERNAL -H ldapi:/// <<EOF dn: olcDatabase={1}mdb,cn=config changetype: modify add: olcDbIndex olcDbIndex: dhcpHWAddress eq - add: olcDbIndex olcDbIndex: dhcpClassData eq EOF
And add a LDAP subtree to hold the dhcp configuration (you need to omit the ou=Services,dc=example,dc=com entry if it is already present):
# ldapadd -x -D cn=admin,dc=example,dc=com -W <<EOF dn: ou=Services,dc=example,dc=com objectClass: organizationalUnit objectClass: top ou: Services dn: ou=dhcp,ou=Services,dc=example,dc=com objectClass: organizationalUnit objectClass: top ou: dhcp EOF Enter LDAP Password: SECRET adding new entry "ou=Services,dc=example,dc=com" adding new entry "ou=dhcp,ou=Services,dc=example,dc=com"
Next, add top-level configuration and server entries (assuming the FQDN of the system is server.example.com, note that dhcpServiceDN and dhcpPrimaryDN need to point to the other entry):
# ldapadd -x -D cn=admin,dc=example,dc=com -W <<EOF dn: cn=server.example.com,ou=dhcp,ou=Services,dc=example,dc=com objectClass: top objectClass: dhcpServer cn: server.example.com dhcpServiceDN: cn=config,ou=dhcp,ou=Services,dc=example,dc=com dn: cn=config,ou=dhcp,ou=Services,dc=example,dc=com cn: config objectClass: top objectClass: dhcpService dhcpPrimaryDN: cn=server.example.com,ou=dhcp,ou=Services,dc=example,dc=com dhcpStatements: ddns-update-style none dhcpStatements: default-lease-time 600 dhcpStatements: max-lease-time 7200 EOF Enter LDAP Password: SECRET adding new entry "cn=server.example.com,ou=dhcp,ou=Services,dc=example,dc=com" adding new entry "cn=config,ou=dhcp,ou=Services,dc=example,dc=com"
Now you can create one or more subnets (for a more complex example, see zless /usr/share/doc/isc-dhcp-server-ldap/README.ldap.gz):
# ldapadd -x -D cn=admin,dc=example,dc=com -W <<EOF # First, a shared network segment (which can hold multiple subnet declarations) dn: cn=internal,cn=config,ou=dhcp,ou=Services,dc=example,dc=com cn: internal objectClass: top objectClass: dhcpSharedNetwork # Second, a subnet declaration dn: cn=192.168.1.0,cn=internal,cn=config,ou=dhcp,ou=Services,dc=example,dc=com cn: 192.168.1.0 objectClass: top objectClass: dhcpSubnet objectClass: dhcpOptions dhcpOption: domain-name-servers 192.168.1.1 dhcpOption: routers 192.168.1.1 dhcpOption: subnet-mask 255.255.255.0 dhcpOption: broadcast-address 192.168.1.255 dhcpNetMask: 24 # Third, a pool for the subnet dn: cn=pool,cn=192.168.1.0,cn=internal,cn=config,ou=dhcp,ou=Services,dc=example,dc=com cn: pool objectClass: top objectClass: dhcpPool dhcpRange: 192.168.1.150 192.168.1.199 EOF Enter LDAP Password: SECRET adding new entry "cn=internal,cn=config,ou=dhcp,ou=Services,dc=example,dc=com" adding new entry "cn=192.168.1.0,cn=internal,cn=config,ou=dhcp,ou=Services,dc=example,dc=com" adding new entry "cn=pool,cn=192.168.1.0,cn=internal,cn=config,ou=dhcp,ou=Services,dc=example,dc=com"
Finally, instruct the dhcp server to use LDAP for the configuration by editing /etc/dhcp/dhcpd.conf to read:
ldap-server "localhost"; ldap-port 389; ldap-base-dn "ou=dhcp,ou=Services,dc=example,dc=com"; ldap-dhcp-server-cn "server.example.com"; ldap-method dynamic; ldap-debug-file "/var/log/dhcp-ldap-debug.log"; # The DHCP server needs read-only access, so an anonymous bind # to the LDAP server is sufficient. If you want a non-anonymous # bind (e.g. because of tight ACLs, use something like this) #ldap-username "cn=admin,dc=example,dc=com"; #ldap-password "SECRET";
Note that the dhcp server startup scripts in Debian by default expect IPv4 and IPv6 to be configured, so either add a DHPCv6 configuration in your LDAP database and configure /etc/dhcp/dhcpd6.conf to use it (the preferred solution), or disable IPv6 by editing /etc/default/isc-dhcp-server and listing the interfaces which the dhcp server should be listening on in the INTERFACESv4 option while leaving INTERFACESv6 empty:
INTERFACESv4="eth0" INTERFACESv6=""
Now start the server:
# systemctl start isc-dhcp-server
The configuration which isc-dhcp-server obtained via LDAP will be output to /var/log/dhcp-ldap-debug.log:
# cat /var/log/dhcp-ldap-debug.log ddns-update-style none; default-lease-time 600; max-lease-time 7200; shared-network "internal" { subnet 192.168.1.0 netmask 255.255.255.0 { option domain-name-servers 192.168.1.1; option routers 192.168.1.1; option subnet-mask 255.255.255.0; option broadcast-address 192.168.1.255; pool { range 192.168.1.150 192.168.1.199; } } }
Once you're happy with your setup, you can comment out ldap-debug-file in /etc/dhcp/dhcpd.conf and restart isc-dhcp-server.
Backup
To backup your LDAP configuration and databases, you use the slapcat(8) command which outputs whole DITs in LDIF format and which can be executed while slapd is running:
# slapcat -n0 -l backup_config.ldif
The above command creates a backup of database 0 (which is the cn=config database) and writes it to backup_config.ldif. After the configuration has been backed up, you need to repeat the command for each of the data directories (in the default installation, you have one data directory, corresponding to e.g. dc=example,dc=com) by using the corresponding database number:
# slapcat -n1 -l backup_data.ldif
For a belt-and-braces approach, you might want to put each database into read-only mode before backing it up, e.g. by running:
# ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF dn: olcDatabase={1}mdb,cn=config changeType: modify replace: olcReadOnly olcReadOnly: TRUE EOF modifying entry "olcDatabase={1}mdb,cn=config"
After the backup is complete, you can disable the read-only mode as follows:
# ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF dn: olcDatabase={1}mdb,cn=config changeType: modify replace: olcReadOnly olcReadOnly: FALSE EOF modifying entry "olcDatabase={1}mdb,cn=config"
Note: do not put the configuration database (olcDatabase={0}config,cn=config) in read-only mode, since disabling read-only mode requires writing to the configuration database, you'll end up in a catch-22.
An example of a backup script which automates all of the above can be found here (courtesy of the DebOps project).
Restoration
To restore from a backup, first stop slapd:
# systemctl stop slapd
Then move any configuration directory out of the way:
# mv -i /etc/ldap/slapd.d /etc/ldap/slapd.d.old
Create new directories:
# mkdir /etc/ldap/slapd.d
Next, use slapadd(8) to restore the configuration directory (the parameters are the same as for slapcat, with the addition of -F which tells slapadd where the configuration should live):
# slapadd -n0 -l backup_config.ldif -F /etc/ldap/slapd.d
slapadd is blissfully unaware of file user/group ownership, so you need to correct them manually:
# chown -R openldap:openldap /etc/ldap/slapd.d
Finally, repeat the above steps for each data directory:
# mv -i /var/lib/ldap /var/lib/ldap.old # mkdir /var/lib/ldap # slapadd -n1 -l backup_data.ldif -F /etc/ldap/slapd.d # chown -R openldap:openldap /var/lib/ldap
And start slapd again:
# systemctl start slapd
Note that if you are using any kind of replication, you need to add the -w flag to each slapadd invocation, e.g.:
# slapadd -n1 -l backup_data.ldif -F /etc/ldap/slapd.d -w
This adds additional information to the directory which allows other servers to determine that synchronization is necessary.
Replication
OpenLDAP supports several different types of replication (see the Administrator's Guide for a detailed explanation). This section will focus on one approach, called Multi-Provider.
In Multi-Provider mode, each server acts as a master/producer, meaning that any server can accept changes to the LDAP database and will propagate it to the other servers.
This means that any server can accept changes, even if one or more of the other servers are offline. However, it also means that there will be more traffic between the servers and that there is a risk of split-brain if changes are performed on different servers during a network split.
The create a Multi-Provider cluster, first install slapd (see initial installation above) on each server and edit /etc/default/slapd to list each server's own FQDN as part of the ldap:// URI. In other words, on e.g. serverA.example.com, the entry:
SLAPD_SERVICES="ldapi:// ldap://"
should read:
SLAPD_SERVICES="ldapi:// ldap://serverA.example.com
Next, configure TLS/SSL on each server.
Once TLS is up and running, restart slapd on each server in order for the changes to /etc/default/slapd and the TLS/SSL configuration to take effect:
# systemctl restart slapd
Make sure the syncprov module is loaded and enabled for the cn=config database on each server:
# ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF dn: cn=module{0},cn=config changetype: modify add: olcModuleLoad olcModuleLoad: syncprov dn: olcOverlay=syncprov,olcDatabase={0}config,cn=config changetype: add objectClass: olcOverlayConfig objectClass: olcSyncProvConfig olcOverlay: syncprov olcSpCheckpoint: 100 10 olcSpSessionLog: 100 EOF modifying entry "cn=module{0},cn=config" adding new entry "olcOverlay=syncprov,olcDatabase={0}config,cn=config"
Assign an ID to each server:
serverA# ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF dn: cn=config changetype: modify add: olcServerID olcServerID: 1 EOF modifying entry "cn=config" serverB# ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF dn: cn=config changetype: modify add: olcServerID olcServerID: 2 EOF modifying entry "cn=config" [...repeat for each server...]
Make sure that there is a user with read/write access to the cn=config database on each server (note: alternatively, this can be accomplished using ACLs and a separate replication user):
# slappasswd New password: SECRET Re-enter new password: SECRET {SSHA}4D/nsBlxhRDzqBb028tynzJzbO+iNpnA # ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF dn: olcDatabase={0}config,cn=config changetype: modify replace: olcRootDN olcRootDN: cn=admin,cn=config - replace: olcRootPW olcRootPW: {SSHA}4D/nsBlxhRDzqBb028tynzJzbO+iNpnA EOF modifying entry "olcDatabase={0}config,cn=config"
Note: run slappasswd on each server to generate unique hashes even if you use the same password for all servers.
Finally, configure each server with knowledge about the other servers and enable syncing:
# ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF dn: cn=config changetype: modify replace: olcServerID olcServerID: 1 ldap://serverA.example.com/ olcServerID: 2 ldap://serverB.example.com/ [...repeat for any further servers...] dn: olcDatabase={0}config,cn=config changetype: modify add: olcSyncRepl olcSyncRepl: rid=001 provider=ldap://serverA.example.com/ bindmethod=simple binddn="cn=admin,cn=config" credentials=SECRET searchbase="cn=config" type=refreshAndPersist retry="5 5 300 5" timeout=1 starttls=critical tls_reqcert=demand olcSyncRepl: rid=002 provider=ldap://serverB.example.com/ bindmethod=simple binddn="cn=admin,cn=config" credentials=SECRET searchbase="cn=config" type=refreshAndPersist retry="5 5 300 5" timeout=1 starttls=critical tls_reqcert=demand [...repeat for any further servers...] - add: olcMirrorMode olcMirrorMode: TRUE EOF modifying entry "cn=config" modifying entry "olcDatabase={0}config,cn=config"
Note: olcSyncRepl and olcMirrorMode need to be set in the same transaction, so do not split the above modifications into several commands.
Test the replication of the cn=config database:
serverA# ldapsearch -LLLQ -Y EXTERNAL -H ldapi:/// -b olcDatabase={-1}frontend,cn=config olcSizeLimit dn: olcDatabase={-1}frontend,cn=config olcSizeLimit: 500 serverB# ldapsearch -LLLQ -Y EXTERNAL -H ldapi:/// -b olcDatabase={-1}frontend,cn=config olcSizeLimit dn: olcDatabase={-1}frontend,cn=config olcSizeLimit: 500 serverA# ldapmodify -Y EXTERNAL -H ldapi:/// <<EOF dn: olcDatabase={-1}frontend,cn=config changetype: modify replace: olcSizeLimit olcSizeLimit: 501 EOF modifying entry "olcDatabase={-1}frontend,cn=config" serverA# ldapsearch -LLLQ -Y EXTERNAL -H ldapi:/// -b olcDatabase={-1}frontend,cn=config olcSizeLimit dn: olcDatabase={-1}frontend,cn=config olcSizeLimit: 501 serverB# ldapsearch -LLLQ -Y EXTERNAL -H ldapi:/// -b olcDatabase={-1}frontend,cn=config olcSizeLimit dn: olcDatabase={-1}frontend,cn=config olcSizeLimit: 501 serverA# # ldapmodify -Y EXTERNAL -H ldapi:/// <<EOF dn: olcDatabase={-1}frontend,cn=config changetype: modify replace: olcSizeLimit olcSizeLimit: 500 modifying entry "olcDatabase={-1}frontend,cn=config" EOF
As can be seen from the above example, the change to olcSizeLimit on serverA was automatically propagated to serverB.
It is now time to configure the replication of the other databases (e.g. dc=example,dc=com). Since the cn=config database is now replicated across servers, the remaining steps only have to be performed on one of the servers.
First, setup indexing for two attributes which are heavily used in the replication:
# ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF dn: olcDatabase={1}mdb,cn=config changetype: modify add: olcDbIndex olcDbIndex: entryCSN eq olcDbIndex: entryUUID eq EOF modifying entry "olcDatabase={1}mdb,cn=config"
Second, add the syncprov overlay to the database:
# ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF dn: olcOverlay=syncprov,olcDatabase={1}mdb,cn=config changetype: add objectClass: olcOverlayConfig objectClass: olcSyncProvConfig olcOverlay: syncprov EOF adding new entry "olcOverlay=syncprov,olcDatabase={1}mdb,cn=config"
Third, enable replication:
# ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF dn: olcDatabase={1}mdb,cn=config changetype: modify add: olcSyncRepl olcSyncRepl: rid=011 provider=ldap://serverA.example.com/ bindmethod=simple binddn="cn=admin,dc=example,dc=com" credentials=SECRET searchbase="dc=example,dc=com" type=refreshAndPersist retry="5 5 300 5" timeout=1 starttls=critical tls_reqcert=demand olcSyncRepl: rid=012 provider=ldap://serverB.example.com/ bindmethod=simple binddn="cn=admin,dc=example,dc=com" credentials=SECRET searchbase="dc=example,dc=com" type=refreshAndPersist retry="5 5 300 5" timeout=1 starttls=critical tls_reqcert=demand [...repeat for any further servers...] - add: olcMirrorMode olcMirrorMode: TRUE EOF modifying entry "olcDatabase={1}mdb,cn=config"
Note the changes to the dn, rid, binddn and searchbase compared to when replication was enabled for the cn=config database.
The changes to the configuration will be replicated to the other servers which will then start replicating the dc=example,dc=com database.
The above three steps need to be repeated for each additional database that you have configured (a default installation has no further databases).
Further Reading
/usr/share/doc/slapd/README.Debian.gz (Debian-specific setup and configuration)
man pages: slapd-config.5, slapcat.1, ldapsearch.1, ldapmodify.1, and ldif.1, slapd.1, slapd.8, slapd.access.5, slapd.backends.5, slapd.overlays.5.
The DebOps project's Ansible role for OpenLDAP
RFC 4510 - Lightweight Directory Access Protocol (LDAP)
Pkg-openldap-devel Debian mailing list
CategorySystemAdministration | CategorySoftware | ToDo: merge information from LDAP/Kerberos