====== Open LDAP Server ====== mirored from http://www.metaconsultancy.com/whitepapers/ldap.htm ---- It is often convenient to share system information among workstations. For example, users like to be able to log in to multiple machines with the same password; this requires that the machines share the data conventionally stored in /etc/passwd and /etc/shadow. Using NFS usually isn't an option, since that would share all of /etc/, and we may well want some things configured differently on each machine. NIS used to be a common answer to this dilemma, but LDAP (Local Directory Access Protocol) databases, being more flexible and scalable, have now become the preferred solution. LDAP databases are object-oriented (as opposed to relational, for those of you familiar with such beasts). An LDAP database is filled with objects, each of which has associated attributes. Here, for example is a typical object representing a user account. dn: uid=john,ou=people,dc=example,dc=com cn: John Doe uid: john uidNumber: 1001 gidNumber: 100 homeDirectory: /home/john loginShell: /bin/bash objectClass: top objectClass: posixAccount Each object has a DN (distinguished name) attribute that identifies it uniquely. Each object is a member of one or more object classes, which determine which attributes it may and must have, according to a well-defined schema. Objects in an LDAP database are organized into a tree hierarchy, based on their DN. {{wiki:ldap:ltree.png }} By tradition, the organization example.com uses dc=example,dc=com for its root object (but nothing enforces this tradition). Below the root are objects representing different organizational units, such as people or hosts. The children of these objects are the people and hosts themselves. We use [[http://openldap.org|OpenLDAP]], because it's free and works for us. The rest of this whitepaper describes how to set up an OpenLDAP server to hold your organization's user data. ===== Installation ===== slapd is the name of the OpenLDAP LDAP server daemon. apt-get install slapd ldap-utils ===== Basic Configuration ===== The basic configuration file for slapd is /etc/ldap/slapd.conf. The file can be loosely divided into two parts: an operational part, describing how the slapd daemon does its job, and a database part, describing the LDAP datastore (or datastores; a single slapd can serve multiple LDAP databases). Consider first the operational part. A simple example follows. //slapd.conf// # schema include /etc/ldap/schema/core.schema include /etc/ldap/schema/nis.schema schemacheck on # run files pidfile /var/run/slapd.pid argsfile /var/run/slapd.args # timeout (in seconds) for dead connections timeout 60 The schema part loads files which describe which sorts of objects may and must have which properties. Schema files are traditionally stored in the /etc/ldap/schema/ directory. Our example includes only the two most common schema files, but you may well want to load all the schema that ship with OpenLDAP, and even add some more of your own. By declaring schemacheck on, we tell slapd to require that objects conform to schema files before it accepts them. You should always maintain this requirement, as it helps protect you against accidental errors when updating your database. The database-specific part of the configuration file tells slapd the database root DN, and how and where to store the data. Here is a simple example: # ldap database database ldbm suffix "dc=example,dc=com" directory "/var/lib/ldap" Our example stores data using an embedded database which stores files in /var/lib/ldap. The embedded database (ldbm) option is by far the most common backend, and is the only one we will discuss here. OpenLDAP allows other options, but they are much more difficult to configure. ===== Securing OpenLDAP ===== OpenLDAP offers several mechanisms to protect the security of the data it stores. Here we discuss password hashing, access control lists, and connection encryption. The userPassword attribute is special. Clients use it to authenticate themselves to slapd, and slapd stores it in hashed form. (A hash is a transformation which is simple to do, but difficult to undo.) When a user types in a password, it is hased and compared against the stored hash, rather than being compared directly against a stored cleartext password. Since the cleartext password is not stored anywhere, this trick (which is also used by /etc/shadow) keeps your passwords safe even from someone who has broken in to your LDAP server. You can specify the hash algorithm you want slapd to employ in slapd.conf. //slapd.conf// # password hash algorithm password-hash {MD5} We like MD5, since the mechanism is both secure and widely employed. SHA and SSHA are also secure, but less widely employed. CRYPT is the most widely employed hashing mechanism in the Unix universe, but is known to be insecure and should be avoided. It is important to define which users are allowed to read and write which object attributes. These "rights" are defined by ACLs (access control lists) in slapd.conf. Here is a simple example for account information. //slapd.conf// # lock down passwords access to attribute=userPassword by dn="cn=admin,dc=example,dc=com" write by self write by anonymous auth by * none # allow users to write some stuff access to attribute=loginShell,shadowLastChange by dn="cn=admin,dc=example,dc=com" write by self write by * read # everything else is read-only access to * by dn="cn=admin,dc=example,dc=com" write by * read It is easy to make security mistakes when setting ACLs. For example, if you give users write-access to uidNumber, they can set it equal to zero to turn themselves into root. Consider carefully the security implications of each access privilege you grant. By default, LDAP data, including passwords being transmitted for authentication, move across the network in the clear. To protect yourself against eavesdroppers, you should take the simple step of configuring slapd to offer encrypted sessions, and configuring your clients to use them. To enable encrypted sessions, use the openssl utilities to generate a key and corresponding public certificate, and tell slapd to use them for encrypted sessions. slapd.conf TLSCertificateFile /etc/ldap/ldap.example.crt TLSCertificateKeyFile /etc/ldap/ldap.example.key TLSCipherSuite HIGH:+MEDIUM:!LOW It is important that the CN (common name) on the certificate be exactly the FQDN (fully qualified domain name) which clients use to contact your LDAP server. For example, if your server is named ldap.example.com, that should be the certificate CN, and clients should connect using that name, not the corresponding IP address. Such a restriction is only necessary for encrypted sessions. The certificate key file should be readable only by the user as which slapd runs (for the Debian package, this is root). # chmod /etc/ldap/ldap.example.key 0700 ===== OpenLDAP Utilities ===== There are two classes of utility programs which allow you to modify your OpenLDAP database. The slap* programs (slapadd, slapcat, and slapindex) read and modify an LDAP database by operating directly on the files in /var/lib/ldap. To avoid database corruption, they should be employed only when slapd is not running. The ldap* programs (ldapsearch, ldapadd, ldapmodify, ldapdelete, and ldappasswd) read and modify an LDAP database by interacting with the slapd server. They are essentially very simple LDAP clients. They can only be employed when slapd is running. ==== offline (slap*) utilities ==== The slapd* utilities accept ldif files as input. ldif files are just flat textfile lists of objects, with attributes indicated in a key: value format, one per line. Here is an example of a simple ldif file that creates the skeletal structure of a simple LDAP database. /tmp/example.ldif dn: dc=example,dc=com dc: example o: example.com objectClass: top objectClass: dcObject objectClass: organization dn: ou=people,dc=example,dc=com ou: people objectClass: top objectClass: organizationalUnit dn: cn=admin,dc=example,dc=com cn: admin userPassword: secret objectClass: top objectClass: organizationalRole objectClass: simpleSecurityObject Getting these objects into the LDAP database is easy. # /etc/init.d/slapd stop # slapadd -v < /tmp/example.ldif # slapindex -v # /etc/init.d/slapd start Note that we shut down the database before running slapadd. Note also that we ran slapindex after entering the data to update the index files. While indices are automatically maintained when changes are made to a running database (e.g. using ldap* commands), they must be updated "by hand" when changes are made directly to the database files; this is accomplished by running slapindex. The slapcat command is the "opposite" of slapadd. It extracts the contents of an LDAP database into a ldif file. To make a backup of your LDAP database, # /etc/init.d/slapd stop # slapcat > /tmp/example.ldif # /etc/init.d/slapd start Be sure to store the extracted ldif file in a safe place, since anyone who can read it can effectively read all the data in your LDAP database. Since making this backup requires you to shut down your slapd server, backups of large, mission-critical LDAP databases should be made from a replicating database (see slaves section below) designed specifically for this purpose. It is often necessary to use slapadd to create the skeletal structure of a new database, since when a database is first created, it does not contain any administrator object that has permission new objects. Once you have used slapadd to overcome this chicken-and-egg problem, though, you will probably want to use ldap* commands or even a GUI LDAP client for further database modifications. ==== online (ldap*) utilities ==== The ldap* utilities are easily installed on a Debian computer. # apt-get install ldap-utils Keep in mind that these utilities need not be run on the LDAP server. The file /etc/ldap/ldap.conf contains the basic configuration information necessary for the ldap* utilities to know with which LDAP database you want them to interact. A simple example follows. /etc/ldap/ldap.conf URI ldap://localhost BASE dc=example,dc=com The URI directive specifies the LDAP server to use; in our example, we are working on the LDAP server itself. The BASE directive specifies the DN of the root node of the database. The most common way to interact with an LDAP server is to read data stored in it. The ldapsearch command allows you to do this from the command line. For example, to obtain the attributes of objects for which cn=admin, # ldapsearch -x cn=admin dn: cn=admin,dc=example,dc=com objectClass: organizationalRole objectClass: simpleSecurityObject objectClass: top cn: admin You can use * as a wildcard in your search. To get every object in the database, use # ldapsearch -x objectClass=* You can use the ldapadd command to add objects to your ldap database. Like slapadd, ldapadd uses LDIF input syntax. Unlike slapadd, ldapadd interacts with slapd via LDAP to make its modifications. Therefore it can be used across the network, can (in fact must) be used while slapd is running, and allows background tasks such as schema checking, indexing, modification time stamps, and replication to be handled transparently by slapd instead of by hand. For example, to add a user account, we prepare an LDIF file /tmp/user.ldif dn: uid=jdoe,ou=people,dc=example,dc=com uid: jdoe cn: Jane Doe uidNumber: 1001 gidNumber: 100 homeDirectory: /home/jdoe userPassword: password loginShell: /bin/bash objectClass: posixAccount and then upload it to the running ldap database $ ldapadd -x -v -D cn=admin,dc=example,dc=com -W < /tmp/user.ldif Note that we bind as the administrator in order to gain write privleges. The ldapmodify utility allows you to modify the attributes to existing ldap objects, and the ldapdelete utility allows you to delete an ldap object completely. The ldappasswd utility, the last of the ldap* suite, is used to change userPassword attributes. Don't use ldapmodify to do this, since that will write a value to the attribute directly, bypassing the hashing specified in slapd.conf. For the administrator to change Jane's password, $ ldappasswd -x -v -S -W -D cn=admin,dc=example,dc=com uid=jdoe,ou=people,dc=example,dc=com ==== Migration Utilities ==== PADL software makes available a set of migration tools which ease the transition from a system using flat files (/etc/passwd, /etc/group, /etc/hosts, /etc/networks, /etc/services, /etc/protocols) to a central directory server. You can download these tools from the PADL site, or install the Debian package # apt-get install migrationtools which places them in /usr/share/migrationtools/. To use these tools, # cd /usr/share/migrationtools # ./migrate_passwd.pl /etc/passwd /tmp/passwd.ldif ===== Performance Tuning ===== LDAP databases take a beating. Every email, every login attempt, every directory listing (ls) on any machine at your site can result in a lookup. Fortunately, there are a number of things you can (and should!) do to increase OpenLDAP's performance. Begin by generating indices, which are database tables that can be used to track down a record much faster than by looking though the entire database. /etc/ldap/slapd.conf index objectClass eq,pres index uid,uidNumber,gidNumber eq,pres index mailLocalAddress eq,pres If monitoring (e.g. using top) indicates that slapd is often consuming a significant fraction of your CPU time, you are probably missing a useful index. LDAP lookup should be I/O-bound, not CPU-bound. Try to give slapd enough memory to hold all or most of its data in memory. The cachesize directive specifies how many attribute values are cached in memory. The dbcachesize directive specifies the size, in bytes, of the space allocated to store database files in memory. The defaults for these numbers are almost never large enough. For our small organization, I use slapd.conf cachesize 10000 dbcachesize 1000000 Ideally, cachesize is as large as the total number of entries in your database, and dbcachesize is as large as all the files in the /var/lib/ldap directory. At larger sites, you may find that your LDAP server needs quite a bit of memory in order to attain these objectives. Make sure you are not writing more to your log files than you need to. If you can get away without an audit trail, set loglevel to 0. If you really need an audit trail, set loglevel to 256, and be sure to use a - in /etc/syslogd.conf to allow log entries to be written asynchronously. Minimize lookups by running nscd on your client machines. Consider upping slapd's threads variable to 64 or 128. At very large sites, you may find that your lookup throughput is still insufficient, even after you have taken all these steps. At this point, you may have to invest in more or better hardware. If your throughput is disk I/O bound, consider dedicating a fast, SCSI disk just to /var/lib/ldap, and mount that disk with the noatime option in order to cut down down on access overhead. If your throughput is network I/O bound, make sure you have a fast ethernet card. Check that the packet collision rate suffered by your LDAP server is still low (say 5% or less); if not, you need to upgrade your network. Finally, consider setting up a number of dedicated LDAP slave machines, and assign the number of clients to each slave that produces a load it can handle. Instructions for setting up LDAP slaves are presented in the following section. ===== LDAP Slaves ===== An LDAP slave is an LDAP server whose contents mirror the contents of its LDAP master. Slaves respond to read requests themselves, but when faced with a write request, a slave refers the client to its master. Any change to a master database is propagated to its slaves immediately and automatically; this process is called replication. LDAP slaves are useful for load-balancing; distributing client requests among a number of slaves can keep the master from getting hammered. LDAP slaves are also useful for automatic failover. Many LDAP clients can be configured to fall back to a second LDAP server if the first does not respond; by setting a client's fall-back server to be an LDAP slave, you can keep your system running even if your LDAP master crashes. Setting up a master-slave relationship between two LDAP servers is not difficult. slapd.conf replogfile /var/lib/ldap/replog replica host=slave.example.com:389 binddn="cn=admin,dc=example,dc=org" bindmethod=simple credentials=secret slapd.conf updatedn "cn=admin,dc=example,dc=org" updateref ldap://master.example.org