Monitoring OpenBSD’s LDAP daemon

    

OpenBSD ships with an LDAP daemon since 4.8. I have an all-in-one server from which the LDAP service has to be shipped out. I’m going to replace that OpenLDAP daemon with the LDAP daemon from OpenBSD 5.1. I already wrote about how to enable LDAP on OpenBSD 4.8 .

Those will be updated notes for OpenBSD 5.1 and additional directions to allow monitoring the LDAP activity using SNMP and Xymon server.

Configure the LDAP daemon

Setting up the LDAP daemon is a painless operation. Get some extra schema definition (I’m using it for virtual users in a Mail/Web environment), update the configuration to configure your namespace, install a few certificates and free the daemon:

  # ftp -o /etc/ldap/courier.schema \
    http://courier.cvs.sourceforge.net/viewvc/courier/libs/authlib/authldap.schema
  
  # vi /etc/ldap/courier.schema                                                           
  (...)
  attributetype ( 1.3.6.1.4.1.10018.1.1.14 NAME 'mailhost'
          DESC 'Host to which incoming POP/IMAP connections should be proxied'
          EQUALITY caseIgnoreIA5Match
          SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
  (...)
  
  # chown _ldapd:_ldapd /etc/ldap/certs/*
  # chmod 0640 /etc/ldap/certs/*key
  # chmod 0644 /etc/ldap/certs/*crt 
  
  # chown root:wheel /etc/ssl/ca.tumfatig.net.pem
  # chmod 0444 /etc/ssl/ca.tumfatig.net.pem
  
  # vi /etc/ldapd.conf  
  (...)
  schema "/etc/ldap/courier.schema"
  (...)
  lan_if = "vic0"
  (...)
  listen on lo0 ldaps certificate localhost
  listen on $lan_if ldaps certificate ldap.tumfatig.net
  (...)
  namespace "dc=tumfatig,dc=net" {
          rootdn          "cn=user,dc=tumfatig,dc=net"
          rootpw          "{SSHA}xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
          index           cn
          index           givenName
          index           mail
          index           objectClass
          index           sn
  }
  
  # vi /etc/rc.conf.local
  (...)
  ldapd_flags=""
  
  # /etc/rc.d/ldapd start
  ldapd(ok)

Talking with the daemon

Any LDAP client will have to talk SSL. And any client will have to authenticate the server’s certificate:

  # cat > ~/.ldaprc
  TLS_CACERT /etc/ssl/ca.tumfatig.net.pem
  ^D
  
  # pkg_add openldap-client
  Password:
  openldap-client-2.4.26:cyrus-sasl-2.1.25p2: ok
  openldap-client-2.4.26: ok
  The following new rcscripts were installed: /etc/rc.d/saslauthd
  See rc.d(8) for details.
  
  # ldapsearch -x -H ldaps://ldap.tumfatig.net -D "cn=user,dc=tumfatig,dc=net" -W 
  Enter LDAP Password: 
  # extended LDIF
  #
  # LDAPv3
  # base <> (default) with scope subtree
  # filter: (objectclass=*)
  # requesting: ALL
  #
  
  # search result
  search: 2
  result: 32 No such object
  
  # numResponses: 1

You can fill-in the LDAP server with existing data as soon as you extracted them in LDIF format :

  # ldapadd -x -H ldaps://ldap.tumfatig.net \
    -D "cn=user,dc=tumfatig,dc=net" -W      \
    -f ldapd-20120813.ldif
  Enter LDAP Password: 
  adding new entry "dc=tumfatig,dc=net"
  adding new entry "cn=user,dc=tumfatig,dc=net"
  adding new entry "ou=alias,dc=tumfatig,dc=net"
  (...)

Keeping an eye on the daemon

The OpenBSD’s LDAP daemon comes with a command that dumps usage statistics:

  # ldapctl stats
  start time: Tue Aug 14 09:48:22 2012
  requests: 0
  search requests: 0
  bind requests: 0
  modify requests: 0
  timeouts: 0
  unindexed searches: 0
  active connections: 0
  active searches: 0
  
  suffix: dc=tumfatig,dc=net
  data timestamp: Mon Aug 13 19:16:06 2012
  data page size: 16384
  data depth: 1
  data revisions: 11
  data entries: 11
  data branch/leaf/overflow pages: 0/1/0
  data cache size: 1 of 1024 (0.1% full)
  data page reads: 1
  data cache hits: 0 (0.0%)
  indx timestamp: Mon Aug 13 19:16:06 2012
  indx page size: 16384
  indx depth: 1
  indx revisions: 11
  indx entries: 86
  indx branch/leaf/overflow pages: 0/1/0
  indx cache size: 1 of 512 (0.2% full)
  indx page reads: 1
  indx cache hits: 0 (0.0%)

What I do is dump the stats every minutes in some temporary file and make them available through the SNMP daemon:

# crontab -e
# generate LDAP statistics
*/1     *       *       *       *       /root/scripts/ldapstats 2>&1

# cat /root/scripts/ldapstats
#!/usr/bin/env ksh
#
# Display LDAP statistics
#

PATH=/bin:/usr/bin:/sbin:/usr/sbin

STATFILE="/tmp/ldapd.stats"
TEMPFILE="/tmp/ldapd.tmp"

case "$1" in
"show") # output the stats
        cat $STATFILE
        ;;
*)      # generate the stats
        ldapctl stats > $TEMPFILE
        [ -s $TEMPFILE ] && mv $TEMPFILE $STATFILE
        ;;
esac

exit 0

# vi /etc/snmp/snmpd.conf
(...)
extend  ldapstats "/root/scripts/ldapstats show"

# /etc/rc.d/netsnmpd restart                                                             
netsnmpd(ok)
netsnmpd(ok)

When the easy part is done, one has to grab those data from their monitoring solution. Mine is Xymon so I wrote a little script that grabs and print those stats as the service status and dumps some of the stats into a RRD datafile.

The monitoring server needs access to the CA to trust the LDAP daemon’s certificate:

# cat > /etc/openldap/ldap.conf
(...)
BASE    dc=tumfatig,dc=net
URI     ldaps://ldap.tumfatig.net
(...)
TLS_CACERT /etc/ssl/ca.tumfatig.net.pem

On the Xymon server, the script that collects data goes like this:

# cat xymon/server/ext/snmp_ldapdstats.sh
(...)

        # get the stats list
        STATLIST="`snmpwalk -v 2c -Oqv -c $SNMPCOMMUNITY $HOSTIP \
        'NET-SNMP-EXTEND-MIB::nsExtendOutLine."ldapstats"'`"

        # set the global metrics
        STATGLOBAL="`echo \"$STATLIST\" \
        | awk '
        /^requests: / { print "DS:rqst:COUNTER:600:0:U " $2 }
        /^search requests: / { print "DS:srch:COUNTER:600:0:U " $3 }
        /^bind requests: / { print "DS:bind:COUNTER:600:0:U " $3 }
        /^modify requests: / { print "DS:mdfy:COUNTER:600:0:U " $3 }
        /^timeouts: / { print "DS:time:COUNTER:600:0:U " $2 }
        /^unindexed searches: / { print "DS:nidx:COUNTER:600:0:U " $3 }
        /^active connections: / { print "DS:aconn:COUNTER:600:0:U " $3 }
        /^active searches: / { print "DS:asrch:COUNTER:600:0:U " $3 }
        '`"

        STATINFO="$STATINFO
LDAP daemon statistics
-----------------------------"
        TESTINFO=""
        TIMEINFO=`time -p ( ldapsearch -x -D "cn=none,dc=tumfatig,dc=net" -w none * ) 2>&1 1>/dev/null`
        TIMEINFO=`echo "${TIMEINFO}" | awk '{ SUM += $2} END { print SUM }'`
        STATINFO="$STATINFO
response time ${TIMEINFO} sec

$STATLIST
"
(...)

        $BB $BBDISP "status $HOSTNAME.$COLUMN $COLOR `date`

$STATINFO
"

Have it run for a while and grab the metrics. Set up a graph definition and look at the ldapd’activity:

I’m not sure why but there are times when total “Requests” is more than the sum of “Bind”, “Search” and “Modify” requests. First thought was that this may be due to statistics not being synced well in ldapctl. Another thought was that Bind/Search/Modify count direct requests while “Requests” also counts recursive request: like ask for a modify, there will be some searches first to get the objects.

So far, so good. The only twitch I have is with a Debian system that doesn’t want to talk SSL with the daemon. The error is “TLS: can't connect: The Diffie-Hellman prime sent by the server is not acceptable (not long enough)..” and I couldn’t solve it. What I did was adding a “listen on $lan_if secure” to ldapd.conf which I know is *bad*.

All in all, the ldapd(8) seems to be far enough for what I need.