LDAP

From CSCWiki
(Redirected from Directory Services)
Jump to: navigation, search

We use OpenLDAP for directory services. Our primary LDAP server is auth1 and our secondary LDAP server is auth2.

ehashman's Guide to Setting up OpenLDAP on Debian

Welcome to my nightmare.

What is LDAP?

LDAP: Lightweight Directory Access Protocol

An open, vendor-neutral, industry standard application protocol for accessing and maintaining distributed directory information services over an Internet Protocol (IP) network. — Wikipedia: LDAP

In this case, "directory" refers to the user directory, like on an old-school Rolodex. Many groups use LDAP to maintain their user directory, including the University (the "WatIAM" identity management system), the Computer Science Club, and even the UW Amateur Radio Club.

This is a guide documenting how to set up LDAP on a Debian Linux system.

First steps

  • Ensure that openldap is installed on the machine:

    # apt-get install slapd ldap-utils
  • Debian will do a lot of magic and set up a skeleton LDAP server and get it running. We need to configure that further.
  • Let's set up logging before we forget. Create the following files in /var/log:

    # mkdir /var/log/ldap
    # touch /var/log/ldap.log
  • Set ownership correctly:

    # chown openldap:openldap /var/log/ldap
  • Set up rsyslog to dump the LDAP logs into /var/log/ldap.log by adding the following lines:

    # vim /etc/rsyslog.conf
    ...
    # Grab ldap logs, don't duplicate in syslog
    local4.*                        /var/log/ldap.log
  • Set up log rotation for these by creating the file /etc/logrotate.d/ldap with the following contents:

    /var/log/ldap/*log {
        weekly
        missingok
        rotate 1000
        compress
        delaycompress
        notifempty
        create 0640 openldap adm
        postrotate
            if [ -f /var/run/slapd/slapd.pid ]; then
                /etc/init.d/slapd restart >/dev/null 2>&1
            fi
        endscript
    }
    
    /var/log/ldap.log {
        weekly
        missingok
        rotate 24
        compress
        delaycompress
        notifempty
    }
  • As of OpenLDAP 2.4, it doesn't actually create a config file for us. Apparently, this is a "feature": LDAP maintainers think we should want to set this up via dynamic queries. We don't, so the first thing we need is our slapd.conf file.

Building slapd.conf from scratch
  • Get a copy to work with:

    # scp uid@auth1.csclub.uwaterloo.ca:/etc/ldap/slapd.conf /etc/ldap/  ## you need CSC root for this
  • You'll want to comment out the TLS lines, and anything referring to Kerberos and access for now. You'll also want to comment out lines specifically referring to syscom and office staff.
  • Make sure you remove the reference to nonMemberTerm as an index, as we're going to remove this field.
  • You'll also need to generate a root password for the LDAP to bootstrap auth, like so:

    # slappasswd
    New password: 
    Re-enter new password:
    {SSHA}longhash
  • Add this line below rootdn in the slapd.conf:

    rootpw          {SSHA}longhash
  • Now we want to edit all instances of "csclub" to be "wics" instead, e.g.:

    suffix     "dc=wics,dc=uwaterloo,dc=ca"
    rootdn     "cn=root,dc=wics,dc=uwaterloo,dc=ca"
  • Next, we need to grab all the relevant schemas:

    scp -r uid@auth1.csclub.uwaterloo.ca:/etc/ldap/schema/ /tmp/schemas
  • Use the include directives to help you find the ones you need. I noticed we were missing sudo.schema, csc.schema, and rfc2307bis.schema.
  • Open up the csc.schema for editing; we're not using it verbatim. Remove the attributes studentid and nonMemberTerm and the objectclass club. Also make sure you change the OID so we don't clash with the CSC. Because we didn't want to go through the process of requesting a PEN number, we chose arbitrarily to use 26338, which belongs to IWICS Inc.
  • We also need to can the auto-generated config files, so do that:

    # rm -rf /etc/openldap/slapd.d/*
  • Also nuke the auto-generated database:

    # rm /var/lib/ldap/__db.*
  • Configure the database:

    # cp /usr/share/slapd/DB_CONFIG /var/lib/ldap/
    # chown openldap:openldap /var/lib/ldap/DB_CONFIG 
  • Now we can generate the new configuration files:

    # slaptest -f /etc/ldap/slapd.conf -F /etc/ldap/slapd.d/
  • And ensure that the permissions are all set correctly, lest this break something:

    # chown -R openldap:openldap /etc/ldap/slapd.d
  • If at this point you get a nasty error, such as

    5657d4db hdb_db_open: database "dc=wics,dc=uwaterloo,dc=ca": db_open(/var/lib/ldap/id2entry.bdb) failed: No such file or directory (2).
    5657d4db backend_startup_one (type=hdb, suffix="dc=wics,dc=uwaterloo,dc=ca"): bi_db_open failed! (2)
    slap_startup failed (test would succeed using the -u switch)

    Just try restarting slapd, and see if that fixes the problem:

    # service slapd stop
    # service slapd start
  • Congratulations! Your LDAP service is now configured and running.

Getting TLS Up and Running

  • Now that we have our LDAP service, we'll want to be able to serve encrypted traffic. This is especially important for any remote access, since binding to LDAP (i.e. sending it a password for auth) occurs over plaintext, and we don't want to leak our admin password.

  • Our first step is to copy our SSL certificates into the correct places. Public ones go into /etc/ssl/certs/ and private ones go into /etc/ssl/private/.

  • Since the LDAP daemon needs to be able to read our private cert, we need to grant LDAP access to the private folder:

    # chgrp openldap /etc/ssl/private 
    # chmod g+x /etc/ssl/private
  • Next, uncomment the TLS-related settings in slapd.conf. These are TLSCertificateFile (the public cert), TLSCertificateKeyFile (the private key), TLSCACertificateFile (the intermediate CA cert), and TLSVerifyClient (set to "allow").

    # enable TLS connections
    TLSCertificateFile      /etc/ssl/certs/wics-wildcard.crt
    TLSCertificateKeyFile   /etc/ssl/private/wics-wildcard.key
    
    # enable TLS client authentication
    TLSCACertificateFile    /etc/ssl/certs/GlobalSign_Intermediate_Root_SHA256_G2.pem
    TLSVerifyClient         allow
  • Update all your LDAP settings:

    # rm -rf /etc/openldap/slapd.d/*
    # slaptest -f /etc/ldap/slapd.conf -F /etc/ldap/slapd.d/
    # chown -R openldap:openldap /etc/ldap/slapd.d
  • And last, ensure that LDAP will actually serve ldaps:// by modifying the init script variables in /etc/default/:

    # vim /etc/default/slapd
    ...
    SLAPD_SERVICES="ldap:/// ldapi:/// ldaps:///"
    ...
  • Now you can restart the LDAP server:

    # service slapd restart
  • And assuming this is successful, test to ensure LDAP is serving on port 636 for ldaps://:

    # netstat -ntaup
    Active Internet connections (servers and established)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
    tcp        0      0 0.0.0.0:389             0.0.0.0:*               LISTEN      22847/slapd     
    tcp        0      0 0.0.0.0:636             0.0.0.0:*               LISTEN      22847/slapd 

Populating the Database

Now you'll need to start adding objects to the database. While we'll want to mostly do this programmatically, there are a few entries we'll need to bootstrap.

Root Entries
  • Start by creating a file tree.ldif to create a few necessary "roots" in our LDAP tree, with the contents:

    dn: dc=wics,dc=uwaterloo,dc=ca
    objectClass: dcObject
    objectClass: organization
    o: Women in Computer Science
    dc: wics
    
    dn: ou=People,dc=wics,dc=uwaterloo,dc=ca
    objectClass: organizationalUnit
    ou: People
    
    dn: ou=Group,dc=wics,dc=uwaterloo,dc=ca
    objectClass: organizationalUnit
    ou: Group
  • Now attempt an LDAP add, using the password you set earlier:

    # ldapadd -cxWD cn=root,dc=wics,dc=uwaterloo,dc=ca -f tree.ldif
    Enter LDAP Password:
    adding new entry "dc=wics,dc=uwaterloo,dc=ca"
    
    adding new entry "ou=People,dc=wics,dc=uwaterloo,dc=ca"
    
    adding new entry "ou=Group,dc=wics,dc=uwaterloo,dc=ca"
  • Test that everything turned out okay, by performing a query of the entire database:

    # ldapsearch -x -h localhost
    # extended LDIF
    #
    # LDAPv3
    # base <dc=wics,dc=uwaterloo,dc=ca> (default) with scope subtree
    # filter: (objectclass=*)
    # requesting: ALL
    #
    
    # wics.uwaterloo.ca
    dn: dc=wics,dc=uwaterloo,dc=ca
    objectClass: dcObject
    objectClass: organization
    o: Women in Computer Science
    dc: wics
    
    # People, wics.uwaterloo.ca
    dn: ou=People,dc=wics,dc=uwaterloo,dc=ca
    objectClass: organizationalUnit
    ou: People
    
    # Group, wics.uwaterloo.ca
    dn: ou=Group,dc=wics,dc=uwaterloo,dc=ca
    objectClass: organizationalUnit
    ou: Group
    
    # search result
    search: 2
    result: 0 Success
    
    # numResponses: 4
    # numEntries: 3
Users and Groups
  • Next, add users to track the current GID and UID. This will save us from querying the entire database every time we make a new user or group. Create this file, nextxid.ldif:

    dn: uid=nextuid,ou=People,dc=wics,dc=uwaterloo,dc=ca
    cn: nextuid
    objectClass: account
    objectClass: posixAccount
    objectClass: top
    uidNumber: 20000
    gidNumber: 20000
    homeDirectory: /dev/null
    
    dn: cn=nextgid,ou=Group,dc=wics,dc=uwaterloo,dc=ca
    objectClass: group
    objectClass: posixGroup
    objectClass: top
    gidNumber: 10000

    You'll see here that our first GID is 10000 and our first UID is 20000.

  • Now add them, like you did with the roots of the tree:

    # ldapadd -cxWD cn=root,dc=wics,dc=uwaterloo,dc=ca -f nextxid.ldif
    Enter LDAP Password:
    adding new entry "uid=nextuid,ou=People,dc=wics,dc=uwaterloo,dc=ca"
    
    adding new entry "cn=nextgid,ou=Group,dc=wics,dc=uwaterloo,dc=ca"
Special sudo Entries
  • We also need to add a sudoers OU with a defaults object for default sudo settings. We also need entries for syscom, such that members of the syscom group can use sudo on all hosts, and for termcom, whose members can use sudo on only the office terminals. Call this one sudoers.ldif:

    dn: ou=SUDOers,dc=wics,dc=uwaterloo,dc=ca
    objectClass: organizationalUnit
    ou: SUDOers
    
    dn: cn=defaults,ou=SUDOers,dc=wics,dc=uwaterloo,dc=ca
    objectClass: top
    objectClass: sudoRole
    cn: defaults
    sudoOption: !lecture
    sudoOption: env_reset
    sudoOption: listpw=never
    sudoOption: mailto="wics-sys@lists.uwaterloo.ca"
    sudoOption: shell_noargs
    
    dn: cn=%syscom,ou=SUDOers,dc=wics,dc=uwaterloo,dc=ca
    objectClass: top
    objectClass: sudoRole
    cn: %syscom
    sudoUser: %syscom
    sudoHost: ALL
    sudoCommand: ALL
    sudoRunAsUser: ALL
    
    dn: cn=%termcom,ou=SUDOers,dc=wics,dc=uwaterloo,dc=ca
    objectClass: top
    objectClass: sudoRole
    cn: %termcom
    sudoUser: %termcom
    sudoHost: honk
    sudoHost: hiss
    sudoHost: gosling
    sudoCommand: ALL
    sudoRunAsUser: ALL
  • Now add them:

    # ldapadd -cxWD cn=root,dc=wics,dc=uwaterloo,dc=ca -f sudoers.ldif
    Enter LDAP Password:
    adding new entry "ou=SUDOers,dc=wics,dc=uwaterloo,dc=ca"
    
    adding new entry "cn=defaults,ou=SUDOers,dc=wics,dc=uwaterloo,dc=ca"
    
    adding new entry "cn=%syscom,ou=SUDOers,dc=wics,dc=uwaterloo,dc=ca"
    
    adding new entry "cn=%termcom,ou=SUDOers,dc=wics,dc=uwaterloo,dc=ca"
  • Last, add some special local groups via local-groups.ldif:

    # ldapadd -cxWD cn=root,dc=wics,dc=uwaterloo,dc=ca -f local-groups.ldif
    The local groups are special because they usually are present on all systems, but we want to be able to add users to them at the LDAP level. For instance, the audio group controls access to sound equipment, and the adm group controls log read access.
  • That's all the entries we have to add manually! Now we can use software for the rest. See weo for more details.


Querying LDAP

There are many tools available for issuing LDAP queries. Queries should be issued to ldap1.csclub.uwaterloo.ca. The search base you almost certainly want is dc=csclub,dc=uwaterloo,dc=ca. Read access is available without authentication; Kerberos is used to authenticate commands which require it.

Example:

ldapsearch -x -h ldap1.csclub.uwaterloo.ca -b dc=csclub,dc=uwaterloo,dc=ca uid=ctdalek

The -x option causes ldapsearch to switch to simple authentication rather than trying to authenticate via SASL (which will fail if you do not have a Kerberos ticket).

The University LDAP server (uwldap.uwaterloo.ca) can also be queried like this. Again, use "simple authentication" as read access is available (from on campus) without authentication. SASL authentication will fail without additional parameters.

Example:

ldapsearch -x -h uwldap.uwaterloo.ca -b dc=uwaterloo,dc=ca "cn=Prabhakar Ragde"

Replication

While ldap1.csclub.uwaterloo.ca (auth1) is the LDAP master, an up-to-date replica is available on ldap2.csclub.uwaterloo.ca (auth2).

In order to replicate changes from the master, the slave maintains an authenticated connection to the master which provides it with full read access to all changes.

Specifically, /etc/systemd/system/k5start-slapd.service maintains an active Kerberos ticket for ldap/auth2.csclub.uwaterloo.ca@CSCLUB.UWATERLOO.CA in /var/run/slapd/krb5cc. This is then used to authenticate the slave to the server, who maps this principal to cn=ldap-slave,dc=csclub,dc=uwaterloo,dc=ca, which in turn has full read privileges.

In the event of master failure, all hosts should fail LDAP reads seamlessly over to the slave.