52038
Comment: pam.conf
|
62585
|
Deletions are marked like this. | Additions are marked like this. |
Line 1: | Line 1: |
#acl Known:read,write,delete,revert All:read | |
Line 4: | Line 5: |
The point of this document is to explain to sysadmins how to set up LDAP as a distributed naming and authentication service for a small network. There exist plenty of guides that purport to do this, but they're all just cargo-cult "copy this and run this command" without any explanation of what's actually going on or how to fix it when it breaks. [http://techpubs.spinlocksolutions.com/dklar/ldap.html Debian GNU: Setting up OpenLDAP] is somewhat of an exception to the rule, so if you're really short on time check it out. This guide includes parts of it but also covers areas it doesn't. Some analogies to SQL will be made, as that's the dominant database metaphor at the moment. | The point of this document is to explain to sysadmins how to set up LDAP as a distributed naming and authentication service for a small network. There exist plenty of guides that purport to do this, but they're all just cargo-cult "copy this and run this command" without any explanation of what's actually going on or how to fix it when it breaks. [[http://techpubs.spinlocksolutions.com/dklar/ldap.html|Debian GNU: Setting up OpenLDAP]] is somewhat of an exception to the rule, so if you're really short on time check it out. This guide includes parts of it but also covers areas it doesn't. Some analogies to SQL will be made, as that's the dominant database metaphor at the moment. |
Line 8: | Line 9: |
This guide will focus on using the OpenLDAP server, as it's the premiere open source LDAP server and is widely packaged. Other LDAP servers can be used and much of the information will be applicable to them, but performance and OpenLDAP-specific overlays will not. You can use Debian lenny or Ubuntu 8.04 on the server, the instructions should work for both. If you want to use some other distribution or OS, find another guide or work out how to adapt what I say. Notably, Ubuntu 8.10 defaults to the slapd.d config format, which is theoretically better due to the configuration being editable over LDAP, however in practice is worse for the beginner as there are currently no high-level tools that use that. Also running OpenLDAP under Xen isn't recommended due to a [http://www.openldap.org/lists/openldap-software/200603/msg00214.html lack of support for an assembly mutex], although [http://www.openldap.org/lists/openldap-technical/200804/msg00057.html this might be fixed now]. On the client side, configuration for Linux, Solaris, OS X, Tru64 and Windows (using Samba) will be discussed. [[TableOfContents]] |
This guide will focus on using the OpenLDAP server, as it's the premiere open source LDAP server and is widely packaged. Other LDAP servers can be used and much of the information will be applicable to them, but performance and OpenLDAP-specific overlays will not. You can use Debian lenny or Ubuntu 8.04 on the server, the instructions should work for both. If you want to use some other distribution or OS, find another guide or work out how to adapt what I say. Notably, Ubuntu 8.10 defaults to the slapd.d config format, which is theoretically better due to the configuration being editable over LDAP, however in practice is worse for the beginner as there are currently no high-level tools that use that. Also running OpenLDAP under Xen isn't recommended due to a [[http://www.openldap.org/lists/openldap-software/200603/msg00214.html|lack of support for an assembly mutex]], although [[http://www.openldap.org/lists/openldap-technical/200804/msg00057.html|this might be fixed now]]. On the client side, configuration for Linux, Solaris, OS X, Tru64 and Windows (using Samba) will be discussed. <<TableOfContents>> |
Line 47: | Line 48: |
LDAP can be used as an authentication service in several ways. The easiest, and the one used here, is to perform a 'simple bind' operation where the password provided by the user is used to authenticate against the LDAP server. Other methods include SASL and client certificates. Kerberos binds can also be used, but are not much use as an authentication service since it requires an existing Kerberos authentication service. SASL offers the ability to use a variety of methods that ensure the password isn't passed in plaintext over the network, however most of thses require that the password is stored in plaintext on the server. In my opinion, having everyone's password in plaintext is a much bigger risk (link to reddit) than sending it over the wire, particularly since SSL/TLS provides wire encryption these days. SASL/SRP doesn't suffer from the plaintext problem, but it's not implemented widely (or arguably, at all) and so is not an option. SASL/EXTERNAL uses client certificates, which if you're happy to deploy and maintain you have enough expertise to not require this guide. | LDAP can be used as an authentication service in several ways. The easiest, and the one used here, is to perform a 'simple bind' operation where the password provided by the user is used to authenticate against the LDAP server. Other methods include SASL and client certificates. Kerberos binds can also be used, but are not much use as an authentication service since it requires an existing Kerberos authentication service. SASL offers the ability to use a variety of methods that ensure the password isn't passed in plaintext over the network, however most of these require that the password is stored in plaintext on the server. In my opinion, having everyone's password in plaintext is a much bigger risk (link to reddit) than sending it over the wire, particularly since SSL/TLS provides wire encryption these days. SASL/SRP doesn't suffer from the plaintext problem, but it's not implemented widely (or arguably, at all) and so is not an option. SASL/EXTERNAL uses client certificates, which if you're happy to deploy and maintain you have enough expertise to not require this guide. |
Line 55: | Line 56: |
unfriendly to newbies. The [http://www.openldap.org/doc/admin24/ admin guide for 2.4] is good, but still requires a certain level of background knowledge. So I'll take the traditional method of | unfriendly to newbies. The [[http://www.openldap.org/doc/admin24/|admin guide for 2.4]] is good, but still requires a certain level of background knowledge. So I'll take the traditional method of |
Line 62: | Line 63: |
{{{apt-get install slapd ldap-utils}}} | {{{ apt-get install slapd ldap-utils }}} |
Line 73: | Line 76: |
DNS domain name:: `hostname -d` Organization name?:: `hostname -d` |
DNS domain name:: $(hostname -d) Organization name?:: $(hostname -d) |
Line 81: | Line 84: |
{{{# This is the main slapd configuration file. See slapd.conf(5) for more | {{{ # This is the main slapd configuration file. See slapd.conf(5) for more |
Line 88: | Line 92: |
#allow bind_v2}}} | #allow bind_v2 }}} |
Line 92: | Line 97: |
{{{# Schema and objectClass definitions | {{{ # Schema and objectClass definitions |
Line 96: | Line 102: |
include /etc/ldap/schema/inetorgperson.schema}}} | include /etc/ldap/schema/inetorgperson.schema }}} |
Line 100: | Line 107: |
{{{# Where the pid file is put. The init.d script | {{{ # Where the pid file is put. The init.d script |
Line 108: | Line 116: |
loglevel none}}} | loglevel none }}} |
Line 112: | Line 121: |
{{{# Where the dynamically loaded modules are stored | {{{ # Where the dynamically loaded modules are stored |
Line 114: | Line 124: |
moduleload back_hdb}}} | moduleload back_hdb }}} |
Line 118: | Line 129: |
{{{# The maximum number of entries that is returned for a search operation sizelimit 500}}} |
{{{ # The maximum number of entries that is returned for a search operation sizelimit 500 }}} |
Line 123: | Line 136: |
{{{# The tool-threads parameter sets the actual amount of cpu's that is used | {{{ # The tool-threads parameter sets the actual amount of cpu's that is used |
Line 131: | Line 145: |
backend hdb}}} | backend hdb }}} |
Line 135: | Line 150: |
{{{####################################################################### | {{{ ####################################################################### |
Line 145: | Line 161: |
database hdb}}} | database hdb }}} |
Line 149: | Line 166: |
{{{# The base of your directory in database #1 | {{{ # The base of your directory in database #1 |
Line 157: | Line 175: |
directory "/var/lib/ldap"}}} | directory "/var/lib/ldap" }}} |
Line 163: | Line 182: |
{{{# The dbconfig settings are used to generate a DB_CONFIG file the first | {{{ # The dbconfig settings are used to generate a DB_CONFIG file the first |
Line 181: | Line 201: |
dbconfig set_lk_max_lockers 1500}}} | dbconfig set_lk_max_lockers 1500 }}} |
Line 185: | Line 206: |
{{{# Indexing options for database #1 index objectClass eq}}} |
{{{ # Indexing options for database #1 index objectClass eq }}} |
Line 192: | Line 215: |
{{{# Save the time that the entry gets modified, for database #1 lastmod on}}} |
{{{ # Save the time that the entry gets modified, for database #1 lastmod on }}} |
Line 198: | Line 223: |
{{{# Checkpoint the BerkeleyDB database periodically in case of system | {{{ # Checkpoint the BerkeleyDB database periodically in case of system |
Line 200: | Line 226: |
checkpoint 512 30}}} | checkpoint 512 30 }}} |
Line 204: | Line 231: |
{{{# Where to store the replica logs for database #1 # replogfile /var/lib/ldap/replog}}} |
{{{ # Where to store the replica logs for database #1 # replogfile /var/lib/ldap/replog }}} |
Line 210: | Line 239: |
{{{# The userPassword by default can be changed | {{{ # The userPassword by default can be changed |
Line 242: | Line 272: |
# by dnattr=owner write}}} Access control can form a large part of `slapd.conf` - it has an [http://www.openldap.org/doc/admin24/access-control.html entire chapter] in the administration guide. The rules here restrict |
# by dnattr=owner write }}} Access control can form a large part of `slapd.conf` - it has an [[http://www.openldap.org/doc/admin24/access-control.html|entire chapter]] in the administration guide. The rules here restrict |
Line 254: | Line 285: |
{{{####################################################################### | {{{ ####################################################################### |
Line 261: | Line 293: |
#suffix "dc=debian,dc=org"}}} This is a stub to show how to set up a second database. You can read up on all the options available in the slapd.conf(5) and slapd-bdb(5) man pages. There's also another way of configuring slapd which uses ldif files in a directory called `slapd.d` and allows configuration over LDAP, which is [http://www.openldap.org/doc/admin24/slapdconf2.html covered in the administration guide], but since it's less obvious than a traditional config file I'm not going to cover it here. |
#suffix "dc=debian,dc=org" }}} This is a stub to show how to set up a second database. You can read up on all the options available in the slapd.conf(5) and slapd-bdb(5) man pages. There's also another way of configuring slapd which uses ldif files in a directory called `slapd.d` and allows configuration over LDAP, which is [[http://www.openldap.org/doc/admin24/slapdconf2.html|covered in the administration guide]], but since it's less obvious than a traditional config file I'm not going to cover it here. |
Line 270: | Line 303: |
{{{dn: dc=daa,dc=com,dc=au | {{{ dn: dc=daa,dc=com,dc=au |
Line 296: | Line 330: |
modifyTimestamp: 20080725064340Z}}} This is the LDIF for the two entries the slapd package created when it was installed. The first is the top of the LDAP tree, `dc=daa,dc=com,dc=au`. All other entries in the tree will be added below this entry. A common trick encountered when installing OpenLDAP without using the packages is that this entry must be created before you can add any other entries, otherwise you get the error [http://www.openldap.org/faq/data/cache/157.html ldap_add: No such object]. The second entry is the database administrator. This object doesn't need to exist, you could just put the `rootpw` in `slapd.conf`, however if it's in the database you can [http://www.openldap.org/doc/admin24/access-control.html#Controlling%20rootdn%20access use ACLs] to limit which hosts the ''rootdn'' can authenticate from. |
modifyTimestamp: 20080725064340Z }}} This is the LDIF for the two entries the slapd package created when it was installed. The first is the top of the LDAP tree, `dc=daa,dc=com,dc=au`. All other entries in the tree will be added below this entry. A common trick encountered when installing OpenLDAP without using the packages is that this entry must be created before you can add any other entries, otherwise you get the error [[http://www.openldap.org/faq/data/cache/157.html|ldap_add: No such object]]. The second entry is the database administrator. This object doesn't need to exist, you could just put the `rootpw` in `slapd.conf`, however if it's in the database you can [[http://www.openldap.org/doc/admin24/access-control.html#Controlling%20rootdn%20access|use ACLs]] to limit which hosts the ''rootdn'' can authenticate from. |
Line 302: | Line 337: |
The client-side commands start with `ldap` and use the LDAP protocol to talk to the LDAP server. They use the libldap library, which has defaults configured via `/etc/ldap/ldap.conf`. Add the following lines to it so you don't have to enter them on the command line all the time: {{{BASE dc=example,dc=com | The client-side commands start with `ldap` and use the LDAP protocol to talk to the LDAP server. They use the libldap library, which has defaults configured via `/etc/ldap/ldap.conf`. Add the following lines to it so you don't have to enter them on the command line all the time: {{{ BASE dc=example,dc=com |
Line 306: | Line 342: |
{{{# extended LDIF | {{{ # extended LDIF |
Line 334: | Line 371: |
# numEntries: 2}}} | # numEntries: 2 }}} |
Line 338: | Line 376: |
There are various other OpenLDAP client utilities like `ldapmodify`, `ldapadd` (actually just a link to `ldapmodify`), `ldapdelete`, `ldappasswd` and `ldapwhoami` which are basic wrappers for the libldap library calls. One very useful tool that's not part of OpenLDAP is `ldapvi` (`apt-get install ldapvi`) which performs a search, opens the resulting LDIF in your favorite $EDITOR, then sends your changes (if any) back to the server. There are many graphical LDAP clients about, but my recommendation is [http://directory.apache.org/studio/ Apache Directory Studio]. Yes, it's written in Java and requires Eclipse, but is unreasonably good despite this. Unfortunately the latest release requires Eclipse 3.3, but the latest version in Debian and Ubuntu is 3.2, so you'll have to download the standalone version. |
There are various other OpenLDAP client utilities like `ldapmodify`, `ldapadd` (actually just a link to `ldapmodify`), `ldapdelete`, `ldappasswd` and `ldapwhoami` which are basic wrappers for the libldap library calls. One very useful tool that's not part of OpenLDAP is `ldapvi` (`apt-get install ldapvi`) which performs a search, opens the resulting LDIF in your favorite $EDITOR, then sends your changes (if any) back to the server. Another good one is `shelldap` (not yet in Debian, but [[http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=548271|will be soon]]) which is a shell-like interface for browsing and editing an LDAP tree as if it were a filesystem. There are many graphical LDAP clients about, but my recommendation is [[http://directory.apache.org/studio/|Apache Directory Studio]]. Yes, it's written in Java and requires Eclipse, but is unreasonably good despite this. Unfortunately the latest release requires Eclipse 3.3, but the latest version in Debian and Ubuntu is 3.2, so you'll have to download the standalone version. |
Line 345: | Line 383: |
{{{dn: ou=People,dc=example,dc=com | {{{ dn: ou=People,dc=example,dc=com |
Line 351: | Line 390: |
objectClass: organizationalUnit}}} | objectClass: organizationalUnit }}} |
Line 360: | Line 400: |
index uniqueMember eq}}} then as root run {{{/etc/init.d/slapd stop | index uniqueMember eq }}} then as root run {{{ /etc/init.d/slapd stop |
Line 363: | Line 405: |
/etc/init.d/slapd start}}} to create these indexes. The traditional way to import users is PADL's [http://www.padl.com/OSS/MigrationTools.html MigrationTools] or [https://gna.org/projects/smbldap-tools/ smbldap-tools], which are both available in Debian/Ubuntu - `migrationtools` and `smbldap-tools` respectively. However both are somewhat icky perl and I don't really trust them (if I had to choose I'd use MigrationTools) since they often add system groups, so here's a simple python script to import existing users: |
/etc/init.d/slapd start }}} to create these indexes. The traditional way to import users is PADL's [[http://www.padl.com/OSS/MigrationTools.html|MigrationTools]] or [[https://gna.org/projects/smbldap-tools/|smbldap-tools]], which are both available in Debian/Ubuntu - `migrationtools` and `smbldap-tools` respectively. However both are somewhat icky perl and I don't really trust them (if I had to choose I'd use MigrationTools) since they often add system groups, so here's a simple python script to import existing users: |
Line 391: | Line 434: |
print user | |
Line 447: | Line 489: |
* Although the password scheme is {CRYPT}, this uses the `crypt(3)` library function, which on Linux has support for salted MD5. Future password changes will use {SSHA}, as that's the `slapd` password-hash default - see `slapd.conf(5)` and the [http://www.openldap.org/faq/data/cache/344.html OpenLDAP Faq-O-Matic] for more details. | * Although the password scheme is {CRYPT}, this uses the `crypt(3)` library function, which on Linux has support for salted MD5. Future password changes will use {SSHA}, as that's the `slapd` password-hash default - see `slapd.conf(5)` and the [[http://www.openldap.org/faq/data/cache/344.html|OpenLDAP Faq-O-Matic]] for more details. |
Line 457: | Line 499: |
Name resolution in Linux is performed by glibc, using the NSS (name service switch) facility which is configured using `/etc/nsswitch.conf` and loads `/lib/libnss_*` modules as required. The Linux [http://www.padl.com/OSS/nss_ldap.html nss_ldap] module is written by PADL, and comes in the `libnss-ldap` package in Debian and Ubuntu. Most Linux distributions (Slackware being the notable exception, but I doubt many lazy sysadmins use it) use [http://www.kernel.org/pub/linux/libs/pam/ Linux-PAM] (pluggable authentication modules), as their authentication system. The [http://www.padl.com/OSS/pam_ldap.html pam_ldap] module was also written by PADL, uses a similar file (in some cases the same file) as the LDAP NSS module, and comes in the `libpam-ldap` package. |
Name resolution in Linux is performed by glibc, using the NSS (name service switch) facility which is configured using `/etc/nsswitch.conf` and loads `/lib/libnss_*` modules as required. The Linux [[http://www.padl.com/OSS/nss_ldap.html|nss_ldap]] module is written by PADL, and comes in the `libnss-ldap` package in Debian and Ubuntu. Most Linux distributions (Slackware being the notable exception, but I doubt many lazy sysadmins use it) use [[http://www.kernel.org/pub/linux/libs/pam/|Linux-PAM]] (pluggable authentication modules), as their authentication system. The [[http://www.padl.com/OSS/pam_ldap.html|pam_ldap]] module was also written by PADL, uses a similar file (in some cases the same file) as the LDAP NSS module, and comes in the `libpam-ldap` package. |
Line 462: | Line 504: |
{{{apt-get install libnss-ldap}}} | {{{ apt-get install libnss-ldap }}} |
Line 474: | Line 518: |
Now, while the NSS and PAM LDAP modules are installed, they're not yet being used. To activate them, run {{{auth-client-config -a -p ldap_example}}} under Ubuntu and it should update everything automagically. On Debian you need to update various files manually. Edit `/etc/nsswitch.conf` and replace the passwd and group lines with the following:{{{ | Now, while the NSS and PAM LDAP modules are installed, they're not yet being used. To activate them, run {{{ auth-client-config -a -p ldap_example}}} under Ubuntu and it should update everything automagically. On Debian you need to update various files manually. Edit `/etc/nsswitch.conf` and replace the passwd and group lines with the following:{{{ |
Line 499: | Line 544: |
PAM configuration files are very sensitive to variations in ordering and words - the examples above should work, but if not you should read the [http://www.kernel.org/pub/linux/libs/pam/Linux-PAM-html/sag-configuration-file.html PAM configuration file syntax] to learn the difference between 'requisite', 'required', 'suffficient' and 'optional'. | PAM configuration files are very sensitive to variations in ordering and words - the examples above should work, but if not you should read the [[http://www.kernel.org/pub/linux/libs/pam/Linux-PAM-html/sag-configuration-file.html|PAM configuration file syntax]] to learn the difference between 'requisite', 'required', 'suffficient' and 'optional'. You may have noticed I haven't mentioned how to set up `nscd` - the name service caching daemon. That's because it's the devil and worse than useless for the sort of environment this guide is aimed at. All it will do is cause confusion and pain. If you are performing thousands of name service lookups per second, then `nscd` is something you should look at, but very few servers do anywhere near that amount. |
Line 505: | Line 552: |
Reliability is handled by replication of the database to another machine running slapd. Just about every LDAP client can handle being given more than one LDAP servers to use if the primary is down. The OpenLDAP Administrator's Guide [http://www.openldap.org/doc/admin24/replication.html#Pull%20Based chapter on replication] is pretty good and goes into the background of how it works, so you should read it, but if you don't have time, here's the short version. | Reliability is handled by replication of the database to another machine running slapd. Just about every LDAP client can handle being given more than one LDAP servers to use if the primary is down. The OpenLDAP Administrator's Guide [[http://www.openldap.org/doc/admin24/replication.html#Pull%20Based|chapter on replication]] is pretty good and goes into the background of how it works, so you should read it, but if you don't have time, here's the short version. |
Line 515: | Line 562: |
syncprov-sessionlog 100}}} and run {{{/etc/init.d/slapd stop | syncprov-sessionlog 100}}} and run {{{ /etc/init.d/slapd stop |
Line 548: | Line 596: |
{{{syncrepl rid=19 | {{{ syncrepl rid=19 |
Line 560: | Line 609: |
''rid'' is a unique identifier for replication, change it on each server if you have multiple slaves. ''refreshAndPersist'' means the slave will receive changes as soon as they are made on the server. Most of the other arguments are obvious, ''retry''="10 3 300 +" means if an error occurs (eg the connection is lost), it will retry every 10 seconds the first three times, then every 300 seconds afterwards (the + means forever - see `slapd.conf(5)` for full details). | ''rid'' is a identifier for replication, which must be unique per `slapd`. ''refreshAndPersist'' means the slave will receive changes as soon as they are made on the server. Most of the other arguments are obvious, ''retry''="10 3 300 +" means if an error occurs (eg the connection is lost), it will retry every 10 seconds the first three times, then every 300 seconds afterwards (the + means forever - see `slapd.conf(5)` for full details). |
Line 564: | Line 613: |
The main thing you have to watch out for with a replication setup is keeping the config files in sync. Replication will function fine even if ACLs, overlays and indexes differ, which can lead to poor performance, missing features or unintended data disclosure. For a small setup it's not too hard to do it by hand. Larger sites will probably want to use the include directive (warning: it's [http://www.openldap.org/its/index.cgi/Software%20Bugs?id=5276 broken in <2.3.40 and <2.4.8]) or use syncrepl on cn=config, but that's getting into serious voodoo so I won't cover it here - see the [http://www.openldap.org/doc/admin24/replication.html#N-Way%20Multi-Master N-Way Multi-Master] section of the administrator's guide for an example. | The main thing you have to watch out for with a replication setup is keeping the config files in sync. Replication will function fine even if ACLs, overlays and indexes differ, which can lead to poor performance, missing features or unintended data disclosure. For a small setup it's not too hard to do it by hand. Larger sites will probably want to use the include directive (warning: it's [[http://www.openldap.org/its/index.cgi/Software%20Bugs?id=5276|broken in <2.3.40 and <2.4.8]]) or use syncrepl on cn=config, but that's getting into serious voodoo so I won't cover it here - see the [[http://www.openldap.org/doc/admin24/replication.html#N-Way%20Multi-Master|N-Way Multi-Master]] section of the administrator's guide for an example. What the manual does not cover is single-master, multiple-slave configuration with `cn=config` replication, instead referring you to the source code for the test suite, of all things. Here is how to go about it using the existing sync agent profile. To edit cn=config (/!\ should be covered in a new section), use `ldapvi --host ldapi:/// -Y EXTERNAL -D cn=config -Y EXTERNAL -b cn=config` (or slapadd instead of ldapvi or whatever; shelldap does not support SASL). Edit the master config to include the following stanzas: In `cn=config`, add {{{ olcServerID: 001 ldap://master.example.com olcServerID: 002 ldap://slave.example.com }}} (you can use whatever numbers you like as long as they are less than 0xFFF; we use the last octet of the IP address of the host.) Then add `olcOverlay=syncprov,olcDatabase={0}config,cn=config` with {{{ objectClass: olcOverlayConfig objectClass: olcSyncProvConfig olcOverlay: syncprov }}} and add an ACL stanza to allow it access, in `olcDatabase={0}config,cn=config`: {{{ olcAccess: {1}to * by dn.base="cn=syncagent,ou=profile,dc=ucc,dc=gu,dc=uwa,dc=edu,dc=au" read by * +0 break }}} Now, on your newly-installed slave, in `olcDatabase={0}config,cn=config`, add {{{ olcSyncrepl: {0}rid=7 provider=ldap://master.example.com type=refreshAndPersist bindmethod=sasl authcid=syncagent saslmech=DIGEST-MD5 credentials=PASSWORD retry="10 3 300 +" searchbase="cn=config" }}} This sets up replication of all the config. If you make a change to the schema, for example, you will see that reflected on the slave. Back on the server, initialise replication of the database: In olcDatabase={1}hdb,cn=config, add {{{ olcAccess: {0}to * by dn.base="cn=syncagent,ou=profile,dc=ucc,dc=gu,dc=uwa,dc=edu,dc=au" read by * +0 break olcSyncrepl: {0}rid=18 provider=ldap://mussel.ucc.gu.uwa.edu.au bindmethod=sasl credentials="PASSWORD" saslmech=DIGEST-MD5 authcID="syncagent" searchbase="dc=ucc,dc=gu,dc=uwa,dc=edu,dc=au" type=refreshAndPersist retry="10 3 300 +" }}} The `rid` in the olcSyncrepl line MUST match the rid for the master server; otherwise the master will try to get updates from somewhere else, and you don't want that. |
Line 570: | Line 661: |
There's much more to SSL than that - it's a topic deserving of an entire HOWTO by itself. Unfortunately most suffer from cargo-cult syndrome; [http://www.zytrax.com/tech/survival/ssl.html Survival Guide - SSL/TLS and X.509 Certificates] is pretty good, apart from its use of CA.pl which is still a bit manual for my liking. Fortunately OpenVPN includes a set of scripts called [http://openvpn.net/index.php/documentation/howto.html#pki easy-rsa] that lives up to its name. By default it creates certificates valid for 10 years, by which time updating the PKI should be SEP. | There's much more to SSL than that - it's a topic deserving of an entire HOWTO by itself. Unfortunately most suffer from cargo-cult syndrome; [[http://www.zytrax.com/tech/survival/ssl.html|Survival Guide - SSL/TLS and X.509 Certificates]] is pretty good, apart from its use of CA.pl which is still a bit manual for my liking. Fortunately OpenVPN includes a set of scripts called [[http://openvpn.net/index.php/documentation/howto.html#pki|easy-rsa]] that lives up to its name. By default it creates certificates valid for 10 years, by which time updating the PKI should be SEP. |
Line 574: | Line 665: |
{{{apt-get install openvpn | {{{ apt-get install openvpn |
Line 579: | Line 671: |
{{{. vars | {{{ . vars |
Line 591: | Line 684: |
{{{./build-key-server ldap}}} | {{{ ./build-key-server ldap}}} |
Line 597: | Line 691: |
{{{cp keys/{ca.crt,ldap.key,ldap.crt} /etc/ldap | {{{ cp keys/{ca.crt,ldap.key,ldap.crt} /etc/ldap |
Line 603: | Line 698: |
{{{# SSL support | {{{ # SSL support |
Line 610: | Line 706: |
{{{TLS_CACERT /etc/ldap/ca.crt}}} | {{{ TLS_CACERT /etc/ldap/ca.crt}}} |
Line 614: | Line 711: |
{{{SLAPD_SERVICES="ldap://127.0.0.1:389/ ldaps:/// ldapi:///"}}} | {{{ SLAPD_SERVICES="ldap://127.0.0.1:389/ ldaps:/// ldapi:///"}}} |
Line 620: | Line 718: |
{{{ldapsearch -x -H ldaps://quoll.daa.com.au/}}} | {{{ ldapsearch -x -H ldaps://quoll.daa.com.au/}}} |
Line 623: | Line 722: |
{{{ssl on | {{{ ssl on |
Line 638: | Line 738: |
The supplied `idsconfig` tool is only really for Sun's (originally Netscape's) LDAP server, and while there are patches around to make it work with OpenLDAP, they're outdated and not actually needed. What need to do is download the solaris specific schemas, attachment:DUAConfigProfile.schema attachment:solaris.schema and put them in /etc/ldap/schema | The supplied `idsconfig` tool is only really for Sun's (originally Netscape's) LDAP server, and while there are patches around to make it work with OpenLDAP, they're outdated and not actually needed. What need to do is download the solaris specific schemas, [[attachment:DUAConfigProfile.schema]] [[attachment:solaris.schema]] and put them in `/etc/ldap/schema`. Next, add the profiles and proxy account. Full details to be added, but for the moment you could do worse than use the appropriate ldif files at http://developers.sun.com/identity/reference/techart/opends-namesvcs.html#5 |
Line 659: | Line 761: |
Next, run `ldapclient init -v -a profileName=default -a defaultServerList=ldap.daa.com.au -a domainName=daa.com.au -a proxyDN=cn=proxyagent,ou=profile,dc=daa,dc=com,dc=au` which will ask for the bind password, then configure the system to use LDAP for NSS (including copying `/etc/nsswitch.ldap` to `/etc/nsswitch.conf`). The final step is to configure PAM, so edit `/etc/pam.conf` - either apply attachment:pam.conf.diff or make the following changes manually: | Next, run `ldapclient init -v -a profileName=default -a defaultServerList=ldap.daa.com.au -a domainName=daa.com.au -a proxyDN=cn=proxyagent,ou=profile,dc=daa,dc=com,dc=au` which will ask for the bind password, then configure the system to use LDAP for NSS (including copying `/etc/nsswitch.ldap` to `/etc/nsswitch.conf`). The final step is to configure PAM, so edit `/etc/pam.conf` - either apply [[attachment:pam.conf.diff]] or make the following changes manually: |
Line 736: | Line 838: |
[http://h30097.www3.hp.com/docs/base_doc/DOCUMENTATION/V51B_HTML/ARH95ETE/PPLDPXXX.HTM Tru64 LDAP Documentation] [http://forums11.itrc.hp.com/service/forums/questionanswer.do?admit=109447626+1218017020582+28353475&threadId=1084988] |
[[http://h30097.www3.hp.com/docs/base_doc/DOCUMENTATION/V51B_HTML/ARH95ETE/PPLDPXXX.HTM|Tru64 LDAP Documentation]] [[http://forums11.itrc.hp.com/service/forums/questionanswer.do?admit=109447626+1218017020582+28353475&threadId=1084988]] |
Line 747: | Line 849: |
/!\ To do. |
|
Line 751: | Line 855: |
Compiling it is a bit of a pain, if you're using Debian use the [http://bugs.debian.org/cgi-bin/bugreport.cgi?msg=85;filename=smbk5pwd.diff;att=1;bug=443073 patch] from [http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=443073 Debian bug 443073] and rebuild slapd: | Compiling it is a bit of a pain, if you're using Debian use the [[http://bugs.debian.org/cgi-bin/bugreport.cgi?msg=85;filename=smbk5pwd.diff;att=1;bug=443073|patch]] from [[http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=443073|Debian bug 443073]] and rebuild slapd: |
Line 764: | Line 868: |
For Ubuntu, the easiest way is to use the packages from the [http://ppa.launchpad.net/ian-sigma-uk/ppa/ubuntu PPA] mentioned in the [https://bugs.launchpad.net/ubuntu/+source/openldap/+bug/82853/ Ubuntu bug]. | For Ubuntu, the easiest way is to use the packages from the [[http://ppa.launchpad.net/ian-sigma-uk/ppa/ubuntu|PPA]] mentioned in the [[https://bugs.launchpad.net/ubuntu/+source/openldap/+bug/82853/|Ubuntu bug]]. |
Line 778: | Line 882: |
Why bother setting up FreeRADIUS to authenticate from an LDAP server? Because if you have NTPasswords thanks to samba, you can trivially set up the PoPToP PPTP server so Windows users can VPN in using the same password. | Why bother setting up FreeRADIUS to authenticate from an LDAP server? Because if you have NTPasswords thanks to samba, you can set up the PoPToP PPTP server so Windows users can VPN in using the same password, or use an 802.1x authenticator to do WPA{,2}-Enterprise wireless authentication or port-based wired authentication. RADIUS is yet another enormously complex protocol, again deserving of its own HOWTO, but the changes required to a stock FreeRADIUS install for PPTP and 802.11x are thankfully minor. Like OpenLDAP, the [[http://freeradius.org/doc/|official FreeRADIUS documentation]] warns against using HOWTOs that are not maintained by the FreeRADIUS team, so YMMV. The [[http://wiki.freeradius.org/PopTop|official documentation on PPTP]] is a bit vague, unfortunately. The [[http://tldp.org/HOWTO/8021X-HOWTO/|802.1X Port-Based Authentication HOWTO]] is old, but good. RADIUS deals with the three As: authentication, authorization and accounting. Only the first two will be dealt with here. '''Authentication''' means determining who a user really is, and is the most obvious use of LDAP - as a password store. Beware trying to use LDAP as the `Auth-Type` module itself, as this will try and authenticate by binding to the LDAP server. This only works if you have cleartext passwords. Instead, what you want to do is instruct the RADIUS server to use LDAP to retrieve hashes for the real authentication module. RADIUS defines a massive suite of authentication protocols, all of which can be layered on top of each other. For PPTP, you want to use EAP (extensible authentication protocol) with MS-CHAPv2. This means not using MS-CHAPv2 on its own - EAP provides the framework for the authentication conversation, and the actual password exchange protocol is MS-CHAPv2. On the other hand, 802.11x is even more complicated than this - the EAP-MSCHAPv2 combination is itself encapsulated in a TLS secure tunnel, forming PEAPv0/MS-CHAPv2. (Windows Vista and above clients can support PEAP/MSCHAPv2 on the PPTP link, but luckily there seems to be an acceptable degree of autonegotiation of encryption protocol.) '''Authorization''' is checking whether a given user is allowed to connect. The documentation for the RADIUS LDAP module is in the [[http://wiki.freeradius.org/Rlm_ldap|rlm_ldap(5)]] manpage. * Set up the LDAP connection first. In `radius.conf`, find the `ldap` block (part of the modules block), and set the variables as follows: {{{ server = "ldapserver.your.domain" identity = "admin_dn" password = admin_password basedn = "search_base_dn" }}} /!\ do these variables need explaining? * If you're using SSL as described above, you should also find the `tls` block for the `ldap` module, and set the appropriate certificate variables, usually just `cacertfile`. * While you're editing the `ldap` module, change the `access_attr` setting. This controls whether an LDAP object can be used for RADIUS lookups; the simplest way to enable access for all users is to set this to `uid`. There are more complex options - see the documentation if you really need that. * The final change in `radius.conf` is in the `mschap` section, which deals with general options for the MS-CHAP and MS-CHAPv2 modules. Enabling the use of MPPE attributes (the encryption parameters for PPTP connections) is the only change required here: {{{ use_mppe = on }}} * Next, you need to fix the attributes that the LDAP modules uses to get the Samba passwords. Make the following changes to the `ldap.attrmap` file: From {{{ checkItem LM-Password lmPassword checkItem NT-Password ntPassword }}} to {{{ checkItem LM-Password sambaLMPassword checkItem NT-Password sambaNTPassword }}} * Next, edit the `eap.conf` file, which is the behemoth that controls the EAP system. Luckily, you only need a simple change here: change the `default_eap_type` from `md5` to `mschapv2`. * The above changes will allow the default configuration (`sites-enabled/default`) to ''authenticate'' against LDAP. You now need to turn on ''authorization'' using the `access-allowed` settings as described above, by editing `sites-enabled/default` and uncommenting the `ldap` option in the `authorize` module. That's it for PPTP - you should now be able to point your PPTP server at the RADIUS server (doing so is beyond the scope of this document.) For 802.1x and WPA-Enterprise, a few more changes are necessary. * If you are using the Debian packages of FreeRADIUS, you have to rebuild them. PEAP requires FreeRADIUS built against OpenSSL, which contravenes Debian guidelines. A few changes to the package configuration are required, and are well-summarised at [[http://www.linuxinsight.com/building-debian-freeradius-package-with-eap-tls-ttls-peap-support.html|Building Debian FreeRadius package with EAP/TLS/TTLS/PEAP support]]. {{{ cd /usr/src apt-get source freeradius cd freeradius-$version # apply the changes in the page above debuild -us -uc -b dpkg -i {freeradius,freeradius-common,freeradius-ldap,freeradius-utils,libfreeradius2}-$version-$arch.deb }}} * Set up server-side TLS certificates for the encrypted tunnel. You can probably just use the LDAP certificates you've already generated, or create some different ones using the process above. Edit `eap.conf` and find the `tls` block, then change the following variables as appropriate: {{{ private_key_file = ${certdir}/radius.key certificate_file = ${certdir}/radius.crt CA_file = /etc/ssl/CA.crt random_file = /dev/urandom }}} * The default configuration uses a different "virtual server" for the EAP exchange in the TLS tunnel. Edit `sites-enabled/inner-tunnel` and make the same changes as you did to the `default` file - i.e. uncommenting the `ldap` option in the `authorize` module. You should now configure your wireless access point or 802.1x-enabled switch to access the RADIUS server. |
Line 788: | Line 967: |
= Debugging = So, what do you do when things go wrong? For NSS, one of the easiest ways is `strace id username`. Understanding `strace` output can be difficult, but what you're looking for is connect() lines featuring the IP address of the LDAP server. If you don't see them, LDAP isn't being queried at all, so look for a local misconfiguration. For other LDAP clients, turn up their logging if possible or strace a running process then perform the LDAP operation. Again, you're looking for connect() calls to your LDAP server. If the program is successfully connecting to the LDAP server, next is to look at the server logs. They're in `/var/log/debug` by default, or wherever you put them if you edited `/etc/syslog.conf`. You'll need `stats` in the `loglevel` line of `/etc/ldap/slapd.conf`, which will show the LDAP binds and searches. Check to see that the searches are what you expect, and if so, perform them yourself from the command line with `ldapsearch(1)`. Another approach is to use Wireshark or another packet sniffer to examine the operations over the wire, although this won't work for SSL encrypted connections. Finally, if you are running `nscd`, stop it while debugging otherwise you'll be confused by stale results. |
|
Line 790: | Line 977: |
There are several places you can get help if something isn't working. You could try #ldap or #openldap on [http://freenode.net/ Freenode] where I and others lurk. There's the [http://www.openldap.org/lists/ OpenLDAP] mailing lists which I don't read, but the authors of OpenLDAP do. Don't email me privately, I won't answer your question. As for distribution support, Ubuntu is pretty abysmal, Debian's ok. | There are several places you can get help if something isn't working. You could try #ldap or #openldap on [[http://freenode.net/|Freenode]] where I and others lurk. There's the [[http://www.openldap.org/lists/|OpenLDAP]] mailing lists which I don't read, but the authors of OpenLDAP do. Don't email me privately, I won't answer your question. As for distribution support, Ubuntu is pretty abysmal eg [[https://lists.ubuntu.com/archives/ubuntu-server/2009-August/003179.html|making big changes in 9.10]] but [[https://bugs.launchpad.net/ubuntu/+source/openldap/+bug/442498|not updating the documentation]], Debian's ok. |
Line 794: | Line 981: |
* [http://techpubs.spinlocksolutions.com/dklar/ldap.html Debian GNU: Setting up OpenLDAP] * [http://www.zytrax.com/books/ldap/ LDAP for Rocket Scientists] * [http://www.openldap.org/doc/admin24/ OpenLDAP Software 2.4 Administrator's Guide] * [https://wiki.ubuntu.com/AuthClientConfig AuthClientConfig] * [http://docs.sun.com/app/docs/doc/816-4556/ldapsetup-1?l=en&a=view Solaris 10 LDAP Naming Services Setup and Administration] * [http://developers.sun.com/identity/reference/techart/opends-namesvcs.html Setting Up OpenDS 1.0.0 as a Naming Service for the OpenSolaris OS, Part 1 of 2: Basic Steps] |
* [[http://techpubs.spinlocksolutions.com/dklar/ldap.html|Debian GNU: Setting up OpenLDAP]] * [[http://www.zytrax.com/books/ldap/|LDAP for Rocket Scientists]] * [[http://www.openldap.org/doc/admin24/|OpenLDAP Software 2.4 Administrator's Guide]] * [[https://wiki.ubuntu.com/AuthClientConfig|AuthClientConfig]] * [[http://docs.sun.com/app/docs/doc/816-4556/ldapsetup-1?l=en&a=view|Solaris 10 LDAP Naming Services Setup and Administration]] * [[http://developers.sun.com/identity/reference/techart/opends-namesvcs.html|Setting Up OpenDS 1.0.0 as a Naming Service for the OpenSolaris OS, Part 1 of 2: Basic Steps]] |
This is a work in progress!
Introduction
The point of this document is to explain to sysadmins how to set up LDAP as a distributed naming and authentication service for a small network. There exist plenty of guides that purport to do this, but they're all just cargo-cult "copy this and run this command" without any explanation of what's actually going on or how to fix it when it breaks. Debian GNU: Setting up OpenLDAP is somewhat of an exception to the rule, so if you're really short on time check it out. This guide includes parts of it but also covers areas it doesn't. Some analogies to SQL will be made, as that's the dominant database metaphor at the moment.
LDAP can be used for much more than just naming and authentication, but this is by far the most common case and often the base for more advanced setups. (The second most common case is as an address book, which might be dealt with in a later supplement.) If you want a full-on introduction to LDAP, this guide is not it - there are several listed in the references.
This guide will focus on using the OpenLDAP server, as it's the premiere open source LDAP server and is widely packaged. Other LDAP servers can be used and much of the information will be applicable to them, but performance and OpenLDAP-specific overlays will not. You can use Debian lenny or Ubuntu 8.04 on the server, the instructions should work for both. If you want to use some other distribution or OS, find another guide or work out how to adapt what I say. Notably, Ubuntu 8.10 defaults to the slapd.d config format, which is theoretically better due to the configuration being editable over LDAP, however in practice is worse for the beginner as there are currently no high-level tools that use that. Also running OpenLDAP under Xen isn't recommended due to a lack of support for an assembly mutex, although this might be fixed now. On the client side, configuration for Linux, Solaris, OS X, Tru64 and Windows (using Samba) will be discussed.
Contents
LDAP Basics
So, what is LDAP? The acronym expands to "Lightweight Directory Access Protocol", and it was originally intended to provide IP (lightweight) access to X.500 servers, which required the use of the heavy OSI stack. Over time, directory servers that could be directly accessed by LDAP were written, cutting X.500 out of the loop. X.500 was a directory system designed by telcos in the 80s, back when the ISDN was the future of telephony. As such, it has several design decisions that presume a central delegating authority which have been inherited by pure LDAP servers. X.509, the security/certificate specification is one of these, and it lives on as the base of SSL/TLS, the internet PKI.
While LDAP strictly refers to the protocol, it is commonly used to refer to the database accessed via the protocol, which is more correctly called the Directory Information Tree (DIT). The DIT consists of a tree structure of entries, each of which belongs to a set of object classes and has a set of key/value attributes. An entry is the fundamental object of LDAP, and its type is determined by the values of its objectClass attribute. Common values include inetOrgPerson, posixAccount and organization.
Each objectClass is defined in a schema that lists the mandatory and optional attributes, which are themselves specified in schema. [2] For this document the important schema files are core.schema, inetorgperson.schema, cosine.schema <insert more>. An objectClass has one or more SUPerior objectClasses, from which it inherits the list of MUST and MAY attributes, and come in three types - ABSTRACT, STRUCTURAL and AUXILIARY. Every entry must have one structural objectClass, and any number of auxiliary objectClasses. Abstract objectClasses are only used to inherit from, and all objectClasses must derive from the abstract top objectClass. The limitation on an entry having only one structural objectClass can be worked around by creating a new structural objectClass that inherits from all the structural objectClasses required. This is getting into creating schema however and is beyond the scope of this document. While an entry can only have one structural objectClass, the superior objectClasses can be listed, style issue. Attribute inheritence
The tree is composed of entries, which can be both leaves and nodes. The path from an entry to the base of the tree identifies an object and is referred to as its distinguished name (DN), e.g. uid=trs80,ou=people,dc=example,dc=com. The components of the DN are the naming attribute? RDN? of each level of the tree, separated by commas. The naming attribute can be any attribute [3] but there are conventions detailed below, and it must be unique at that level of the tree, although it need not be globally unique. DNs and attribute names are generally case-insensitive, so UID=TRS80,ou=People,dc=Example,dc=COM is the same as the previous example.
The original X.500 specification envisioned a global directory service, divided by geographical regions and then companies, resulting in DNs like o=Widgets Inc.,st=Western Australia,c=AU. This doesn't map well to the internet, so the domain objectClass was defined in RFC ???? (and is included in cosine.schema) which MUST have a domainComponent (dc) attribute [4] that is by convention used as the RDN. So a domain like engineering.example.com is split at the periods to become the DN dc=engineering,dc=example,dc=com.
Administration domains. At this point you might be wondering who runs the dc=com domain and provides referrals. The answer is nobody - instead, PTR records in the DNS are used.
Filters
LDAP filters are the equivalent of the SELECT statement in SQL, but are formed of s-expressions. The full syntax is specified in RFCs ???? and ????, but the basic format is (attribute=value). Boolean operations are written like (&(a=b)(c=d)(e=f)) where & is the symbol for logical and, | is logical or, ! is logical not etc. Substring matching is allowed if the schema specifies it for that attribute...
LDIF
LDAP entries are transmitted over the wire in a binary ASN.1 format called BER, but there's an alternative text representation, the LDAP? Data Interchange Format (LDIF). This is specified in RFC ????, and there are several extensions, but the core of the format is <code>attributeName: value</code>. Here's the LDIF for an example entry:
<code> </code>
Binary attributes are base64 encoded, and the separator is change to be two colons (::) to indicate this. This also applies to ASCII characters outside a safe range.
LDAP as a name service
A name service is one of those infrastructure things that mostly just sits behind the scenes and works. More details.
To use LDAP as a naming service, entries need to be created for the accounts in the DIT. These entries typically have an objectClass of posixAccount as specified in RFC 2307, however this is an auxiliary objectClass so we still need a structural objectClass. For this document we'll use inetOrgPerson, as it contains a useful set of attributes that can be used for other things later on, such as mail, <insert more>.
Authentication
LDAP can be used as an authentication service in several ways. The easiest, and the one used here, is to perform a 'simple bind' operation where the password provided by the user is used to authenticate against the LDAP server. Other methods include SASL and client certificates. Kerberos binds can also be used, but are not much use as an authentication service since it requires an existing Kerberos authentication service. SASL offers the ability to use a variety of methods that ensure the password isn't passed in plaintext over the network, however most of these require that the password is stored in plaintext on the server. In my opinion, having everyone's password in plaintext is a much bigger risk (link to reddit) than sending it over the wire, particularly since SSL/TLS provides wire encryption these days. SASL/SRP doesn't suffer from the plaintext problem, but it's not implemented widely (or arguably, at all) and so is not an option. SASL/EXTERNAL uses client certificates, which if you're happy to deploy and maintain you have enough expertise to not require this guide.
The authentication process takes two steps - first, a search is conducted for the full DN using the provided username in the subtree specified in the configuration, then a bind is performed with the DN and the provided password.
OpenLDAP Setup
OpenLDAP is the best-performing and most powerful LDAP server available. Unfortunately it has historically been somewhat poorly documented and unfriendly to newbies. The admin guide for 2.4 is good, but still requires a certain level of background knowledge. So I'll take the traditional method of providing a slapd.conf, but unlike other guides I'll explain what's going on.
Installation
First, install the OpenLDAP server (commonly referred to as slapd):
apt-get install slapd ldap-utils
Debconf will ask some questions (I recommend you use pwgen to generate a random password):
- Administrator password
- PASSWORD
- Confirm password
- PASSWORD
The following questions that are only asked if you have debconf at low priority or are using Debian, otherwise they're set to the defaults below:
- Omit OpenLDAP server configuration?
- No
- DNS domain name
- $(hostname -d)
- Organization name?
- $(hostname -d)
- Database backend to use
- HDB
- Do you want the database to be removed when slapd is purged?
- No
- Allow LDAPv2 protocol?
- No
The slapd package creates a basic slapd.conf and populates the directory with two entries. First, let's look at /etc/ldap/slapd.conf:
# This is the main slapd configuration file. See slapd.conf(5) for more # info on the configuration options. ####################################################################### # Global Directives: # Features to permit #allow bind_v2
LDAPv2 is deprecated, and not needed unless you have Tru64 clients.
# Schema and objectClass definitions include /etc/ldap/schema/core.schema include /etc/ldap/schema/cosine.schema include /etc/ldap/schema/nis.schema include /etc/ldap/schema/inetorgperson.schema
These are the schema files that cover the most common LDAP use-cases.
# Where the pid file is put. The init.d script # will not stop the server if you change this. pidfile /var/run/slapd/slapd.pid # List of arguments that were passed to the server argsfile /var/run/slapd/slapd.args # Read slapd.conf(5) for possible values loglevel none
Standard configuration items. I'm yet to work out what the best value for the loglevel is, but none config stats seems reasonable. slapd logs using the local4.debug facility, which by default ends up in /var/log/debug. To make it go elsewhere, add the following to /etc/syslog.conf: local4.debug /var/log/slapd.log with tabs, not spaces.
# Where the dynamically loaded modules are stored modulepath /usr/lib/ldap moduleload back_hdb
back_hdb is a backend storage module. It uses Berkeley DB and is largely the same as back_bdb, except it stores entries in a hierarchical fashion (hence hdb) giving greater performance. The modules in /usr/lib/ldap include other backends (starting with back_) that can be used in backend/database statements (see below) and overlay modules (man pages start with slapo-) that can be used in overlay statements (none in this example file, but see replication). Overlay statements in particular are very sensitive to ordering, however I don't know of any documentation that lists a general order - people often resort to trial and error to get it right.
# The maximum number of entries that is returned for a search operation sizelimit 500
If you have a large database you may want to tune this, or consider adding a larger limit for authenticated users.
# The tool-threads parameter sets the actual amount of cpu's that is used # for indexing. tool-threads 1 ####################################################################### # Specific Backend Directives for hdb: # Backend specific directives apply to this backend until another # 'backend' directive occurs backend hdb
All bdb options can be used for hdb as well.
####################################################################### # Specific Backend Directives for 'other': # Backend specific directives apply to this backend until another # 'backend' directive occurs #backend <other> ####################################################################### # Specific Directives for database #1, of type hdb: # Database specific directives apply to this databasse until another # 'database' directive occurs database hdb
Why is there another line saying hdb? slapd can handle multiple independent databases, eg an ISP might have a staff database ou=internal,dc=example,dc=com and several customer databases dc=example,dc=org and dc=example,dc=net served from a single slapd instance. Each database can also have its own set of overlays.
# The base of your directory in database #1 suffix "dc=daa,dc=com,dc=au" # rootdn directive for specifying a superuser on the database. This is needed # for syncrepl. # rootdn "cn=admin,dc=daa,dc=com,dc=au" # Where the database file are physically stored for database #1 directory "/var/lib/ldap"
Each database is identified by its suffix, and needs its own directory to store files in. The rootdn identifies the superuser who can add, delete and modify any entry. You don't have to have one if your ACLs are sufficient (see below).
# The dbconfig settings are used to generate a DB_CONFIG file the first # time slapd starts. They do NOT override existing an existing DB_CONFIG # file. You should therefore change these settings in DB_CONFIG directly # or remove DB_CONFIG and restart slapd for changes to take effect. # For the Debian package we use 2MB as default but be sure to update this # value if you have plenty of RAM dbconfig set_cachesize 0 2097152 0 # Sven Hartge reported that he had to set this value incredibly high # to get slapd running at all. See http://bugs.debian.org/303057 for more # information. # Number of objects that can be locked at the same time. dbconfig set_lk_max_objects 1500 # Number of locks (both requested and granted) dbconfig set_lk_max_locks 1500 # Number of lockers dbconfig set_lk_max_lockers 1500
Tuning Berkeley DB is somewhat of a black art, see below for more details. slapd has several levels of caching, so tends to use a lot of memory.
# Indexing options for database #1 index objectClass eq
Indexes are used for optimising searches, just like in SQL. As the comments note, these statements apply to a specific database, so you can tune them individually.
# Save the time that the entry gets modified, for database #1 lastmod on
This adds four useful operational attributes, modifiersName, modifyTimestamp, creatorsName, and createTimestamp. It's also needed for replication.
# Checkpoint the BerkeleyDB database periodically in case of system # failure and to speed slapd shutdown. checkpoint 512 30
More BDB tuning.
# Where to store the replica logs for database #1 # replogfile /var/lib/ldap/replog
This is cruft left over from the old replication method and can be deleted. The new replication method (syncrepl) is discussed below.
# The userPassword by default can be changed # by the entry owning it if they are authenticated. # Others should not be able to see it, except the # admin entry below # These access lines apply to database #1 only access to attrs=userPassword,shadowLastChange by dn="cn=admin,dc=daa,dc=com,dc=au" write by anonymous auth by self write by * none # Ensure read access to the base for things like # supportedSASLMechanisms. Without this you may # have problems with SASL not knowing what # mechanisms are available and the like. # Note that this is covered by the 'access to *' # ACL below too but if you change that as people # are wont to do you'll still need this if you # want SASL (and possible other things) to work # happily. access to dn.base="" by * read # The admin dn has full write access, everyone else # can read everything. access to * by dn="cn=admin,dc=daa,dc=com,dc=au" write by * read # For Netscape Roaming support, each user gets a roaming # profile for which they have write access to #access to dn=".*,ou=Roaming,o=morsnet" # by dn="cn=admin,dc=daa,dc=com,dc=au" write # by dnattr=owner write
Access control can form a large part of slapd.conf - it has an entire chapter in the administration guide. The rules here restrict access to passwords, so people can authenticate against their own, but can't see other people's. The second and third set up basic ACLs that you'll probably want to customise later on. Note the statements are wrapped over several lines - any line starting with whitespace is considered to be a continuation of the previous line.
ACLs are evaluated in the order specified in the file, with the first match being used.
####################################################################### # Specific Directives for database #2, of type 'other' (can be hdb too): # Database specific directives apply to this databasse until another # 'database' directive occurs #database <other> # The base of your directory for database #2 #suffix "dc=debian,dc=org"
This is a stub to show how to set up a second database. You can read up on all the options available in the slapd.conf(5) and slapd-bdb(5) man pages. There's also another way of configuring slapd which uses ldif files in a directory called slapd.d and allows configuration over LDAP, which is covered in the administration guide, but since it's less obvious than a traditional config file I'm not going to cover it here.
Utilities
OpenLDAP comes with a variety of utilities, both client- and server-side. In general, commands starting with slap are server-side, operate on the database directly and so you have to be root or the openldap user on the same machine as slapd to use them, while commands starting with ldap are client-side, operate using the LDAP protocol and can be run as anyone including over the network, but will require authentication for some tasks.
Let's start with the server-side commands. As root, run slapcat and you should see something similar to the following:
dn: dc=daa,dc=com,dc=au objectClass: top objectClass: dcObject objectClass: organization o: daa.com.au dc: daa structuralObjectClass: organization entryUUID: c2a8b180-ee60-102c-9e7b-914c836f2853 creatorsName: createTimestamp: 20080725064340Z entryCSN: 20080725064340.037379Z#000000#000#000000 modifiersName: modifyTimestamp: 20080725064340Z dn: cn=admin,dc=daa,dc=com,dc=au objectClass: simpleSecurityObject objectClass: organizationalRole cn: admin description: LDAP administrator userPassword:: d2VsbCBkb25lLCB5b3UgY2FuIGJhc2U2NCBkZWNvZGU= structuralObjectClass: organizationalRole entryUUID: c2a95b62-ee60-102c-9e7c-914c836f2853 creatorsName: createTimestamp: 20080725064340Z entryCSN: 20080725064340.041861Z#000000#000#000000 modifiersName: modifyTimestamp: 20080725064340Z
This is the LDIF for the two entries the slapd package created when it was installed. The first is the top of the LDAP tree, dc=daa,dc=com,dc=au. All other entries in the tree will be added below this entry. A common trick encountered when installing OpenLDAP without using the packages is that this entry must be created before you can add any other entries, otherwise you get the error ldap_add: No such object. The second entry is the database administrator. This object doesn't need to exist, you could just put the rootpw in slapd.conf, however if it's in the database you can use ACLs to limit which hosts the rootdn can authenticate from.
Note that creatorsName and modifiersName are empty. This is because they were added using slapadd, which bypasses slapd and directly writes to the database. This is a two-edged sword - it does allow you to set operational attributes, which are normally managed by the server, but it also allows you to fuck up your database if you're not careful. Generally slapadd is only used when restoring from backup (created using slapcat), particularly since it requires slapd to be stopped.
The client-side commands start with ldap and use the LDAP protocol to talk to the LDAP server. They use the libldap library, which has defaults configured via /etc/ldap/ldap.conf. Add the following lines to it so you don't have to enter them on the command line all the time:
BASE dc=example,dc=com URI ldap://your.ldap.server/
See the ldap.conf(5) man page for other options that can be set.
Now, as your regular user, run ldapsearch -x (if you hadn't edited ldap.conf you'd have to run ldapsearch -x -b dc=example,dc=com -H ldap://your.ldap.server/) and you should get something similar to the following:
# extended LDIF # # LDAPv3 # base <dc=daa,dc=com,dc=au> with scope subtree # filter: (objectclass=*) # requesting: ALL # # daa.com.au dn: dc=daa,dc=com,dc=au objectClass: top objectClass: dcObject objectClass: organization o: daa.com.au dc: daa # admin, daa.com.au dn: cn=admin,dc=daa,dc=com,dc=au objectClass: simpleSecurityObject objectClass: organizationalRole cn: admin description: LDAP administrator # search result search: 2 result: 0 Success # numResponses: 3 # numEntries: 2
As you can see, userPassword isn't shown, since anonymous users don't have permission to read it. Also the operational attributes were not returned. To see them, run ldapsearch -x + - + is an OpenLDAP extension to request all attributes. The syntax for ldapsearch is ldapsearch [options] [LDAP filter] [list of attributes]. All the options are listed in the ldapsearch(1) man page, but the most useful ones are -x for simple authentication instead of SASL (there's no way to default to using simple auth, so you'll always be using -x), -D binddn to authenticate as a user, -W to interactively enter a password (you could use -w password but someone could run ps and see it), and -b (base|one|sub|children)' which controls how deeply the tree is searched. If you want to have a poke around your LDAP server, run ldapsearch -x -b '' -s base which shows what features slapd supports.
There are various other OpenLDAP client utilities like ldapmodify, ldapadd (actually just a link to ldapmodify), ldapdelete, ldappasswd and ldapwhoami which are basic wrappers for the libldap library calls. One very useful tool that's not part of OpenLDAP is ldapvi (apt-get install ldapvi) which performs a search, opens the resulting LDIF in your favorite $EDITOR, then sends your changes (if any) back to the server. Another good one is shelldap (not yet in Debian, but will be soon) which is a shell-like interface for browsing and editing an LDAP tree as if it were a filesystem.
There are many graphical LDAP clients about, but my recommendation is Apache Directory Studio. Yes, it's written in Java and requires Eclipse, but is unreasonably good despite this. Unfortunately the latest release requires Eclipse 3.3, but the latest version in Debian and Ubuntu is 3.2, so you'll have to download the standalone version.
Importing existing users
First we need to create some structure for the users to go in. The account entries are located in a subtree, typically called ou=People. Groups are located in ou=Group. To create these entries, put the following a file, eg /tmp/ou.ldif:
dn: ou=People,dc=example,dc=com ou: People objectClass: organizationalUnit dn: ou=Group,dc=example,dc=com ou: Group objectClass: organizationalUnit
Now add it to the server with this command: ldapadd -x -D cn=admin,dc=example,dc=com -W -f /tmp/ou.ldif.
Next, add some indexes to make searches go faster. Replace the index objectClass eq with the following:
index cn,sn,uid,displayName pres,sub,eq index uidNumber,gidNumber eq index objectClass pres,eq index memberUid eq index uniqueMember eq
then as root run
/etc/init.d/slapd stop slapindex chown -R openldap:openldap /var/lib/ldap /etc/init.d/slapd start
to create these indexes.
The traditional way to import users is PADL's MigrationTools or smbldap-tools, which are both available in Debian/Ubuntu - migrationtools and smbldap-tools respectively. However both are somewhat icky perl and I don't really trust them (if I had to choose I'd use MigrationTools) since they often add system groups, so here's a simple python script to import existing users:
1 import pwd,spwd,grp,ldif,sys,socket
2 # Get user/groups range. If you have users outside this range, just set {fir,la}st[ug]id manually
3 adduser = file("/etc/adduser.conf",'r')
4 for line in adduser:
5 if line[:9]=='FIRST_UID':
6 firstuid=int(line[10:])
7 if line[:8]=='LAST_UID':
8 lastuid=int(line[9:])
9 if line[:9]=='FIRST_GID':
10 firstgid=int(line[10:])
11 if line[:8]=='LAST_GID':
12 lastgid=int(line[10:])
13 adduser.close()
14 # If this doesn't detect it correctly, check your /etc/hosts file or just set it manually
15 domain = socket.getfqdn().split('.')[1:]
16 # Set the base DN.
17 base = ','.join(['dc=%s' % i for i in domain])
18 domain = '.'.join(domain)
19 pwall = pwd.getpwall()
20 grpall = grp.getgrall()
21 ldifw = ldif.LDIFWriter(sys.stdout)
22
23 for user in pwall:
24 if firstuid <= user.pw_uid <= lastuid:
25 shadow = spwd.getspnam(user.pw_name)
26 surname = ''
27 given = ''
28 # This ignores any GECOS data
29 name = user.pw_gecos.split(',')[0]
30 names = name.split()
31 if len(names) > 1:
32 surname = names[-1]
33 given = ' '.join(names[:-1])
34 dn = 'uid=%s,ou=People,%s' % (user.pw_name,base)
35 entry = {
36 'cn': [name],
37 'objectClass': ['inetOrgPerson', 'posixAccount', 'shadowAccount', 'top'],
38 'uid': [user.pw_name],
39 'displayName': [name],
40 'uidNumber': [str(user.pw_uid)],
41 'gidNumber': [str(user.pw_gid)],
42 'givenName': [given],
43 'sn': [surname],
44 'mail': ['%s@%s' % (user.pw_name,domain)],
45 'gecos': [name],
46 'homeDirectory': [user.pw_dir],
47 'loginShell': [user.pw_shell],
48 'shadowLastChange': [str(shadow.sp_lstchg)],
49 'shadowMin': [str(shadow.sp_min)],
50 'shadowMax': [str(shadow.sp_max)],
51 'shadowWarning': [str(shadow.sp_warn)],
52 'shadowInactive': [str(shadow.sp_inact)],
53 'shadowExpire': [str(shadow.sp_expire)],
54 'shadowFlag': [str(shadow.sp_flag)],
55 'userPassword': [ '{CRYPT}' + shadow.sp_pwd] }
56 # clean up whitespace
57 for i in entry.keys():
58 entry[i] = [t.strip() for t in entry[i]]
59 entry[i] = [t for t in entry[i] if t]
60 # sn and cn are required by schema
61 if not entry.get('sn', None):
62 entry['sn'] = ["No surname"]
63 if not entry.get('cn', None):
64 entry['cn'] = ["No name"]
65 ldifw.unparse(dn, entry)
66
67 for group in grpall:
68 if firstgid <= group.gr_gid <= lastgid:
69 dn = 'cn=%s,ou=Group,%s' % (group.gr_name, base)
70 entry = {
71 'cn': [group.gr_name],
72 'objectClass': ['posixGroup', 'top'],
73 'gidNumber': [str(group.gr_gid)] }
74 if group.gr_mem:
75 entry['memberUid'] = group.gr_mem
76 ldifw.unparse(dn,entry)
Some things to note about this script:
Although the password scheme is {CRYPT}, this uses the crypt(3) library function, which on Linux has support for salted MD5. Future password changes will use {SSHA}, as that's the slapd password-hash default - see slapd.conf(5) and the OpenLDAP Faq-O-Matic for more details.
User information added by chfn(1) (eg phone numbers) is silently dropped, but it's not too hard to modify this script to keep it.
The schema for inetOrgPerson requires cn and sn, so fake values are used if there's no name.
To use this script, run it and redirect the output to a file, review it and remove any system users that have crept in, then use ldapadd to import it:
./pw2ldap.py > /tmp/users.ldif ldapadd -x -D cn=admin,dc=daa,dc=com,dc=au -W -f /tmp/users.ldif
Linux
Name resolution in Linux is performed by glibc, using the NSS (name service switch) facility which is configured using /etc/nsswitch.conf and loads /lib/libnss_* modules as required. The Linux nss_ldap module is written by PADL, and comes in the libnss-ldap package in Debian and Ubuntu.
Most Linux distributions (Slackware being the notable exception, but I doubt many lazy sysadmins use it) use Linux-PAM (pluggable authentication modules), as their authentication system. The pam_ldap module was also written by PADL, uses a similar file (in some cases the same file) as the LDAP NSS module, and comes in the libpam-ldap package.
Install them both, then answer the debconf questions:
apt-get install libnss-ldap
- LDAP server Uniform Resource Identifier
- ldap://quoll.daa.com.au
- Distinguished name of the search base
- dc=daa,dc=com,dc=au
- LDAP version to use
- 3
- Make local root Database admin
- Yes
- Does the LDAP database require login?
- No
- LDAP account for root
- cn=admin,dc=daa,dc=com,dc=au
- LDAP root account password
- PASSWORD
This will write to /etc/libnss-ldap.conf and /etc/pam_ldap.conf under Debian, and /etc/ldap.conf under Ubuntu (since 7.10). I don't recommend keeping these files under debconf, so edit them and remove the first line. Note that /etc/ldap.conf and /etc/ldap/ldap.conf are different files - the first is for lib{nss,pam}-ldap, while the second is for all programs that link against libldap (which confusingly includes lib{nss,pam}-ldap, however /etc/ldap.conf takes precedence for them).
Now, while the NSS and PAM LDAP modules are installed, they're not yet being used. To activate them, run
auth-client-config -a -p ldap_example
under Ubuntu and it should update everything automagically. On Debian you need to update various files manually. Edit /etc/nsswitch.conf and replace the passwd and group lines with the following:
passwd: files ldap group: files ldap
This means /etc/passwd and /etc/group will be checked for users and groups first, then LDAP will be searched.
Then edit the common-* files in /etc/pam.d and replace the required pam_unix.so with the following:
/etc/pam.d/common-account:
account sufficient pam_unix.so account required pam_ldap.so
/etc/pam.d/common-auth:
auth [success=1 default=ignore] pam_unix.so nullok_secure auth required pam_ldap.so try_first_pass auth required pam_permit.so
/etc/pam.d/common-password:
password sufficient pam_unix.so nullok obscure md5 password required pam_ldap.so use_authtok
Only if you're not sharing home directories by NFS: /etc/pam.d/common-session:
session required pam_unix.so session required pam_mkhomedir.so skel=/etc/skel/ umask=0022
PAM configuration files are very sensitive to variations in ordering and words - the examples above should work, but if not you should read the PAM configuration file syntax to learn the difference between 'requisite', 'required', 'suffficient' and 'optional'.
You may have noticed I haven't mentioned how to set up nscd - the name service caching daemon. That's because it's the devil and worse than useless for the sort of environment this guide is aimed at. All it will do is cause confusion and pain. If you are performing thousands of name service lookups per second, then nscd is something you should look at, but very few servers do anywhere near that amount.
Right now we have a basic LDAP setup working. However, it's missing two things - reliability and security.
Replication
Reliability is handled by replication of the database to another machine running slapd. Just about every LDAP client can handle being given more than one LDAP servers to use if the primary is down. The OpenLDAP Administrator's Guide chapter on replication is pretty good and goes into the background of how it works, so you should read it, but if you don't have time, here's the short version.
Syncrepl is the new hotness for replication, ignore any OpenLDAP guide that mentions slurpd, particularly since it's been removed in 2.4. You can do all kinds of cool replication setups with syncrepl, including multi-master and mirror-mode, but for simplicity I'll only cover basic replication to a read-only slave that forwards updates to the master.
First the server's slapd.conf needs a few extra items. Add moduleload syncprov after moduleload back_hdb, then add the following lines after the existing indexes:
index entryUUID,entryCSN eq # replication overlay syncprov syncprov-checkpoint 100 10 syncprov-sessionlog 100
and run
/etc/init.d/slapd stop slapindex chown -R openldap:openldap /var/lib/ldap /etc/init.d/slapd start
to generate the new indexes. Further down, add these lines before the access to attrs=userPassword,shadowLastChange section:
# SASL auth for syncagent authz-regexp uid=([^,]*),cn=digest-md5,cn=auth cn=$1,ou=profile,dc=ucc,dc=gu,dc=uwa,dc=edu,dc=au # replication sync access to * by dn.base="cn=syncagent,ou=profile,dc=daa,dc=com,dc=au" read by * break limits dn.exact="cn=syncagent,ou=profile,dc=daa,dc=com,dc=au" size=unlimited time=unlimited
Since a rootdn is required for syncrepl, uncomment the rootdn line (just after the database and suffix lines in the default config) and delete all the by dn="cn=admin,dc=daa,dc=com,dc=au" write lines in the access to statements, otherwise you'll get warnings on startup.
Those of you who are reading closely will note that I'm using SASL to authenticate the synchronisation agent, despite my earlier statement I wouldn't cover it. In this case since the password is only used for synchronisation, not general authentication, there's no downside to using SASL. Add the user with the following LDIF (again, use pwgen to generate a password) :
dn: ou=profile,dc=daa,dc=com,dc=au ou: profile objectClass: top objectClass: organizationalUnit dn: cn=syncagent,ou=profile,dc=daa,dc=com,dc=au cn: syncagent objectClass: top objectClass: person sn: syncagent userPassword: {CLEARTEXT}PASSWORD
Next, install slapd on the slave server. It doesn't matter what you answer to the debconf questions as we'll be replacing the config immediately. Stop slapd, delete all files in /var/lib/ldap and copy across the slapd.conf from the primary. We need to make a few changes - remove the syncproc and syncagent lines, and add the following in their place:
syncrepl rid=19 provider=ldap://quoll.daa.com.au type=refreshAndPersist searchbase="dc=daa,dc=com,dc=au" bindmethod=sasl authcid=syncagent saslmech=DIGEST-MD5 credentials=PASSWORD retry="10 3 300 +" updateref ldap://quoll.daa.com.au
rid is a identifier for replication, which must be unique per slapd. refreshAndPersist means the slave will receive changes as soon as they are made on the server. Most of the other arguments are obvious, retry="10 3 300 +" means if an error occurs (eg the connection is lost), it will retry every 10 seconds the first three times, then every 300 seconds afterwards (the + means forever - see slapd.conf(5) for full details).
You should now be able to start slapd on the slave and it will sync across your entire database immediately. You can now replace any LDAP URIs (eg in NSS/PAM configs) with ldap://master.example.com/ ldap://slave.example.com/ and they will automatically fail over if the master goes down.
The main thing you have to watch out for with a replication setup is keeping the config files in sync. Replication will function fine even if ACLs, overlays and indexes differ, which can lead to poor performance, missing features or unintended data disclosure. For a small setup it's not too hard to do it by hand. Larger sites will probably want to use the include directive (warning: it's broken in <2.3.40 and <2.4.8) or use syncrepl on cn=config, but that's getting into serious voodoo so I won't cover it here - see the N-Way Multi-Master section of the administrator's guide for an example.
What the manual does not cover is single-master, multiple-slave configuration with cn=config replication, instead referring you to the source code for the test suite, of all things. Here is how to go about it using the existing sync agent profile.
To edit cn=config (/!\ should be covered in a new section), use ldapvi --host ldapi:/// -Y EXTERNAL -D cn=config -Y EXTERNAL -b cn=config (or slapadd instead of ldapvi or whatever; shelldap does not support SASL).
Edit the master config to include the following stanzas:
In cn=config, add
olcServerID: 001 ldap://master.example.com olcServerID: 002 ldap://slave.example.com
(you can use whatever numbers you like as long as they are less than 0xFFF; we use the last octet of the IP address of the host.)
Then add olcOverlay=syncprov,olcDatabase={0}config,cn=config with
objectClass: olcOverlayConfig objectClass: olcSyncProvConfig olcOverlay: syncprov
and add an ACL stanza to allow it access, in olcDatabase={0}config,cn=config:
olcAccess: {1}to * by dn.base="cn=syncagent,ou=profile,dc=ucc,dc=gu,dc=uwa,dc=edu,dc=au" read by * +0 break
Now, on your newly-installed slave, in olcDatabase={0}config,cn=config, add
olcSyncrepl: {0}rid=7 provider=ldap://master.example.com type=refreshAndPersist bindmethod=sasl authcid=syncagent saslmech=DIGEST-MD5 credentials=PASSWORD retry="10 3 300 +" searchbase="cn=config"
This sets up replication of all the config. If you make a change to the schema, for example, you will see that reflected on the slave.
Back on the server, initialise replication of the database:
In olcDatabase={1}hdb,cn=config, add
olcAccess: {0}to * by dn.base="cn=syncagent,ou=profile,dc=ucc,dc=gu,dc=uwa,dc=edu,dc=au" read by * +0 break olcSyncrepl: {0}rid=18 provider=ldap://mussel.ucc.gu.uwa.edu.au bindmethod=sasl credentials="PASSWORD" saslmech=DIGEST-MD5 authcID="syncagent" searchbase="dc=ucc,dc=gu,dc=uwa,dc=edu,dc=au" type=refreshAndPersist retry="10 3 300 +"
The rid in the olcSyncrepl line MUST match the rid for the master server; otherwise the master will try to get updates from somewhere else, and you don't want that.
SSL/TLS
First, some background. X.509 a standard for public-key infrastructure, and is part of the X.500 series of standards which LDAP is descended from. SSL/TLS are protocols that use X.509 certificates to provide a secure transport layer for higher-level protocols, like LDAP and HTTP. SSL is the predecessor to TLS, and they are largely the same, however TLS offers a few more features. One of these is StartTLS, which allows you to open an unencrypted connection, then negotiate TLS and upgrade to a secure connection. The benefit of this is you only need one port open instead of two, but the disadvantage is it's much harder to guarantee all traffic is encrypted. When talking about LDAP, TLS is often used as a term for StartTLS, vs SSL which refers to LDAPS on a dedicated port (usually 636).
There's much more to SSL than that - it's a topic deserving of an entire HOWTO by itself. Unfortunately most suffer from cargo-cult syndrome; Survival Guide - SSL/TLS and X.509 Certificates is pretty good, apart from its use of CA.pl which is still a bit manual for my liking. Fortunately OpenVPN includes a set of scripts called easy-rsa that lives up to its name. By default it creates certificates valid for 10 years, by which time updating the PKI should be SEP.
First, install openvpn and copy the easy-rsa scripts under /etc/ssl:
apt-get install openvpn cp -a /usr/share/doc/openvpn/examples/easy-rsa/2.0/ /etc/ssl/CA
Edit /etc/ssl/CA/vars and set the bottom five KEY_ variables, although these are mainly only aesthetically important. Initialise the environment and create the CA:
. vars ./clean-all ./build-ca --pass
You'll be asked for a password and then some details about the CA, defaulting to the values you just set in vars. The CA will then be created in the keys/ subdirectory, and consists of 4 files:
- ca.crt
- The CA certificate. Used by clients as an authority that identifies servers, and hence is public and copied around lots.
- ca.key
- The CA private key. Encrypted by the password, and should only be readable by admins.
- index.txt
- A list of signed keys. Not private, but doesn't need to be copied.
- serial
- The serial number used for signing the next key. Also not private but doesn't need to be copied.
Next, create a certificate for the LDAP server:
./build-key-server ldap
Again the fields are mostly unimportant, with the exception of the Common Name, which is vital - it must match the hostname used to access the LDAP server. If it doesn't match, then the TLS client will reject the certificate and not establish a connection.
This will have created several files in keys/, of which the pertinent ones are ldap.crt and ldap.key. Similarly to the CA, ldap.key is secret and ldap.crt is not. Now, copy the required files to /etc/ldap and set the appropriate permissions:
cp keys/{ca.crt,ldap.key,ldap.crt} /etc/ldap chgrp openldap /etc/ldap/ldap.key chmod 640 /etc/ldap/ldap.key
To tell the OpenLDAP server about the certificates and keys, edit /etc/ldap/slapd.conf and add the following lines at the bottom:
# SSL support TLSCertificateFile /etc/ldap/ldap.crt TLSCertificateKeyFile /etc/ldap/ldap.key TLSCACertificateFile /etc/ldap/ca.crt
LDAP clients just need to know about the CA, which is done by adding this line to /etc/ldap/ldap.conf:
TLS_CACERT /etc/ldap/ca.crt
Finally, edit /etc/default/slapd and add (or uncomment) the following line:
SLAPD_SERVICES="ldap://127.0.0.1:389/ ldaps:/// ldapi:///"
This tells slapd to only accept unencrypted connections from localhost, and TLS-secured connections from anywhere. ldapi uses a Unix domain socket and won't be covered here.
OK, now everything should be set, /etc/init.d/slapd restart and test it like so:
ldapsearch -x -H ldaps://quoll.daa.com.au/
If it works, you can update /etc/ldap.conf//etc/libnss-ldap.conf//etc/pam_ldap.conf with the ldaps:// URI, and add (or uncomment) the following lines:
ssl on tls_cacertfile /etc/ldap/ca.crt
(technically the second line isn't needed as they inherit TLS_CACERT from /etc/ldap.conf)
Also needing updating will be the config on the slave server - copy across ca.crt, edit the uris in slapd.conf but you'll need to generate a second server key with the appropriate common name to match the slave's hostname.
TODO: TLSCipherSuite HIGH:MEDIUM or however it's done with gnutls.
Access Control
http://www.openldap.org/doc/admin24/access-control.html
Solaris
Solaris' LDAP client is a bit special, and not in a good way. The standard "search for the username's DN anonymously, then bind using that DN" method doesn't work for arcane reasons, so you need a proxy agent to do the search.
The supplied idsconfig tool is only really for Sun's (originally Netscape's) LDAP server, and while there are patches around to make it work with OpenLDAP, they're outdated and not actually needed. What need to do is download the solaris specific schemas, DUAConfigProfile.schema solaris.schema and put them in /etc/ldap/schema.
Next, add the profiles and proxy account. Full details to be added, but for the moment you could do worse than use the appropriate ldif files at http://developers.sun.com/identity/reference/techart/opends-namesvcs.html#5
Once you have a profile set up, the rest is fairly easy. First, edit /etc/nsswitch.ldap and replace the hosts, ipnodes etc. lines with the following:
# Sun are fucking idiots for thinking hosts should go over LDAP hosts: files dns # Note that IPv4 addresses are searched for in all of the ipnodes databases # before searching the hosts databases. ipnodes: files dns networks: files ldap protocols: files ldap rpc: files ldap ethers: files ldap netmasks: files ldap bootparams: files ldap publickey: files ldap
If you don't do this, Solaris will try and use LDAP for hosts, which is a fucking stupid idea given TLS requires hostnames.
Next, run ldapclient init -v -a profileName=default -a defaultServerList=ldap.daa.com.au -a domainName=daa.com.au -a proxyDN=cn=proxyagent,ou=profile,dc=daa,dc=com,dc=au which will ask for the bind password, then configure the system to use LDAP for NSS (including copying /etc/nsswitch.ldap to /etc/nsswitch.conf). The final step is to configure PAM, so edit /etc/pam.conf - either apply pam.conf.diff or make the following changes manually:
Old:
# login service (explicit because of pam_dial_auth) # login auth requisite pam_authtok_get.so.1 login auth required pam_dhkeys.so.1 login auth required pam_unix_cred.so.1 login auth required pam_unix_auth.so.1 login auth required pam_dial_auth.so.1
New:
# login service (explicit because of pam_dial_auth) # login auth requisite pam_authtok_get.so.1 login auth required pam_dhkeys.so.1 login auth required pam_unix_cred.so.1 login auth binding pam_unix_auth.so.1 server_policy login auth required pam_dial_auth.so.1 login auth required pam_ldap.so.1
Old:
# Default definitions for Authentication management # Used when service name is not explicitly mentioned for authentication # other auth requisite pam_authtok_get.so.1 other auth required pam_dhkeys.so.1 other auth required pam_unix_cred.so.1 other auth required pam_unix_auth.so.1
New:
# Default definitions for Authentication management # Used when service name is not explicitly mentioned for authentication # other auth requisite pam_authtok_get.so.1 other auth required pam_dhkeys.so.1 other auth required pam_unix_cred.so.1 other auth binding pam_unix_auth.so.1 server_policy other auth required pam_ldap.so.1
Old:
# Default definition for Account management # Used when service name is not explicitly mentioned for account management # other account requisite pam_roles.so.1 other account required pam_unix_account.so.1
New:
# Default definition for Account management # Used when service name is not explicitly mentioned for account management # other account requisite pam_roles.so.1 other account binding pam_unix_account.so.1 server_policy other account required pam_ldap.so.1
Add this at the bottom:
# SSH publickey support: # see http://lists.ucc.gu.uwa.edu.au/pipermail/tech/2007-February/003146.html sshd-pubkey account requisite pam_roles.so.1 sshd-pubkey account required pam_unix_account.so.1
certutil
http://blog.maniac.nl/setting-up-ldap-with-openldap-server-solaris-10-aix-61-and-linux-clients/ http://docs.lucidinteractive.ca/index.php/Solaris_LDAP_client_with_OpenLDAP_server
Tru64
ldapcd, certutil Tru64 LDAP Documentation http://forums11.itrc.hp.com/service/forums/questionanswer.do?admit=109447626+1218017020582+28353475&threadId=1084988
OS X
Directory Utility or whatever it's called. screenshots.
Samba/Windows
This covers using Samba 3 as an NT4 Domain Controller using the same n*x accounts and passwords already stored in LDAP. If you want to do something else, like joining an existing Windows domain or Active Directory tree, or using Samba 4 (currently in alpha) to be an Active Directory domain controller, this is not the guide for you. Samba is pretty flexible and there's more than one way to do many things, including using winbind to authenticate n*x servers from it, but for this guide it's assumed n*x servers use plain LDAP and Samba is just for Windows clients.
To do.
smbk5pwd
smbk5pwd is a nifty little overlay that updates both the sambaLMPassword, sambaNTPassword and regular userPassword attributes. This means if you change your n*x password using passwd the Windows password is updated, and changing your password in Windows' Ctrl-Alt-Del dialog changes the n*x password.
Compiling it is a bit of a pain, if you're using Debian use the patch from Debian bug 443073 and rebuild slapd:
cd /usr/src apt-get source slapd apt-get build-dep slapd wget "http://bugs.debian.org/cgi-bin/bugreport.cgi?msg=85;filename=smbk5pwd.diff;att=1;bug=443073" \ -O smbk5pwd.diff cd openldap-2.4.11 dch -i "Rebuild including smbk5pwd." debuild -us -uc -b cd .. dpkg -i libldap-2.4-2_2.4.11-2_i386.deb ldap-utils_2.4.11-2_i386.deb slapd_2.4.11-2_i386.deb slapd-smbk5pwd_2.4.11-2_i386.deb
For Ubuntu, the easiest way is to use the packages from the PPA mentioned in the Ubuntu bug.
Once this is done, add moduleload smbk5pwd and overlay smbk5pwd in /etc/ldap/slapd.conf below the other moduleload and overlay directives, and if using the Ubuntu PPA, smbk5pwd-enable samba (as we don't want Heimdal support) and restart slapd. You don't need to do any of this on the slave, as all writes are directed to the master, including password changes. pam_ldap should already be configured to use the LDAP password change exteneded operation, check for pam_password exop in /etc/pam_ldap.conf (Debian) or /etc/ldap.conf (Ubuntu). For samba, set ldap passwd sync = only in /etc/samba/smb.conf.
Since I haven't written the Samba part yet, you'll need to install the Samba schema on both the master and slave:
apt-get install samba-doc cd /etc/ldap/schema zcat /usr/share/doc/samba-doc/examples/LDAP/samba.schema > samba.schema
and edit slapd.conf and add include /etc/ldap/schema/samba.schema after the other schema include lines.
FreeRADIUS
Why bother setting up FreeRADIUS to authenticate from an LDAP server? Because if you have NTPasswords thanks to samba, you can set up the PoPToP PPTP server so Windows users can VPN in using the same password, or use an 802.1x authenticator to do WPA{,2}-Enterprise wireless authentication or port-based wired authentication.
RADIUS is yet another enormously complex protocol, again deserving of its own HOWTO, but the changes required to a stock FreeRADIUS install for PPTP and 802.11x are thankfully minor. Like OpenLDAP, the official FreeRADIUS documentation warns against using HOWTOs that are not maintained by the FreeRADIUS team, so YMMV. The official documentation on PPTP is a bit vague, unfortunately. The 802.1X Port-Based Authentication HOWTO is old, but good.
RADIUS deals with the three As: authentication, authorization and accounting. Only the first two will be dealt with here.
Authentication means determining who a user really is, and is the most obvious use of LDAP - as a password store. Beware trying to use LDAP as the Auth-Type module itself, as this will try and authenticate by binding to the LDAP server. This only works if you have cleartext passwords. Instead, what you want to do is instruct the RADIUS server to use LDAP to retrieve hashes for the real authentication module.
RADIUS defines a massive suite of authentication protocols, all of which can be layered on top of each other. For PPTP, you want to use EAP (extensible authentication protocol) with MS-CHAPv2. This means not using MS-CHAPv2 on its own - EAP provides the framework for the authentication conversation, and the actual password exchange protocol is MS-CHAPv2. On the other hand, 802.11x is even more complicated than this - the EAP-MSCHAPv2 combination is itself encapsulated in a TLS secure tunnel, forming PEAPv0/MS-CHAPv2. (Windows Vista and above clients can support PEAP/MSCHAPv2 on the PPTP link, but luckily there seems to be an acceptable degree of autonegotiation of encryption protocol.)
Authorization is checking whether a given user is allowed to connect.
The documentation for the RADIUS LDAP module is in the rlm_ldap(5) manpage.
Set up the LDAP connection first. In radius.conf, find the ldap block (part of the modules block), and set the variables as follows:
server = "ldapserver.your.domain" identity = "admin_dn" password = admin_password basedn = "search_base_dn"
do these variables need explaining?
If you're using SSL as described above, you should also find the tls block for the ldap module, and set the appropriate certificate variables, usually just cacertfile.
While you're editing the ldap module, change the access_attr setting. This controls whether an LDAP object can be used for RADIUS lookups; the simplest way to enable access for all users is to set this to uid. There are more complex options - see the documentation if you really need that.
The final change in radius.conf is in the mschap section, which deals with general options for the MS-CHAP and MS-CHAPv2 modules. Enabling the use of MPPE attributes (the encryption parameters for PPTP connections) is the only change required here:
use_mppe = on
Next, you need to fix the attributes that the LDAP modules uses to get the Samba passwords. Make the following changes to the ldap.attrmap file:
From
checkItem LM-Password lmPassword checkItem NT-Password ntPassword
to
checkItem LM-Password sambaLMPassword checkItem NT-Password sambaNTPassword
Next, edit the eap.conf file, which is the behemoth that controls the EAP system. Luckily, you only need a simple change here: change the default_eap_type from md5 to mschapv2.
The above changes will allow the default configuration (sites-enabled/default) to authenticate against LDAP. You now need to turn on authorization using the access-allowed settings as described above, by editing sites-enabled/default and uncommenting the ldap option in the authorize module.
That's it for PPTP - you should now be able to point your PPTP server at the RADIUS server (doing so is beyond the scope of this document.)
For 802.1x and WPA-Enterprise, a few more changes are necessary.
If you are using the Debian packages of FreeRADIUS, you have to rebuild them. PEAP requires FreeRADIUS built against OpenSSL, which contravenes Debian guidelines. A few changes to the package configuration are required, and are well-summarised at Building Debian FreeRadius package with EAP/TLS/TTLS/PEAP support.
cd /usr/src apt-get source freeradius cd freeradius-$version # apply the changes in the page above debuild -us -uc -b dpkg -i {freeradius,freeradius-common,freeradius-ldap,freeradius-utils,libfreeradius2}-$version-$arch.deb
Set up server-side TLS certificates for the encrypted tunnel. You can probably just use the LDAP certificates you've already generated, or create some different ones using the process above. Edit eap.conf and find the tls block, then change the following variables as appropriate:
private_key_file = ${certdir}/radius.key certificate_file = ${certdir}/radius.crt CA_file = /etc/ssl/CA.crt random_file = /dev/urandom
The default configuration uses a different "virtual server" for the EAP exchange in the TLS tunnel. Edit sites-enabled/inner-tunnel and make the same changes as you did to the default file - i.e. uncommenting the ldap option in the authorize module.
You should now configure your wireless access point or 802.1x-enabled switch to access the RADIUS server.
Adding users
cpu-ldap
Tuning and monitoring OpenLDAP
http://www.openldap.org/doc/admin24/monitoringslapd.html http://www.openldap.org/doc/admin24/tuning.html
Debugging
So, what do you do when things go wrong? For NSS, one of the easiest ways is strace id username. Understanding strace output can be difficult, but what you're looking for is connect() lines featuring the IP address of the LDAP server. If you don't see them, LDAP isn't being queried at all, so look for a local misconfiguration. For other LDAP clients, turn up their logging if possible or strace a running process then perform the LDAP operation. Again, you're looking for connect() calls to your LDAP server.
If the program is successfully connecting to the LDAP server, next is to look at the server logs. They're in /var/log/debug by default, or wherever you put them if you edited /etc/syslog.conf. You'll need stats in the loglevel line of /etc/ldap/slapd.conf, which will show the LDAP binds and searches. Check to see that the searches are what you expect, and if so, perform them yourself from the command line with ldapsearch(1).
Another approach is to use Wireshark or another packet sniffer to examine the operations over the wire, although this won't work for SSL encrypted connections. Finally, if you are running nscd, stop it while debugging otherwise you'll be confused by stale results.
Getting Help
There are several places you can get help if something isn't working. You could try #ldap or #openldap on Freenode where I and others lurk. There's the OpenLDAP mailing lists which I don't read, but the authors of OpenLDAP do. Don't email me privately, I won't answer your question. As for distribution support, Ubuntu is pretty abysmal eg making big changes in 9.10 but not updating the documentation, Debian's ok.
References
[2] discuss what can be specified in schema [3] including a binary attribute, say jpegPhoto, leading to a DN thousands of characters long [4] itself in core.schema - a common mistake is include core.schema but not cosine.schema leading to objectClass unknown errors.